Expand description
Tombstone semantics shared by every Store implementation
(ADR 0021). Stores read the current record inside their own OCC critical
section, ask a planner here what to do, and carry out the returned plan, so
every substrate reaches identical decisions by construction.
Enums§
- Delete
Plan - What a store must do for a
delete. - Purge
Plan - What a store must do for a
purge. - PutPlan
- What a store must do for a
put. Decided with the store’s current record in hand, inside its OCC critical section.
Constants§
- CONSUMER_
TOMBSTONE_ REJECTED - The reason a consumer
putof aRecordKind::Tombstonerecord is rejected (seePutPlan::Rejected). - DEFAULT_
ANCESTOR_ CAP - Ancestor list length used when a store is not configured otherwise. About 90 bytes per serialized entry: ~2.9 KB at the cap.
- MANIFEST_
TOMBSTONE_ RECREATE_ REJECTED - The reason a consumer
putthat would create over a manifest tombstone is rejected (seePutPlan::Rejected). A manifest tombstone retains the deleted body, which is the restore window ADR 0029 promises; overwriting it would unpin blobs that may be unregenerable (ADR 0030). - TOMBSTONE_
DOMAIN - Domain string hashed to form every tombstone’s revision hash. Not the empty body’s hash: that would let a tombstone collide with a live record edited to an empty body at the same counter, and sync would miss the divergence.
Functions§
- fold_
ancestors - The ancestor list to persist for a record whose revision is
stored, replacingcurrent(if any), given the ancestors the writer supplied. - now_ms
- Wall-clock milliseconds since the Unix epoch. A clock set before the epoch
yields
i64::MAX: collection treats a future stamp as too young, so a broken clock can only delay purging a tombstone, never make it early (spec §3.8). - plan_
delete - Decide a conditional
delete(spec §3.2). Deleting an absent key writes nothing: there is no revision to order a tombstone against a peer’s copy. Deleting a tombstone writes nothing: the chain does not advance. - plan_
purge - Decide a
purge: remove only the exact revision named, so a key recreated after its tombstone was listed survives collection. - plan_
put - Decide a consumer
put(spec §3.2). ARecordKind::Tombstonerecord is alwaysRejected: deletes go throughStore::delete_as, and replication writes tombstones throughput_raw. Otherwise, a tombstone counts as absent: a create (expected == None) recreates the key past the tombstone, and anySome(_)isNotFound. The one exception is a manifest tombstone (deleted_kindofGraphManifestorVectorManifest), whose retained body is a restore window: a create over it isRejectedwithMANIFEST_TOMBSTONE_RECREATE_REJECTED. Replication writes useplan_put_raw. - plan_
put_ raw - Decide a replication write (
Store::put_raw, spec §3.2). Never re-stamps: a tombstone is an ordinary record here. A create that finds anything stored (live or tombstone) is aConflictcarrying it, so sync re-reads instead of turning a copy into a recreation that would resurrect a deleted record. - reconciled_
ancestors - Ancestors for a record that reconciles two diverged records
aandb: a sync or pull merge result, or a tombstone winner. Both revisions and both ancestor lists are folded (spec §3.4), minusstored, sorted by(counter desc, hash desc)and truncated tocap. - reconciled_
record - The record reconciling two diverged live records
aandbinto mergedbody(spec §3.4, §3.5): revisionmax(counter) + 1overbody, parent = the higher-counter side, labels and links unioned, both chains folded. On a label-key collisionbwins, and on a counter tie the parent isa. Sync calls this with(a, b); pull calls it with(local, remote). - tombstone_
hash - The revision hash shared by every tombstone.
- tombstone_
of - The tombstone that deleting the live record
currentproduces.author, when given, is the deleter and replacesmeta.author; otherwise the tombstone keeps the last live writer’s metadata. - tombstone_
winner - Resolve two diverged tombstones for one key (spec §3.4, §3.5): the one with
the higher
(counter, hash)wins and carries ancestors reconciled from both. - validate_
ancestor_ cap - Reject an ancestor cap of zero: with no ancestors, sync could never fast-forward and every divergence would surface as a conflict.