contract store · 10-store.md · 11-snapshot.md · 12-time.md · 13-replica.md · 14-drain.md · 15-endpoint.md · 16-collect.md · 17-merge.md · 18-pull.md · guide · card
Bucket collection
A bucket keeps every object a push writes until a collect deletes it.
contextful sync collect unlists, then deletes, the objects no reader needs: objects the bucket manifest no longer lists, a superseded snapshot’s parts and sidecars, the run directories an aged snapshot folds, and the generation manifests past a retained count. Every snapshot’s _manifest.json stays.
collect
Unlisting and deleting the bucket objects no reader needs, and the generation manifests past the retained count.
commandtesttestcontextful sync collectprints JSON naming, per classunlisted,superseded,folded_runsandgenerations, the keys it records as collected, the objects it deletes, their bytes andunknown_size, thenundeclared,shared_prefixandreferenced;--dry-runprints the same and writes nothing.Why
because an operator sizes a reclamation before running itunlistedtesttestCollect records as collected an object of the project the bucket manifest does not list when a tombstone or a generation pastretain-generationsnames its key, save a_group.json.Why
because a key some manifest once listed is one a push wrote, while an unnamed object may be an upload awaiting its commitsupersededtestCollect records as collected every object of a bucket chain snapshot’s directory once a child createdretain_runsago supersedes it and no unexpired hold names it, save_manifest.jsonand each part or segment a retained snapshot names.manifest-kepttestCollect deletes no snapshot_manifest.jsonand lists_collected.jsonbeside each snapshot it reclaims, the only writer of that marker, so every chain reaches its root and eachincludes_runsstill names its folded runs.folded-runstestCollect records as collected every object of a run directory,_manifest.jsonincluded, once the bucket chain snapshot naming the run inincludes_runssupersedes a snapshotsupersededreclaims, save a_group.jsongroup-windowkeeps.group-windowtestCollect keeps a folded run’s_group.jsonwhile a member table holding a copy of the run has not folded it out underfolded-runs, under that member’sretain_runs.Why
because a member run reads as committed only beside its group root’s marker, anas_ofread inside the window includedindex-walktesttestUnder the pointer’s valid bucket index, collect’s walk stops at a child within the cutoff, by clock and id, whose parent is collected; older folded runs come from the index, older collected snapshots from the listing.chain-onlytestCollect reclaims only snapshots the bucket pointer reaches throughparentlinks; another snapshot’sincludes_runscollects no run.Why
because a snapshot that lost its pointer commit folded nothing a bucket reader seesdeclared-windowtestCollect takes each table’sretain_runsfrom the collecting store’s declarations, a declared model defaulting as its builds’ retention does, and reclaims no snapshot or run of a table it declares none for, naming it underundeclared.Why
because the window is a table declaration, not bucket statetwo-phasetestCollect records a key as collected whether or not a retained generation lists it, and deletes the object at the first collect aftergeneration-listedstops holding it.Why
because a restore of a retained generation reads the object, while the record already keeps it out of every mergerecord-standstestWhile the bucket holds a recorded object, each collect stamps its record again once it passes half the agetombstone-ttlsets; past its object, a record lapses andcollected-directorykeeps the key out.Why
because a record lapsing before its object goes lets a merge list the key againretained-kepttesttestCollect deletes no recorded object a retained snapshot names, reporting its key underreferenced, and the key stays recorded.Why
because a hold reaching the bucket outsidehold-bucket-firstthen leaves a refusal rather than a lossserializedtestCollect holds the bucket’s collect lease from before it reads a hold until its last deletion, and refuses ashelddoes while another collect holds it.Why
because a hold or a record a concurrent collect commits otherwise reaches the deletes of a collect that never read itlease-renewedtestCollect renews its lease at a fresh clock reading before its deletes and atrenewal‘s interval through them, and deletes nothing more oncestale-fenceanswers a renewal.Why
because a collect outliving its lease otherwise deletes beside a successor that read newer holdsmetadata-kepttestCollect records no snapshot_manifest.jsonor_collected.json, pointer,schema.json, hold or run state, and no key a retained snapshot names, a tombstoned one included.Why
because those keys hold the chain and the coordination state every reader walksmarker-first-writertestA collect uploads_collected.jsononly where no object holds its key, and lists the bytes the bucket then holds.Why
because a losing concurrent collect overwriting a listed marker fails every pull’s digest checkgeneration-listedtestCollect deletes no object whose key a retained generation lists, and leaves it for a later collect.Why
becausesync pull --generationrestores a retained generation’s keys at their listed digestsretain-generationstest[sync] retain_generations, default 64 generations, sets how many newest generation manifests a collect keeps, the current one included; a value of 0 fails the configuration’s parse.generationstesttestCollect heals an absent copy of the read generation, then deletes everymanifests/gen-<N>.jsonolder than the newestretain-generations, so a restore of one meetsgeneration-absent.Why
because each generation manifest lists the whole store, and a push after every run writes one per rundrop-firsttesttestCollect commits a bucket manifest recording each key it unlists as collected, by the conditional replace ofmanifest-commit, before deleting any object, so no push lists a deleted object and a lazy read meetspart-collected.
unsettled: Does a collect reclaim another project’s unlisted objects when the generations it prunes are the last to name them? owner: store affects: store.collect
Scenarios
store.collect.drop-first: WHEN an owner restoring a tombstoned run reads the manifest, a collect then commits and deletes the run’s objects, and the owner’s push commits, THEN the push loses its condition, re-merges, and lists no deleted object.store.collect.generation-listed: WHEN a tombstoned run is unlisted while 64 retained generations list it, THEN the collect deletes none of its objects.store.collect.manifest-kept: WHEN a node holding a copy of runrbut no snapshot pulls after a collect reclaimed the snapshot foldingr, THEN its chain reaches that snapshot’s manifest andrreads once.store.collect.folded-runs: WHEN the owner of a collected run lists its restored copy again after the record’s age, THEN every reader folds the run through the kept manifest and reads it once.store.collect.group-window: WHEN a member table folds its copy of a grouped run one day before a collect, THEN the root run’s directory leaves save its_group.json.
A collect, from the manifest commit to the generation manifests it deletes.