fix(palace): pair the mine_palace_lock holder-set update with its release (#1970) - #1971
Merged
igorls merged 1 commit intoJul 14, 2026
Conversation
Contributor
Author
This was referenced Jul 9, 2026
…ease _mark_held(palace_key) ran before the try: whose finally runs _mark_released(). An async exception (SIGINT/KeyboardInterrupt) landing after _mark_held() and before the try: skips _mark_released(), stranding the key in the process-wide _palace_lock_keys set while the outer finally frees the flock. The in-memory hold then outlives the OS lock: a later re-entrant acquire passes through and writes without the flock while another process can acquire it, i.e. two writers into one palace. Move _mark_held() inside the try so it pairs with _mark_released() on every exit. Add a regression test that injects the interrupt in the window and asserts the holder set is not stranded.
mvalentsev
force-pushed
the
fix/palace-lock-holder-set-async-safety
branch
from
July 11, 2026 10:22
3cf9338 to
4b98dd7
Compare
Merged
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 #1970.
What does this PR do?
mine_palace_lock()recorded the process-wide hold with_mark_held(palace_key)before thetry:whosefinally:runs_mark_released(). An async exception (aKeyboardInterrupt/SIGINT, or one injected into a thread) landing in the gap after_mark_held()and before thetry:skips_mark_released(), sopalace_keyis left in the_palace_lock_keysset. The outerfinally:still frees the flock, so the in-memory holder set outlives the OS lock:_held_by_this_process()then reports a hold the flock no longer backs, the next re-entrant acquire in this process passes through and writes without the flock, and another process is free to acquire it at the same time. That is two writers into one palace, the HNSW-corruption race the lock is there to stop.The fix moves
_mark_held()to the first line inside thetry:, so it pairs with_mark_released()on every exit._mark_released()is aset.discard, so releasing a key that was never added is a no-op, and the normal acquire/release path is unchanged.How to test
tests/test_palace_locks.py::test_holder_set_not_orphaned_by_interrupt_after_mark_heldruns the real_mark_held, then raises in the window as a signal would, and asserts the holder set is unchanged afterwards. It fails on the current code (the key is stranded) and passes with the fix.Checklist
python -m pytest tests/ -v)ruff check .)