Repository navigation
Fixes the same class of bug that 63d5df6 addressed in SyncVec::iter(): an unconditional
promote() on a read path publishes a fresh snapshot and retires the previous one, so the
retired allocation is kept alive until the container is dropped.
Fixed
SyncHashMap::iter(),SyncIndexMap::iter(),SyncBtreeMap::iter()now publish a fresh
snapshot only whendirtyhas un-published writes (amended), exactly like
SyncVec::iter(). Previously every call retired a whole snapshot and paid an O(n) clone
under the lock just to throw the previous snapshot away.SyncVec::get_uncheck()now uses the same lazy path asget(): lock-free on a hit,
promotion only when the index is still pending indirty.clear()on all four containers only promotes whendirtywas non-empty.IterMut::drop()only promotes when an element was actually handed out, so dropping an
unusediter_mut()no longer retires a snapshot.
Notes
- Writes that completed before a call are still visible; as with Go's
sync.Map, a reader
that misses theamendedflag may observe a snapshot that predates a concurrent write. - No public API changes.
Tests
- Added a test-only
AtomicSnapshot::retired_len()and 21 unit tests across the four
containers asserting that repeatediter()/clear()/ unusediter_mut()calls do not
grow the retired snapshot list, while pending writes stay visible anditer_mut()still
publishes mutations. - Full suite green (24 lib tests + integration + doc tests), plus a Miri run with
--no-default-features --features std-lock.