aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-09 20:29:32 +0000
committertv <tv@krebsco.de>2026-11-09 22:20:00 +0100
commit152890f321075beede075314d37ff6451604c359 (patch)
tree352bbdeabea55735d9bafe78cba24b58a1182c2f /src/main.rs
parent5f7e29cec4333715346b4bf3195633db93449d9d (diff)
document file: a clean stop marked, and `--keep-actor` writes on as the same actor
A node writes as a fresh Automerge actor at each start, so no change number of an actor comes twice: one sent before a crash but not yet appended to the document file would otherwise be made again, differently. An epoch thus gathers a writer per start, and every transfer of its history carries a signature per writer. The document file now says when it holds everything the node wrote: * at a clean stop, after the last append, an empty `Closed` record, only where the file is up to the document's heads (ready, not rejoining); * as a node starts on the file, before anything is written, an empty `Opened` record, so a crash from then on leaves a file without the mark; * the header names the actor the node writes with (`current`). With `--keep-actor` (off by default; needs `--document-file`), a node starting on a file that ends with `Closed` writes on as that actor. A crash, a drop, a switch or a rejoin still starts a fresh one, so an epoch's writers come to one per node plus one per such event. lifecycle.md says so.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs47
1 files changed, 36 insertions, 11 deletions
diff --git a/src/main.rs b/src/main.rs
index 880d793..7c819e5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -165,18 +165,37 @@ async fn main() -> Result<()> {
&files,
&force,
)?;
- let (initial_doc, starting_epoch, starting_swarm, earlier_actors, initial_signatures) =
- match starting {
- Some(starting) => (
- starting.doc,
- Some(starting.epoch),
- Some((starting.swarm_id, starting.origin)),
- starting.earlier_actors,
- starting.signatures,
- ),
- None => (Document::new(), None, None, Vec::new(), Vec::new()),
- };
+ let (
+ initial_doc,
+ starting_epoch,
+ starting_swarm,
+ earlier_actors,
+ initial_signatures,
+ resumable,
+ ) = match starting {
+ Some(starting) => (
+ starting.doc,
+ Some(starting.epoch),
+ Some((starting.swarm_id, starting.origin)),
+ starting.earlier_actors,
+ starting.signatures,
+ starting.resumable,
+ ),
+ None => (Document::new(), None, None, Vec::new(), Vec::new(), None),
+ };
let mut initial_doc = initial_doc;
+ // Writing on as the actor of before, where this node stopped cleanly: everything it
+ // wrote as that one is in the document, so no change of it comes twice.
+ match resumable.filter(|_| args.keep_actor) {
+ Some(actor) => {
+ info!(actor = %actor, "Writing on as the actor of before (--keep-actor)");
+ initial_doc.set_actor(actor);
+ }
+ None if args.keep_actor && starting_epoch.is_some() => {
+ info!("Writing as a fresh actor: this node didn't stop cleanly (--keep-actor)");
+ }
+ None => {}
+ }
if let Some(spec) = &args.remake {
remake::remake_genesis(spec, &files, &mut initial_doc)
.with_context(|| format!("Making the genesis document (--remake {spec})"))?;
@@ -228,6 +247,11 @@ async fn main() -> Result<()> {
args.document_rewrite,
))
});
+ // A clean stop's mark undone before anything is written: a crash from here on
+ // leaves a file that doesn't say so.
+ if let Some(file) = &document_file {
+ file.open();
+ }
let node = node::Node::new(node::NodeConfig {
transport,
identity: Some(transport::identity::IdentityConfig {
@@ -367,6 +391,7 @@ async fn main() -> Result<()> {
swarm::peer::farewell(&state).await;
swarm::state_file::update(&state, true).await;
swarm::document_file::flush(&state).await;
+ swarm::document_file::close(&state).await;
Ok(())
}