Skip to content

Size SSTable bloom filters by entry count#117

Open
mweiden wants to merge 1 commit into
mainfrom
claude/audit-fix-10-bloom-filter-sizing
Open

Size SSTable bloom filters by entry count#117
mweiden wants to merge 1 commit into
mainfrom
claude/audit-fix-10-bloom-filter-sizing

Conversation

@mweiden

@mweiden mweiden commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Problem

Bloom filters were a fixed 1024 bits regardless of how many keys an SSTable held. Any table beyond a few hundred entries saturated the filter, so may_contain returned true for nearly every absent key — the filter stopped pruning disk reads entirely, which is its only job.

Fix

  • BloomFilter::with_capacity(expected_keys): 10 bits per key (~3% false-positive rate with the two hash functions used), 1024-bit floor.
  • SsTable::create sizes the filter from the entry count; the meta-less rebuild path in SsTable::load counts entries in a first pass and sizes identically.
  • Hardening: an empty bit vector (e.g. decoded from a corrupt/empty meta proto) previously hit a modulo-by-zero panic in hashes(); it now reports may_contain = true (no information ⇒ must not rule keys out) and insert is a no-op. new(0) is also guarded.

Tests

  • sized_filter_keeps_false_positive_rate_low: 10k keys, no false negatives, <20% FP on absent keys (the old fixed filter is ~100% here).
  • bloom_filter_scales_with_entry_count: same property at the SSTable level, both freshly created and rebuilt without a meta file.
  • empty_filter_from_proto_does_not_panic, zero_size_filter_does_not_panic.

Found by codebase audit (medium severity: bloom filter ineffective at scale + panic on corrupt meta).

https://claude.ai/code/session_01CJXWjB9ERGgV6B9mRqrdM9


Generated by Claude Code

Bloom filters were a fixed 1024 bits regardless of how many keys an
SSTable held, so any table beyond a few hundred entries saturated the
filter and may_contain returned true for nearly every absent key,
defeating the filter's purpose of pruning disk reads.

Filters are now sized at 10 bits per key (~3% false-positive rate with
the two hash functions used), with a 1024-bit floor. The rebuild path
in SsTable::load counts entries first and sizes the filter the same
way. Also hardened the filter against empty bit vectors (e.g. decoded
from a corrupt meta file): an empty filter now reports may_contain =
true instead of panicking on a modulo-by-zero.

https://claude.ai/code/session_01CJXWjB9ERGgV6B9mRqrdM9
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.

2 participants