package octez-shell-libs
Octez shell libraries
Install
Dune Dependency
Authors
Maintainers
Sources
tezos-octez-v20.1.tag.bz2
sha256=ddfb5076eeb0b32ac21c1eed44e8fc86a6743ef18ab23fff02d36e365bb73d61
sha512=d22a827df5146e0aa274df48bc2150b098177ff7e5eab52c6109e867eb0a1f0ec63e6bfbb0e3645a6c2112de3877c91a17df32ccbff301891ce4ba630c997a65
doc/src/octez-shell-libs.proxy/proxy_getter.ml.html
Source file proxy_getter.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2020-2021 Nomadic Labs, <contact@nomadic-labs.com> *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) (* to deal in the Software without restriction, including without limitation *) (* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) (* and/or sell copies of the Software, and to permit persons to whom the *) (* Software is furnished to do so, subject to the following conditions: *) (* *) (* The above copyright notice and this permission notice shall be included *) (* in all copies or substantial portions of the Software. *) (* *) (* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) (* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) (* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) (* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) (* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) (* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) module Local = Tezos_context_memory.Context module Proof = Tezos_context_sigs.Context.Proof_types (** The kind of RPC request: is it a GET (i.e. is it loading data?) or is it only a MEMbership request (i.e. is the key associated to data?). *) type kind = Get | Mem let kind_encoding : kind Data_encoding.t = let open Data_encoding in conv (function Get -> true | Mem -> false) (function true -> Get | false -> Mem) bool let pp_kind fmt kind = Format.fprintf fmt "%s" (match kind with Get -> "get" | Mem -> "mem") module Events = struct include Internal_event.Simple let section = ["proxy_getter"] let pp_key = let pp_sep fmt () = Format.fprintf fmt "/" in Format.pp_print_list ~pp_sep Format.pp_print_string let cache_hit = declare_2 ~section ~name:"cache_hit" ~msg:"Cache hit ({kind}): ({key})" ~level:Debug ~pp1:pp_kind ~pp2:pp_key ("kind", kind_encoding) ("key", Data_encoding.(list string)) let cache_miss = declare_2 ~section ~name:"cache_miss" ~msg:"Cache miss ({kind}): ({key})" ~level:Debug ~pp1:pp_kind ~pp2:pp_key ("kind", kind_encoding) ("key", Data_encoding.(list string)) let split_key_triggers = declare_2 ~section ~level:Debug ~name:"split_key_triggers" ~msg:"split_key heuristic triggers, getting {parent} instead of {leaf}" ~pp1:pp_key ~pp2:pp_key ("parent", Data_encoding.(list string)) ("leaf", Data_encoding.(list string)) end let rec raw_context_size = function | Proof.Key _ | Cut -> 0 | Dir map -> String.Map.fold (fun _key v acc -> acc + 1 + raw_context_size v) map 0 let rec raw_context_to_tree (raw : Proof.raw_context) : Local.tree option Lwt.t = match raw with | Key (bytes : Bytes.t) -> Lwt.return_some (Local.Tree.of_raw (`Value bytes)) | Cut -> Lwt.return_none | Dir map -> let open Lwt_syntax in let add_to_tree tree (string, raw_context) = let* u = raw_context_to_tree raw_context in match u with | None -> Lwt.return tree | Some u -> Local.Tree.add_tree tree [string] u in let* dir = String.Map.bindings map |> List.fold_left_s add_to_tree (Tezos_context_memory.Context.make_empty_tree ()) in if Local.Tree.is_empty dir then return_none else return_some dir module type M = sig val proxy_dir_mem : Proxy.proxy_getter_input -> Local.key -> bool tzresult Lwt.t val proxy_get : Proxy.proxy_getter_input -> Local.key -> Local.tree option tzresult Lwt.t val proxy_mem : Proxy.proxy_getter_input -> Local.key -> bool tzresult Lwt.t end type proxy_m = (module M) type proxy_builder = | Of_rpc of (Proxy_proto.proto_rpc -> proxy_m Lwt.t) | Of_data_dir of (Context_hash.t -> Tezos_protocol_environment.Proxy_delegate.t tzresult Lwt.t) type rpc_context_args = { printer : Tezos_client_base.Client_context.printer option; proxy_builder : proxy_builder; rpc_context : Tezos_rpc.Context.generic; mode : Proxy.mode; chain : Tezos_shell_services.Block_services.chain; block : Tezos_shell_services.Block_services.block; } module StringMap = String.Map let make_delegate (ctx : rpc_context_args) (proto_rpc : (module Proxy_proto.PROTO_RPC)) (hash : Context_hash.t) : Tezos_protocol_environment.Proxy_delegate.t tzresult Lwt.t = match ctx.proxy_builder with | Of_rpc f -> let open Lwt_result_syntax in let*! (module Initial_context) = f proto_rpc in let pgi : Proxy.proxy_getter_input = { rpc_context = (ctx.rpc_context :> Tezos_rpc.Context.simple); mode = ctx.mode; chain = ctx.chain; block = ctx.block; } in return (module struct let proxy_dir_mem = Initial_context.proxy_dir_mem pgi let proxy_get = Initial_context.proxy_get pgi let proxy_mem = Initial_context.proxy_mem pgi end : Tezos_protocol_environment.Proxy_delegate.T) | Of_data_dir f -> f hash module Tree : Proxy.TREE with type t = Local.tree with type key = Local.key = struct type t = Local.tree type key = Local.key let empty = Local.Tree.empty (Tezos_context_memory.Context.make_empty_context ()) let get = Local.Tree.find_tree let add_leaf tree key raw_context : t Proxy.update Lwt.t = let open Lwt_syntax in let* tree_opt = raw_context_to_tree raw_context in let* updated_tree = match tree_opt with | None -> Lwt.return tree | Some sub_tree -> Local.Tree.add_tree tree key sub_tree in Lwt.return (Proxy.Value updated_tree) end module type REQUESTS_TREE = sig type tree = Partial of tree StringMap.t | All val empty : tree val add : tree -> string list -> tree val find_opt : tree -> string list -> tree option end module RequestsTree : REQUESTS_TREE = struct type tree = Partial of tree StringMap.t | All let empty = Partial StringMap.empty let rec add (t : tree) (k : string list) : tree = match (t, k) with | _, [] | All, _ -> All | Partial map, k_hd :: k_tail -> ( let sub_t_opt = StringMap.find_opt k_hd map in match sub_t_opt with | None -> Partial (StringMap.add k_hd (add empty k_tail) map) | Some (Partial _ as sub_t) -> Partial (StringMap.add k_hd (add sub_t k_tail) map) | Some All -> t) let rec find_opt (t : tree) (k : string list) : tree option = match (t, k) with | All, _ -> Some All | Partial _, [] -> None | Partial map, k_hd :: k_tail -> ( let sub_t_opt = StringMap.find_opt k_hd map in match sub_t_opt with | None -> None | Some All -> Some All | Some (Partial _ as sub_t) -> ( match k_tail with [] -> Some sub_t | _ -> find_opt sub_t k_tail)) end module Core (T : Proxy.TREE with type key = Local.key and type t = Local.tree) (X : Proxy_proto.PROTO_RPC) : Proxy.CORE = struct let store = ref None (** Only load the store the first time it is needed *) let lazy_load_store () = match !store with | None -> let e = T.empty in store := Some e ; Lwt.return e | Some e -> Lwt.return e let get key = let open Lwt_syntax in let* store = lazy_load_store () in T.get store key let do_rpc : Proxy.proxy_getter_input -> Local.key -> unit tzresult Lwt.t = fun pgi key -> let open Lwt_result_syntax in let* tree = X.do_rpc pgi key in let*! current_store = lazy_load_store () in (* Update cache with data obtained *) let*! updated = T.add_leaf current_store key tree in (match updated with Mutation -> () | Value cache' -> store := Some cache') ; return_unit end module Make (C : Proxy.CORE) (X : Proxy_proto.PROTO_RPC) : M = struct let requests = ref RequestsTree.empty let is_all k = match RequestsTree.find_opt !requests k with Some All -> true | _ -> false (** Handles the application of [X.split_key] to optimize queries. *) let do_rpc (pgi : Proxy.proxy_getter_input) (kind : kind) (requested_key : Local.key) : unit tzresult Lwt.t = let open Lwt_result_syntax in let key_to_get, split = match kind with | Mem -> (* If the value is not going to be used, don't request a parent *) (requested_key, false) | Get -> ( match X.split_key pgi.mode requested_key with | None -> (* There's no splitting for this key *) (requested_key, false) | Some (prefix, _) -> (* Splitting triggers: a parent key will be requested *) (prefix, true)) in let remember_request () = (* Remember request was done: map [key] to [All] in [!requests] (see [Proxy_getter.REQUESTS_TREE] mli for further details) *) requests := RequestsTree.add !requests key_to_get ; return_unit in (* [is_all] has been checked (by the caller: [generic_call]) for the key received as parameter. Hence it only makes sense to check it if a parent key is being retrieved ('split' = true and hence 'key' here differs from the key received as parameter) *) if split && is_all key_to_get then return_unit else let*! () = if split then Events.(emit split_key_triggers (key_to_get, requested_key)) else Lwt.return_unit in let*! r = C.do_rpc pgi key_to_get in match r with | Ok _ -> remember_request () | Error _ when X.failure_is_permanent requested_key -> remember_request () | Error err -> (* Don't remember the request, maybe it will succeed in the future *) Lwt.return_error err (* [generic_call] and [do_rpc] above go hand in hand. [do_rpc] takes care of performing the RPC call and updating [cache]. [generic_call] calls [do_rpc] to make sure the cache is filled, and then queries the cache to return the desired value. Having them separate allows to avoid mixing the logic of [X.split_key] (confined to [do_rpc]) and the logic of getting the key's value. *) let generic_call : kind -> Proxy.proxy_getter_input -> Local.key -> Local.tree option tzresult Lwt.t = fun (kind : kind) (pgi : Proxy.proxy_getter_input) (key : Local.key) -> let open Lwt_result_syntax in let* () = if is_all key then (* This exact request was done already. So data was obtained already. Note that this does not imply that this function will return [Some] (maybe the node doesn't map this key). *) Lwt_result.ok @@ Events.(emit cache_hit (kind, key)) else (* This exact request was NOT done already (either a longer request was done or no related request was done at all). An RPC MUST be done. *) let*! () = Events.(emit cache_miss (kind, key)) in do_rpc pgi kind key in Lwt_result.ok @@ C.get key let proxy_get pgi key = generic_call Get pgi key let proxy_dir_mem pgi key = let open Lwt_result_syntax in let* tree_opt = generic_call Mem pgi key in match tree_opt with | None -> return_false | Some tree -> ( match Local.Tree.kind tree with | `Tree -> return_true | `Value -> return_false) let proxy_mem pgi key = let open Lwt_result_syntax in let* tree_opt = generic_call Mem pgi key in match tree_opt with | None -> return_false | Some tree -> ( match Local.Tree.kind tree with | `Tree -> return_false | `Value -> return_true) end module MakeProxy (X : Proxy_proto.PROTO_RPC) : M = Make (Core (Tree) (X)) (X) module Internal = struct module Tree = Tree let raw_context_to_tree = raw_context_to_tree end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>