aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/remake/snapshot.rs43
1 files changed, 27 insertions, 16 deletions
diff --git a/src/remake/snapshot.rs b/src/remake/snapshot.rs
index b4f1f35..fa1fa39 100644
--- a/src/remake/snapshot.rs
+++ b/src/remake/snapshot.rs
@@ -251,18 +251,20 @@ pub(crate) fn verify_document(doc: &Document, epoch: Epoch) -> Result<EpochMetad
read_epoch_metadata(&at_snapshot, epoch.generation)
}
-/// The epoch `doc` is on: genesis if it holds no epoch metadata; otherwise the newest
-/// generation it has metadata for, whose snapshot change is the document's only change
-/// without dependencies (verified). For a document loaded from a backup.
+/// The epoch `doc` is on: the newest generation the metadata at its only change without
+/// dependencies names (that change, a snapshot, writes its own and carries the earlier
+/// ones), verified; genesis if none names one, as the genesis change doesn't. Read at
+/// that change, not as the document stands: an entry a member wrote since (with no
+/// policy, its own change could) doesn't decide. For a document loaded from a backup.
pub(crate) fn epoch_of(doc: &Document) -> Result<Epoch, String> {
- let generation = store::keys_at(doc, &meta::path(&[EPOCHS]))
- .map_err(|error| error.to_string())?
- .unwrap_or_default()
- .iter()
- .filter_map(|key| key.parse::<u64>().ok())
- .max();
- let Some(generation) = generation.filter(|generation| *generation > 0) else {
- return Ok(Epoch::GENESIS);
+ let generations = |doc: &Document| -> Result<Option<u64>, String> {
+ Ok(store::keys_at(doc, &meta::path(&[EPOCHS]))
+ .map_err(|error| error.to_string())?
+ .unwrap_or_default()
+ .iter()
+ .filter_map(|key| key.parse::<u64>().ok())
+ .filter(|generation| *generation > 0)
+ .max())
};
let roots: Vec<ChangeHash> = doc
.get_changes(&[])
@@ -271,10 +273,17 @@ pub(crate) fn epoch_of(doc: &Document) -> Result<Epoch, String> {
.map(|change| change.hash())
.collect();
let [root] = roots.as_slice() else {
- return Err(format!(
- "generation {generation} needs exactly one change without dependencies (its snapshot), found {}",
- roots.len()
- ));
+ return match generations(doc)? {
+ None => Ok(Epoch::GENESIS),
+ Some(generation) => Err(format!(
+ "generation {generation} needs exactly one change without dependencies (its snapshot), found {}",
+ roots.len()
+ )),
+ };
+ };
+ let at_root = doc.fork_at(&[*root]).map_err(|error| error.to_string())?;
+ let Some(generation) = generations(&at_root)? else {
+ return Ok(Epoch::GENESIS);
};
let epoch = Epoch {
generation,
@@ -690,7 +699,9 @@ mod tests {
.fork()
.with_actor(ActorId::from(b"actor-b".as_slice()));
change(&mut later, |later| {
- store::write_path(later, &["k".into()], &json!(2)).unwrap()
+ store::write_path(later, &["k".into()], &json!(2)).unwrap();
+ // A generation planted since doesn't decide.
+ store::write_path(later, &meta::path(&[EPOCHS, "99"]), &json!({})).unwrap();
});
let backup = Document::load(&later.save()).unwrap();
assert_eq!(epoch_of(&backup), Ok(snap.epoch));