Skip to content

Commit 18f8ff9

Browse files
indexzeroclaude
andauthored
fix(cache): prevent bloom filter from rejecting reads on existing caches (#20)
The bloom filter was incorrectly blocking all reads from existing caches because it was empty on startup - it wasn't populated from the persisted cache data. Added _bloomPopulated flag that is only set to true when keys are added via set(). The bloom filter check in fetch() and has() now only applies when this flag is true, allowing reads from existing caches to work. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0fa5278 commit 18f8ff9

1 file changed

Lines changed: 13 additions & 10 deletions

File tree

src/cache/cache.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ export class Cache {
1313
this.bloomSize = options.bloomSize || 10000;
1414
this.bloomFalsePositiveRate = options.bloomFalsePositiveRate || 0.01;
1515
this._bloomInitialized = false;
16+
this._bloomPopulated = false; // True only when bloom filter is populated from existing data
1617
this._inflightRequests = new Map();
1718
this._driverInitialized = false;
18-
19+
1920
if (!this.driver) {
2021
throw new Error('Storage driver is required');
2122
}
@@ -61,12 +62,13 @@ export class Cache {
6162
async _doFetch(key, options = {}) {
6263
const driver = await this._ensureDriver();
6364
await this._initBloomFilter();
64-
65-
// Check bloom filter first for non-existence
66-
if (this.bloomFilter && !this.bloomFilter.has(key)) {
65+
66+
// Only use bloom filter if it was pre-populated (e.g., loaded from disk)
67+
// An empty bloom filter would incorrectly reject all keys from existing caches
68+
if (this.bloomFilter && this._bloomPopulated && !this.bloomFilter.has(key)) {
6769
return null; // Definitely not in cache
6870
}
69-
71+
7072
try {
7173
const value = await driver.get(key);
7274
// Handle cache validation, ETags, etc.
@@ -82,20 +84,21 @@ export class Cache {
8284
async set(key, value, options = {}) {
8385
const driver = await this._ensureDriver();
8486
await this._initBloomFilter();
85-
86-
// Add to bloom filter
87+
88+
// Add to bloom filter and mark as populated
8789
if (this.bloomFilter) {
8890
this.bloomFilter.add(key);
91+
this._bloomPopulated = true;
8992
}
9093
return driver.put(key, value, options);
9194
}
9295

9396
async has(key) {
9497
const driver = await this._ensureDriver();
9598
await this._initBloomFilter();
96-
97-
// Check bloom filter first
98-
if (this.bloomFilter && !this.bloomFilter.has(key)) {
99+
100+
// Only use bloom filter if it was pre-populated
101+
if (this.bloomFilter && this._bloomPopulated && !this.bloomFilter.has(key)) {
99102
return false; // Definitely not in cache
100103
}
101104
return driver.has(key);

0 commit comments

Comments
 (0)