Fix the GC/sync lock key; record why stratum's GC differs - #40
Open
whilo wants to merge 3 commits into
Open
Conversation
`with-storage-lock` is what keeps stratum's standalone `gc!` from sweeping chunks a concurrent `sync!` is about to reference. It allocated its monitor in a ConcurrentHashMap keyed by the store REFERENCE, on the stated reasoning that "File-store / S3-store records with content-based equality: two instances configured against the same backing storage share a lock — which is what we want (they protect the same physical data)." They do not. Two `connect-fs-store` calls on one path are neither `identical?` nor `=`, and hash differently: identical? false = false same hash? false So a process that connected twice to one store got two independent monitors and no exclusion at all — measured at 0.16ms of contention where the lock should have blocked for 300ms. The companion claim, that "under-locking is impossible: distinct keys always get distinct locks", had it exactly backwards. Two distinct keys for ONE physical store IS under-locking. The safe direction is the opposite, and it is the same rule `konserve.gc-guard` follows for the safe point: the key may be COARSER than the physical store — two stores collapsing onto one monitor merely over-locks — but never FINER. konserve's `:id` is coarser: a logical identity shared by replicas across machines, and within one JVM (all a monitor can reach) one id names one store. Stores built through a backend constructor carry no id and fall back to the object, which is the old behaviour; such callers should still avoid connecting twice. The regression test observes the monitor through the behaviour it exists for rather than reaching into private state: a lock held on one connection must exclude the other. It fails on the old key. Signed-off-by: Christian Weilbach <christian@weilbach.name>
…unify it Companion to the lock fix. Records that stratum's GC design follows from sharing datahike's store rather than owning its own, that both patterns already exist in the stack, and that the open question is store ownership rather than collection mechanism. Signed-off-by: Christian Weilbach <christian@weilbach.name>
Carries `konserve.protocols/store-id`, which the GC/sync lock now keys on (replikativ/konserve#159). Both pins bumped — the main dependency and the `:release` override. The `:local` alias stays for co-development but is no longer needed to build. 1430 tests / 5866 assertions against the published artifact. Signed-off-by: Christian Weilbach <christian@weilbach.name>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes: a real bug in the GC/sync coordination lock, and a design note
recording why stratum's garbage collection differs from the rest of the stack —
written while landing
konserve.gc-guardacross konserve, scriptum, proximumand stratum.
The lock did not lock
with-storage-lockis what keeps stratum's standalonegc!from sweepingchunks a concurrent
sync!is about to reference. It allocated its monitor ina
ConcurrentHashMapkeyed by the store REFERENCE, on the stated reasoningthat
They do not. Two
connect-fs-storecalls on one path are neitheridentical?nor
=, and hash differently:So a process that connected twice to one store got two independent monitors and
no exclusion at all — measured at 0.16 ms of contention where the lock should
have blocked for 300 ms.
The companion claim, that "under-locking is impossible: distinct keys always
get distinct locks", had it exactly backwards. Two distinct keys for ONE
physical store is under-locking. The safe direction is the opposite, and it
is the same rule the GC safe point follows: the key may be COARSER than the
physical store — two stores collapsing onto one monitor merely over-locks — but
never FINER.
The lock now keys on konserve's
:id, which is coarser (a logical identity,shared by replicas across machines) and within one JVM names one store. Stores
built through a backend constructor carry no id and fall back to the object,
which is the old behaviour.
The regression test observes the monitor through the behaviour it exists for
rather than reaching into private state: a lock held on one connection must
exclude the other. It fails on the old key.
Why stratum's GC is not being changed
doc/gc-and-store-ownership.mdrecords what the vertical established, becausethe obvious next step — porting stratum to
konserve.gc/sweep!for consistency— would be a mistake as things stand.
Stratum is already correct on both its paths. Embedded, datahike opens
guard/writing!before the secondary flush (its comment names stratum) andabsorbs stratum's marks via
sec/mark-from-key-map. Standalone, the monitorserializes
gc!againstsync!.And its GC design follows from a choice one level up.
konserve.gc/sweep!isallow-list — it deletes everything not whitelisted — which is only safe for a
store you own outright. Stratum SHARES datahike's store, so its explicit
three-family deletion is the adaptation that sharing forces, not an oversight.
Porting would trade a safe-by-construction design for one that depends on an
exhaustive whitelist, in the exact configuration where being wrong destroys
datahike's data.
The note lays out the two axes (collection mechanism vs store ownership), the
Model 1 / Model 2 trade-off that actually needs deciding, and a tripwire: if
scriptum's konserve backing ever moves into datahike's store, its
mark-from-key-mapreturning#{}becomes a data-loss bug.Verification
1430 tests / 5866 assertions against the published konserve 0.9.375.