diff options
| author | tv <tv@krebsco.de> | 2026-10-26 05:24:32 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-26 05:24:32 +0100 |
| commit | 223834c9dabdab00fceda69b9ce989995de47efa (patch) | |
| tree | cdc8bc55750436bc81fec6c6b67b036504f313c8 /src/remake | |
| parent | c0ab6dbd13f26c7307b57a032da961bd6c49461c (diff) | |
remove unit suffixes from fields
Diffstat (limited to 'src/remake')
| -rw-r--r-- | src/remake/api.rs | 57 | ||||
| -rw-r--r-- | src/remake/coordinator.rs | 2 |
2 files changed, 31 insertions, 28 deletions
diff --git a/src/remake/api.rs b/src/remake/api.rs index 515468d..ab1b01b 100644 --- a/src/remake/api.rs +++ b/src/remake/api.rs @@ -5,7 +5,7 @@ //! node becomes its coordinator. `202` with the report, or with `?wait=true` the final //! report once decided. A dropped request does not abort anything. The remake //! commits as soon as a majority of its electorate voted for it (`vote`), and aborts -//! once that is out of reach or `settleSecs` passed without it. +//! once that is out of reach or `settle` passed without it. //! * `GET /admin/remakes` lists all remakes. //! * `GET /admin/remakes/{id}` reports one; `?wait=true` long-polls until decided //! (bounded by the proposal's own expiry). @@ -22,10 +22,12 @@ //! `{ "kind": "compact", "spec": null, "baseHeads": ["<hex>", …], //! "replayWindow": {"epochs": 1, "seconds": 604800}, //! "archiveRetention": {"epochs": 2, "seconds": 2592000}, -//! "settleSecs": 480, "switchDelaySecs": 60 }` +//! "settle": "8m", "switchDelay": "1m" }` +//! +//! `settle` and `switchDelay` are durations (`units`: seconds, or e.g. `500ms`, `8m`). //! //! `?force=` overrides checks: `true` all of them, or a comma-separated list of -//! * `switchDelaySecs`: accept one below a keepalive interval (for tests and debugging, +//! * `switchDelay`: accept one below a keepalive interval (for tests and debugging, //! not for real swarms); //! * `supersede`: abort expired remakes of this epoch and propose in their place. //! Without it, an expired remake still holding votes answers `409`. @@ -39,8 +41,8 @@ //! downloads it (`content`). Requests may be up to 64 MiB. //! //! An import can also be uploaded as is, with `Content-Type: application/octet-stream`; -//! then `rules` (JSON), `baseHeads` (comma-separated), `settleSecs` and -//! `switchDelaySecs` go in the query. Restoring a backup, keeping writes made since at +//! then `rules` (JSON), `baseHeads` (comma-separated), `settle` and `switchDelay` go +//! in the query. Restoring a backup, keeping writes made since at //! their paths: //! `curl --data-binary @backup.automerge -H 'Content-Type: application/octet-stream' --url-query 'rules=[{"from":"","to":""}]' …/admin/remakes` @@ -103,16 +105,18 @@ pub(crate) struct StartQuery { rules: Option<String>, /// Comma-separated hex. base_heads: Option<String>, - settle_secs: Option<u64>, - switch_delay_secs: Option<u64>, + #[serde(default, with = "crate::units::optional_duration")] + settle: Option<Duration>, + #[serde(default, with = "crate::units::optional_duration")] + switch_delay: Option<Duration>, } impl StartQuery { fn has_request_fields(&self) -> bool { self.rules.is_some() || self.base_heads.is_some() - || self.settle_secs.is_some() - || self.switch_delay_secs.is_some() + || self.settle.is_some() + || self.switch_delay.is_some() } /// An import request for a document uploaded as is. @@ -135,8 +139,8 @@ impl StartQuery { .map(str::to_owned) .collect() }), - settle_secs: self.settle_secs, - switch_delay_secs: self.switch_delay_secs, + settle: self.settle, + switch_delay: self.switch_delay, ..StartRequest::default() }) } @@ -164,14 +168,16 @@ struct StartRequest { replay_window: Option<Retention>, archive_retention: Option<Retention>, /// How long votes are collected; twice the dormancy threshold if absent. - settle_secs: Option<u64>, + #[serde(default, with = "crate::units::optional_duration")] + settle: Option<Duration>, /// How long nodes wait after seeing the commit before switching; one keepalive - /// interval if absent. Shorter only with `?force=switchDelaySecs`. - switch_delay_secs: Option<u64>, + /// interval if absent. Shorter only with `?force=switchDelay`. + #[serde(default, with = "crate::units::optional_duration")] + switch_delay: Option<Duration>, } /// What `?force=` may override on a proposal (`force`). -const FORCE: &[&str] = &["switchDelaySecs", "supersede", "coordinatorActive"]; +const FORCE: &[&str] = &["switchDelay", "supersede", "coordinatorActive"]; /// What `?force=` may override on an abort. const ABORT_FORCE: &[&str] = &["coordinatorActive"]; @@ -387,7 +393,7 @@ async fn start_kind<H: Host>( } else if query.has_request_fields() { return error_response( StatusCode::BAD_REQUEST, - "rules, baseHeads, settleSecs and switchDelaySecs go in the query only for an application/octet-stream import; put them in the JSON body", + "rules, baseHeads, settle and switchDelay go in the query only for an application/octet-stream import; put them in the JSON body", None, ); } else if body.is_empty() { @@ -461,20 +467,17 @@ async fn start_kind<H: Host>( // The voting period. No lower bound: the majority protects against competitors, // a short period only risks an abort for lack of votes. let dormant_after = host.dormant_after(); - let settle = request - .settle_secs - .map(Duration::from_secs) - .unwrap_or(dormant_after * 2); + let settle = request.settle.unwrap_or(dormant_after * 2); // The delay lets the commit reach every node through ordinary sync before any of // them stops syncing the old epoch. let keepalive = dormant_after / 4; - let switch_delay = request.switch_delay_secs.map(Duration::from_secs); + let switch_delay = request.switch_delay; match switch_delay { - Some(delay) if delay < keepalive && force.allows("switchDelaySecs") => { + Some(delay) if delay < keepalive && force.allows("switchDelay") => { warn!( - switch_delay_secs = delay.as_secs(), - keepalive_secs = keepalive.as_secs(), + switch_delay = %crate::units::format_duration(delay), + keepalive = %crate::units::format_duration(keepalive), "Forced switch delay shorter than a keepalive interval; slow nodes may have to rejoin" ); } @@ -482,8 +485,8 @@ async fn start_kind<H: Host>( return error_response( StatusCode::BAD_REQUEST, format!( - "switchDelaySecs must be at least {} (one keepalive interval), so the commit reaches every node before they switch; add ?force=switchDelaySecs to override", - keepalive.as_secs() + "switchDelay must be at least {} (one keepalive interval), so the commit reaches every node before they switch; add ?force=switchDelay to override", + crate::units::format_duration(keepalive) ), None, ); @@ -607,7 +610,7 @@ async fn start_kind<H: Host>( info!( remake = %id, - settle_secs = settle.as_secs(), + settle = %crate::units::format_duration(settle), "Remake proposed" ); diff --git a/src/remake/coordinator.rs b/src/remake/coordinator.rs index 20de712..6902515 100644 --- a/src/remake/coordinator.rs +++ b/src/remake/coordinator.rs @@ -6,7 +6,7 @@ //! * an operator requested an abort, //! * the local epoch changed, //! * a competing remake of the same epoch committed, -//! * the voting period (`settleSecs`) passed without a majority, or +//! * the voting period (`settle`) passed without a majority, or //! * a majority is out of reach (too many members voted for a competing remake). //! //! The decision is written in the same step that checks the records once more, so a |
