summaryrefslogtreecommitdiffstats
path: root/src/remake/api.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/remake/api.rs')
-rw-r--r--src/remake/api.rs46
1 files changed, 29 insertions, 17 deletions
diff --git a/src/remake/api.rs b/src/remake/api.rs
index 826c81e..3530423 100644
--- a/src/remake/api.rs
+++ b/src/remake/api.rs
@@ -17,7 +17,8 @@
//! can't commit it any more anyway (`coordinator`). `DELETE /admin/remakes` does the
//! same for the undecided remake of the local epoch, without having to know its ID.
//!
-//! Request body for POST (all optional):
+//! Request body for POST (all optional; `baseHeads` not for `compact`, whose base is
+//! fixed when it commits):
//! `{ "kind": "compact", "spec": null, "baseHeads": ["<hex>", …],
//! "replayWindow": {"epochs": 1, "seconds": 604800},
//! "archiveRetention": {"epochs": 2, "seconds": 2592000},
@@ -395,6 +396,15 @@ async fn start_kind<H: Host>(
}
};
+ if kind.base_at_commit() && request.base_heads.is_some() {
+ return error_response(
+ StatusCode::BAD_REQUEST,
+ format!(
+ "a {kind_name} remake fixes its base when it commits; baseHeads is not accepted"
+ ),
+ None,
+ );
+ }
let base = match &request.base_heads {
None => None,
Some(heads) => {
@@ -454,7 +464,8 @@ async fn start_kind<H: Host>(
let mut proposal = Proposal {
coordinator: host.node_id(),
from_epoch: host.current_epoch().into(),
- base_heads: Vec::new(),
+ // Filled in when the proposal is written, unless the kind fixes it at the commit.
+ base_heads: None,
policy: Policy {
replay_window: request
.replay_window
@@ -598,6 +609,7 @@ async fn propose<H: Host>(
let electorate_host = host.clone();
let me = host.node_id();
let started = host.remake().started_at() + grace;
+ let base_at_commit = kind::by_name(&proposal.kind).is_some_and(|kind| kind.base_at_commit());
let record = host
.commit_doc(move |doc| -> Result<Record, StartError> {
let mut all = records::load_all(doc);
@@ -656,22 +668,22 @@ async fn propose<H: Host>(
}
// The base is the requested heads, or everything before the proposal (the
- // proposal itself is never in it).
- let base = match base {
- Some(base) => {
- if let Some(unknown) = base
- .iter()
- .find(|head| doc.get_change_by_hash(head).is_none())
- {
- return Err(StartError::UnknownBase(unknown.to_string()));
+ // proposal itself is never in it); or, for a compaction, left to the commit.
+ if !base_at_commit {
+ let base = match base {
+ Some(base) => {
+ if let Some(unknown) = base
+ .iter()
+ .find(|head| doc.get_change_by_hash(head).is_none())
+ {
+ return Err(StartError::UnknownBase(unknown.to_string()));
+ }
+ base
}
- base
- }
- None => doc.get_heads(),
- };
- let mut heads: Vec<String> = base.iter().map(|h| h.to_string()).collect();
- heads.sort();
- proposal.base_heads = heads;
+ None => doc.get_heads(),
+ };
+ proposal.base_heads = Some(records::encode_heads(&base));
+ }
// We vote for our own remake, so we are always in the electorate.
let mut electorate = electorate_host.electorate(doc, now);