Skip to content

Close the OLC validation and ordering holes gating the WorkTable write mutex - #3

Merged
pathscale merged 15 commits into
masterfrom
fix/audit-findings
Sep 1, 2026
Merged

pathscale merged 15 commits into
masterfrom
fix/audit-findings

Conversation

@pathscale

Copy link
Copy Markdown
Owner

Fixes the five reader-vs-writer holes found by the 2026-08-31 WorkTable audit. These are the items gating removal of WorkTable's global write mutex (the 0.4.1 visibility-bug workaround, whose underlying bug 0.4.2 already fixed).

Fixes

  1. Range scan single-child miss path validated — scan() returned Ok(0) (authoritative empty range) without check_version when get_child missed, so a scan racing a same-node insert (whose copy_within shifts the key array mid-read) reported empty while committed keys existed. The miss path now validates like the hit path.
  2. No scan read escapes unvalidated — KeyTracker::append_prefix re-validates the child version after reading its prefix, and every successful return in scan()/find_start()/find_end()/copy_node_recursive() re-validates the node, closing the torn-prefix window on the last-processed child.
  3. KeyTracker::push is fallible — overflow (only reachable via torn reads) maps to VersionNotMatch and feeds the existing retry loops instead of aborting the process (release profile is panic=abort).
  4. Seqlock ordering strengthened — both upgrade CAS success orderings Release → AcqRel (lock acquisition needs Acquire), and check_version gets an Acquire fence before its load so preceding data loads cannot sink below the re-validation. One-line rationale comments at each site.
  5. Payload tag invariant asserted and documented — NodePtr::from_payload debug-asserts the high bit; CongeeRaw::insert documents that values must stay below 2^63. Plus: range-scan docs corrected to end-exclusive [start, end) (the implementation is authoritative; the inclusive doc comments were wrong), and the Arc wrapper's compute_* no longer leaks one refcount per contention retry.

Verification

  • New test_scan_racing_same_node_insert: 100k native rounds; catches fix 1 when it is reverted (3/5 runs), which is the teeth check. Also wrapped for shuttle and added to CI.
  • Full suite green: 92 lib + 7 integration + 39 doc tests, clippy --all-features -D warnings, fmt, and all four shuttle CI targets in release.
  • Honest scope note: shuttle cannot observe the plain-memory copy_within tear (it only preempts at instrumented atomics) and models everything as SeqCst, so the native stress is the net for fix 1 and the ordering fixes in commit 4 are correct by construction rather than shuttle-validated.

Known issues documented for the next audit (not fixed here)

stats()/to_compact_set() unwrap read locks and abort under a concurrent writer; to_compact_set() has an empty-node underflow and i16 offset truncation; remove never shrinks/merges nodes (memory ratchets under churn); retry loops spin without parking; no resumable scan cursor (consumers should key-page).

For WorkTable

After this merges and publishes, WorkTable can drop its global write mutex around congee mutations (src/index/congee.rs), and its range adapter should switch to key-paging.

@pathscale
pathscale merged commit ef8dd33 into master Sep 1, 2026
7 checks passed
@pathscale
pathscale deleted the fix/audit-findings branch September 1, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant