Repository navigation
Stores: update(annotation) — replace by id in one transaction (#66) - #67
Merged
Merged
Conversation
remove(id) then add(...) is two commits, so a reader between them sees the id missing. update exists on MemoryStore, MappingStore, SqliteStore and PostgresStore; it raises KeyError for an unknown id. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… MappingStore add/remove (#66) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Fixes #66.
store.update(annotation)replaces the annotation with that id atomically on every backend (added to theIntervalAnnotationStoreprotocol). RaisesKeyErrorfor an unknown id (addstays the way to create); the replacement may change interval or tier. Additive: nothing existing changes signature.BEGIN IMMEDIATEtransaction updates the row and its R*Tree entry. On a connection shared between threads a reader would see the open transaction's state, so annotation reads (all,by_tier,__getitem__,_candidates, id lookup) now take the store's lock.RLock.UPDATE ... WHERE id AND owner/projectstatement (atomic in any isolation mode);TierOverlapErroras inadd.Tests:
tests/test_store_update.py(memory, mapping, sqlite): replace, move, unknown id, and the acceptance test, a reader thread against a replacing thread, same-interval and moving. Guard checked by mutation: swappingupdateforremove+addfails all six concurrency cases; removing the sqlite read lock fails both sqlite ones. Postgres tests are intests/test_store_postgres.py(including a reader on a second connection). No Postgres server on the machine that built this, so those tests were not run here (they skip); the Postgres code follows the file's existing patterns.Local: full suite with
--doctest-modules: 902 passed, 5 skipped.Adversarial review (fresh Opus subagent): no correctness defect in the update paths; Postgres checked by reading (placeholders, Range/Jsonb adaptation, KeyError via rowcount, ExclusionViolation). Two confirmed findings fixed in the second commit: (1) the reader thread could die and the test still pass, so it now records the reader's exceptions and asserts it ran; (2) the new
RLockbrokecopy.deepcopy/pickle of MemoryStore/MappingStore, so__getstate__/__setstate__rebuild the lock (test added). Also: MappingStoreadd/removenow take the lock, and a Postgres test forTierOverlapErrorfromupdate. Left for follow-up (filed as an issue): MappingStore__setitem__/__delitem__do not take the lock; iteration over the store while an update moves an annotation can still raise, as withaddbefore.🤖 Generated with Claude Code