fix(privacy): merge token vault writes across instances; thread-safe SQLite vault - #400
Merged
Merged
Conversation
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
FreshData benchmark report —
|
| fixture | n_rows | n_cols | p50 s | p95 s | peak MB | repair % | false-repair % | preserve % | trust | monotonic | export % |
|---|
Authored-code reduction (Metric 6)
…SQLite vault Root cause: - JsonTokenVault loaded its file once in __init__ and every put rewrote the whole file from that in-memory copy, so two instances sharing a path overwrote each other's entries and those tokens could no longer be detokenized. - SqliteTokenVault opened its connection with sqlite's default check_same_thread=True, so a vault created in one thread raised ProgrammingError when apply_privacy_policy ran it from a worker thread. Fix: - JsonTokenVault merges and serialises writes. put/save open the file with open(path, "a+"), take an exclusive fcntl.flock (msvcrt.locking on byte 0 on Windows; the per-instance thread lock alone when neither module is importable), always re-read the file inside the lock, merge it with the in-memory map, rewrite it in place, then flush and fsync before unlocking. A put whose entry is already on disk skips the rewrite. __init__ reads under a shared lock, get reloads on a miss when the file changed, and an empty file loads as an empty vault. The docstring notes that a crash mid-write can leave the file incomplete. - SqliteTokenVault connects with check_same_thread=False and timeout=30.0, and an RLock serialises get, put, __len__ and close. Closes #279
kevincostner17
force-pushed
the
fix/token-vault-concurrency
branch
from
September 15, 2026 11:03
f6f24ce to
f418b00
Compare
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.
Summary
Fixes two problems with sharing the persistent token vaults.
put, so two instances on the same path overwrote each other's entries.put/savenow opens the file and takes an exclusive lock:fcntl.flockon POSIX,msvcrt.lockingon byte 0 on Windows, or only the per-instance thread lock when neither is available.flush()+os.fsync()before unlocking.putwhose entry is already on disk skips the rewrite.__init__reads under a shared lock,getreloads on a miss when the file has changed, and an empty file loads as an empty vault.check_same_thread=False, timeout=30.0, and anRLockserialisesget,put,__len__andclose. A vault created in the main thread can therefore be passed toapply_privacy_policyrunning in a worker pool.Only the two vault classes (plus a small lock helper next to them) change; tokenization, masking and key handling are untouched. The on-disk format is unchanged.
Behaviour changes:
JSONDecodeError.save()keeps entries that other instances wrote.Limitation: CI has no Windows job, so the
msvcrtpath is covered only by a stub-module test.Rebased onto #399 (merged); the only overlap was the
privacy.pyimport block.Tests
New
tests/test_token_vault_concurrency.py(17 tests, well under a second,tmp_pathonly):getsees A's entry.put.putskips the rewrite.save()keeps other instances' entries.msvcrt.ThreadPoolExecutorworker.12 of the new tests fail on main, including both issue repros. The new file passed 5 runs in a row on each interpreter.
Verification
ruff check .: passed.mypy src/freshdata: no issues.pytest -m "not online and not large"on main 78b7790 (after fix(privacy): missing values stay missing, categorical k-anonymity, duplicate labels, fpe audit metadata, NER status #399) + this commit:Closes #279