Skip to content

fix: route shard saves through durable_write for crash safety - #28

Merged
titusz merged 2 commits into
mainfrom
fix/durable-shard-saves
May 6, 2026
Merged

fix: route shard saves through durable_write for crash safety#28
titusz merged 2 commits into
mainfrom
fix/durable-shard-saves

Conversation

@titusz

@titusz titusz commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

Closes #26

  • Replace all direct Index.save(path) calls in ShardedIndex with buffer serialization + durable_write (temp file, fdatasync, atomic os.replace). Affects save(), _rotate_shard(), and compact().
  • Enforce bloom → shard → tombstones persistence ordering so that tombstone removals only become visible after the shard data they depend on is durable. This prevents previously deleted keys from reappearing after a crash during shard writes.
  • Add automatic bloom filter rebuild on load when the bloom file is missing or corrupt, with exception handling in _load_bloom_if_exists.
  • Extract _persist_bloom() and _persist_tombstones() helpers to eliminate duplicated save logic.

Test plan

  • test_save_uses_durable_write — monkeypatches durable_write to verify it's called for save
  • test_rotation_uses_durable_write — verifies rotation goes through durable_write
  • test_compact_uses_durable_write — verifies compact goes through durable_write
  • test_original_shard_intact_on_durable_write_failure — original file untouched when write fails
  • test_rotation_persistence_order — bloom < shard < tombstones ordering verified
  • test_tombstone_removal_safe_across_crash — deleted key stays deleted after failed shard write
  • test_bloom_rebuild_on_corrupt_file — corrupt bloom triggers rebuild
  • test_bloom_missing_file_rebuilds_on_load — missing bloom triggers rebuild
  • test_tombstone_file_missing_on_reload — no crash, keys reappear as expected
  • test_no_direct_save_path_in_sharded — AST audit: no .save(str(...)) calls remain
  • test_save_progress_callback_preserved — progress callback passes through to buffer serialization
  • Full test suite: 985 passed, 100% coverage

titusz added 2 commits May 6, 2026 21:14
Shard rotation, save, and compact were calling usearch's native
Index.save(path) which writes directly to disk without fsync or atomic
rename. Replace with buffer serialization + durable_write (temp file,
fdatasync, atomic os.replace).

Persistence ordering is bloom → shard → tombstones so that tombstone
removals only become visible after the shard data they depend on is
durable. Also adds automatic bloom rebuild on load when the bloom file
is missing or corrupt, and extracts _persist_bloom/_persist_tombstones
helpers to eliminate duplication.
@titusz
titusz merged commit 23d422b into main May 6, 2026
16 checks passed
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.

Shard rotation and save bypass durable write path

1 participant