diff --git a/src/lib_node_config/config_file.ml b/src/lib_node_config/config_file.ml index 32c2d2ec384f1b616a8cc5760d8438b676a86aef..d74d89e684439328bc9d616cc3f706848e106989 100644 --- a/src/lib_node_config/config_file.ml +++ b/src/lib_node_config/config_file.ml @@ -918,7 +918,7 @@ let update ?(disable_config_validation = false) ?data_dir ?min_connections ?(enable_testchain = default_p2p.enable_testchain) ?(cors_origins = []) ?(cors_headers = []) ?rpc_tls ?log_output ?log_coloring ?synchronisation_threshold ?history_mode ?network ?latency - ?enable_http_cache_headers ?context_pruning cfg = + ?enable_http_cache_headers ?context_pruning ?storage_maintenance_delay cfg = let open Lwt_result_syntax in let disable_config_validation = cfg.disable_config_validation || disable_config_validation @@ -1046,6 +1046,10 @@ let update ?(disable_config_validation = false) ?data_dir ?min_connections history_mode = Option.either history_mode cfg.shell.history_mode; context_pruning = Option.either context_pruning cfg.shell.context_pruning; + storage_maintenance_delay = + Option.either + storage_maintenance_delay + cfg.shell.storage_maintenance_delay; } in (* If --network is specified it overrides the "network" entry of the diff --git a/src/lib_node_config/config_file.mli b/src/lib_node_config/config_file.mli index 7e57aec842ca03a7a1a78d830927a591e28c38ee..f108669c3eb8266a8065bd92f3243b8722bb7fec 100644 --- a/src/lib_node_config/config_file.mli +++ b/src/lib_node_config/config_file.mli @@ -144,6 +144,7 @@ val update : ?latency:int -> ?enable_http_cache_headers:bool -> ?context_pruning:Storage_maintenance.context_pruning -> + ?storage_maintenance_delay:Storage_maintenance.delay -> t -> t tzresult Lwt.t diff --git a/src/lib_node_config/shared_arg.ml b/src/lib_node_config/shared_arg.ml index a740b326c48d124396049e03b643c4a4ee8be408..4a6f5130e136344b7298d52be44fb2ba688cbf1a 100644 --- a/src/lib_node_config/shared_arg.ml +++ b/src/lib_node_config/shared_arg.ml @@ -73,6 +73,7 @@ type t = { Shell_limits.operation_metadata_size_limit option; enable_http_cache_headers : bool option; context_pruning : Storage_maintenance.context_pruning option; + storage_maintenance_delay : Storage_maintenance.delay; } type error += @@ -194,7 +195,7 @@ let wrap data_dir config_file network connections max_download_speed log_coloring history_mode synchronisation_threshold latency disable_config_validation allow_all_rpc media_type max_active_rpc_connections metrics_addr operation_metadata_size_limit - enable_http_cache_headers context_pruning = + enable_http_cache_headers context_pruning storage_maintenance_delay = let actual_data_dir = Option.value ~default:Config_file.default_data_dir data_dir in @@ -248,6 +249,7 @@ let wrap data_dir config_file network connections max_download_speed operation_metadata_size_limit; enable_http_cache_headers; context_pruning; + storage_maintenance_delay; } let process_command run = @@ -765,7 +767,7 @@ module Term = struct in let parse str = match str with - | "disabled" -> `Ok Disabled + | "disabled" -> `Ok (Disabled : Storage_maintenance.context_pruning) | "enabled" -> `Ok Enabled | _ -> `Error @@ -776,6 +778,19 @@ module Term = struct & opt (some (parse, pp_context_pruning)) None & info ~docs ~doc ["context-pruning"]) + let storage_maintenance_delay = + let open Storage_maintenance in + let doc = "Configures the storage maintenance delays" in + let get_storage_maintenance_delay_arg str = + match str with + | "disabled" -> `Ok Disabled + | _ -> `Error "storage-maintenance-delay only supports \"disabled\" mode" + in + Arg.( + value + & opt (get_storage_maintenance_delay_arg, pp_delay) Disabled + & info ~docs ~doc ["storage-maintenance-delay"]) + (* Args. *) let args = @@ -790,7 +805,7 @@ module Term = struct $ log_output $ log_coloring $ history_mode $ synchronisation_threshold $ latency $ disable_config_validation $ allow_all_rpc $ media_type $ max_active_rpc_connections $ metrics_addr $ operation_metadata_size_limit - $ enable_http_cache_headers $ context_pruning + $ enable_http_cache_headers $ context_pruning $ storage_maintenance_delay end let read_config_file args = @@ -940,6 +955,7 @@ let patch_config ?(may_override_network = false) ?(emit = Event.emit) operation_metadata_size_limit; enable_http_cache_headers; context_pruning; + storage_maintenance_delay; } = args in @@ -1099,6 +1115,7 @@ let patch_config ?(may_override_network = false) ?(emit = Event.emit) ?latency ?enable_http_cache_headers ?context_pruning + ~storage_maintenance_delay cfg let read_and_patch_config_file ?may_override_network ?emit diff --git a/src/lib_node_config/shared_arg.mli b/src/lib_node_config/shared_arg.mli index 60a3a543124d87bbf7e1e844931e4adc781e27b3..d58c8a141fcb5c0855cbc26dd8d0d712eebb8987 100644 --- a/src/lib_node_config/shared_arg.mli +++ b/src/lib_node_config/shared_arg.mli @@ -91,6 +91,7 @@ type t = { (** Adds Cache-control header directives to RPC responses for queries that are relative to the head block. *) context_pruning : Storage_maintenance.context_pruning option; + storage_maintenance_delay : Storage_maintenance.delay; } val process_command : unit tzresult Lwt.t -> unit Cmdliner.Term.ret diff --git a/src/lib_shell_services/shell_limits.ml b/src/lib_shell_services/shell_limits.ml index e8092ba291034963350d87317b5434dc6e5c0732..f8e8589cf87001d3d4d9375a466478fca9835115 100644 --- a/src/lib_shell_services/shell_limits.ml +++ b/src/lib_shell_services/shell_limits.ml @@ -247,6 +247,8 @@ let chain_validator_limits_encoding = let default_storage_maintenance_context_pruning = Storage_maintenance.Enabled +let default_storage_maintenance_delay = Storage_maintenance.Disabled + type limits = { block_validator_limits : block_validator_limits; prevalidator_limits : prevalidator_limits; @@ -254,6 +256,7 @@ type limits = { chain_validator_limits : chain_validator_limits; history_mode : History_mode.t option; context_pruning : Storage_maintenance.context_pruning option; + storage_maintenance_delay : Storage_maintenance.delay option; } let default_limits = @@ -264,6 +267,7 @@ let default_limits = chain_validator_limits = default_chain_validator_limits; history_mode = None; context_pruning = Some Enabled; + storage_maintenance_delay = Some Disabled; } let limits_encoding = @@ -276,19 +280,22 @@ let limits_encoding = chain_validator_limits; history_mode; context_pruning; + storage_maintenance_delay; } -> ( peer_validator_limits, block_validator_limits, prevalidator_limits, chain_validator_limits, history_mode, - context_pruning )) + context_pruning, + storage_maintenance_delay )) (fun ( peer_validator_limits, block_validator_limits, prevalidator_limits, chain_validator_limits, history_mode, - context_pruning ) -> + context_pruning, + storage_maintenance_delay ) -> { peer_validator_limits; block_validator_limits; @@ -296,8 +303,9 @@ let limits_encoding = chain_validator_limits; history_mode; context_pruning; + storage_maintenance_delay; }) - (obj6 + (obj7 (dft "peer_validator" peer_validator_limits_encoding @@ -315,4 +323,5 @@ let limits_encoding = chain_validator_limits_encoding default_chain_validator_limits) (opt "history_mode" History_mode.encoding) - (opt "context_pruning" Storage_maintenance.context_pruning_encoding)) + (opt "context_pruning" Storage_maintenance.context_pruning_encoding) + (opt "storage_maintenance_delay" Storage_maintenance.delay_encoding)) diff --git a/src/lib_shell_services/shell_limits.mli b/src/lib_shell_services/shell_limits.mli index 79a8ee85501f3388ef6c5d48587c948144756850..86813499bc559c5befc86ec260fcc207b6918670 100644 --- a/src/lib_shell_services/shell_limits.mli +++ b/src/lib_shell_services/shell_limits.mli @@ -96,6 +96,8 @@ val chain_validator_limits_encoding : chain_validator_limits Data_encoding.t val default_storage_maintenance_context_pruning : Storage_maintenance.context_pruning +val default_storage_maintenance_delay : Storage_maintenance.delay + type limits = { block_validator_limits : block_validator_limits; prevalidator_limits : prevalidator_limits; @@ -103,6 +105,7 @@ type limits = { chain_validator_limits : chain_validator_limits; history_mode : History_mode.t option; context_pruning : Storage_maintenance.context_pruning option; + storage_maintenance_delay : Storage_maintenance.delay option; } val default_limits : limits diff --git a/src/lib_shell_services/storage_maintenance.ml b/src/lib_shell_services/storage_maintenance.ml index ccd56d0dac3a3d3b4e8b955748ca211981730610..c7c0d1b683c34d79334f2f5367bd51f311795eb0 100644 --- a/src/lib_shell_services/storage_maintenance.ml +++ b/src/lib_shell_services/storage_maintenance.ml @@ -38,3 +38,27 @@ let context_pruning_encoding = let pp_context_pruning fmt = function | Disabled -> Format.fprintf fmt "disabled" | Enabled -> Format.fprintf fmt "enabled" + +type delay = Disabled + +let delay_encoding = + let open Data_encoding in + def + "storage_maintenance_delay" + ~title:"storage maintenance delay" + ~description:"Delay prior to the storage maintenance trigger" + (union + ~tag_size:`Uint8 + [ + case + ~title:"disabled" + ~description: + "When disabled, the storage maintenance is triggered without any \ + delay, as soon as a new cycle starts." + (Tag 0) + (constant "disabled") + (function Disabled -> Some ()) + (fun () -> Disabled); + ]) + +let pp_delay fmt = function Disabled -> Format.fprintf fmt "disabled" diff --git a/src/lib_shell_services/storage_maintenance.mli b/src/lib_shell_services/storage_maintenance.mli index aed282bf3d6479c087ca2993d1fc4d4fbef56a56..1a96fb55dfaef888e7f4a47b045d4e6c1c1ae254 100644 --- a/src/lib_shell_services/storage_maintenance.mli +++ b/src/lib_shell_services/storage_maintenance.mli @@ -19,3 +19,14 @@ type context_pruning = Enabled | Disabled val context_pruning_encoding : context_pruning Data_encoding.t val pp_context_pruning : Format.formatter -> context_pruning -> unit + +(** The type [delay] specifies whether or not a storage maintenance + should be delayed or not. + Setting it to [Disabled] will trigger the storage maintenance as + soon as possible, that is, at the very beginning of a new cycle + dawn. *) +type delay = Disabled + +val delay_encoding : delay Data_encoding.t + +val pp_delay : Format.formatter -> delay -> unit diff --git a/tezt/lib_tezos/node.ml b/tezt/lib_tezos/node.ml index a6c20d5aa4e4322afddcbf4f7afd6f7eec4c719b..66e5a459f72061fa88813c03c69eb386e3a51cc4 100644 --- a/tezt/lib_tezos/node.ml +++ b/tezt/lib_tezos/node.ml @@ -43,6 +43,7 @@ type argument = | Max_active_rpc_connections of int | Enable_http_cache_headers | Context_pruning of string + | Storage_maintenance_delay of string let make_argument = function | Network x -> ["--network"; x] @@ -78,6 +79,7 @@ let make_argument = function ["--max-active-rpc-connections"; string_of_int n] | Enable_http_cache_headers -> ["--enable-http-cache-headers"] | Context_pruning x -> ["--context-pruning"; x] + | Storage_maintenance_delay x -> ["--storage-maintenance-delay"; x] let make_arguments arguments = List.flatten (List.map make_argument arguments) @@ -102,7 +104,8 @@ let is_redundant = function | Version, Version | Max_active_rpc_connections _, Max_active_rpc_connections _ | Enable_http_cache_headers, Enable_http_cache_headers - | Context_pruning _, Context_pruning _ -> + | Context_pruning _, Context_pruning _ + | Storage_maintenance_delay _, Storage_maintenance_delay _ -> true | Metrics_addr addr1, Metrics_addr addr2 -> addr1 = addr2 | Peer peer1, Peer peer2 -> peer1 = peer2 @@ -129,7 +132,8 @@ let is_redundant = function | Version, _ | Max_active_rpc_connections _, _ | Enable_http_cache_headers, _ - | Context_pruning _, _ -> + | Context_pruning _, _ + | Storage_maintenance_delay _, _ -> false (* Some arguments should not be written in the config file by [Node.init] diff --git a/tezt/lib_tezos/node.mli b/tezt/lib_tezos/node.mli index 451ea8d7ba5b68b6adffdf1bc33121da0cb04da1..888f3e1c2c83f9ad173d67d509cdcdf7f0072347 100644 --- a/tezt/lib_tezos/node.mli +++ b/tezt/lib_tezos/node.mli @@ -101,6 +101,7 @@ type argument = | Max_active_rpc_connections of int (** [--max-active-rpc-connections] *) | Enable_http_cache_headers (** [--enable-http-cache-headers] *) | Context_pruning of string (** [--context-pruning] *) + | Storage_maintenance_delay of string (** [--storage-maintenance-delay]*) (** A TLS configuration for the node: paths to a [.crt] and a [.key] file. diff --git a/tezt/tests/storage_maintenance.ml b/tezt/tests/storage_maintenance.ml index 467c8c85f1d9ec6c1c8da425da624a8f7bbd37f2..ae9fab0694d0f6810d934952158904d5dc4b105d 100644 --- a/tezt/tests/storage_maintenance.ml +++ b/tezt/tests/storage_maintenance.ml @@ -69,4 +69,59 @@ let test_context_pruning_call = let* () = wait_context_gc and* () = wait_context_split in unit -let register ~protocols = test_context_pruning_call protocols +let wait_for_complete_storage_maintenance node target = + let filter json = + let level = JSON.(json |> as_int) in + if level = target then Some () else None + in + let wait_for_ending_merge () = + Node.wait_for node "end_merging_stores.v0" @@ fun _json -> Some () + in + let* () = Node.wait_for node "start_merging_stores.v0" filter in + wait_for_ending_merge () + +let test_disabled_maintenance_delay = + Protocol.register_test + ~__FILE__ + ~title:(Format.asprintf "storage maintenance disabled delay") + ~tags:[team; "storage"; "maintenance"; "delay"; "disabled"] + @@ fun protocol -> + let* node = + Node.init + Node.[Synchronisation_threshold 0; Storage_maintenance_delay "disabled"] + in + let* client = Client.init ~endpoint:(Node node) () in + let* () = Client.activate_protocol_and_wait ~protocol ~node client in + let blocks_per_cycle = 8 in + let blocks_to_bake = 2 * blocks_per_cycle in + let wait_merge = + wait_for_complete_storage_maintenance node (blocks_per_cycle + 1) + in + let* () = bake_blocks node client ~blocks_to_bake in + Log.info "Waiting for the merge" ; + let* () = wait_merge in + unit + +(* This is a temporary test to ensure that only the disabled mode is + implemented. *) +let test_only_disabled_is_implemented = + Protocol.register_test + ~__FILE__ + ~title:(Format.asprintf "storage maintenance allows disabled only") + ~tags:[team; "storage"; "maintenance"; "delay"; "enable"] + ~uses_client:false + ~uses_admin_client:false + @@ fun _protocol -> + let node = Node.create Node.[Synchronisation_threshold 0] in + let* () = + Node.spawn_config_update node [Storage_maintenance_delay "enabled"] + |> Process.check_error + ~msg:(rex "only supports \"disabled\" mode") + ~exit_code:124 + in + unit + +let register ~protocols = + test_context_pruning_call protocols ; + test_disabled_maintenance_delay protocols ; + test_only_disabled_is_implemented protocols