You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 28dd843
Browse filesBrowse the repository at this point in the historyBrowse files
fix: make setvar =+N / =-N an atomic update in the collection backend
`setvar:ip.counter=+1` was a read-modify-write at the action level:
`SetVar::evaluate` resolved the current value, added the delta and
stored the result with `storeOrUpdateFirst`. Two transactions doing the
same read concurrently stored the same incremented number, so counters
in persistent collections drifted under load. With LMDB it is worse:
the database is opened with `MDB_DUPSORT`, so a stale read makes the
`mdb_del` inside `storeOrUpdateFirst` fail and the whole write
transaction is aborted, losing the increment outright.
Add `Collection::incrementFirst(key, delta)` and implement it in both
backends as one atomic step: the in-memory backend does the read, add
and write under its existing exclusive lock, and the LMDB backend does
them inside a single write transaction, which holds the LMDB writer
lock across threads and processes. The base class keeps a non-atomic
fallback for out-of-tree backends. `SetVar::evaluate` now calls it for
the `=+N` and `=-N` forms through the `*_DynamicElement` helpers.
Missing, expired or non-numeric values still count as 0, as before.
Measured with a harness running 8 threads x 2000 transactions, each
with `setvar:ip.counter=+1`, against an LMDB build on macOS: before
this change 2001 of 16001 increments survived (three identical runs);
with it, all 16001 do.
Fixes#2306.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tz1sULBvqAwnRreKh5eC9h
0 commit comments