/** Process-local read reuse. Every access checks the live database revision, including cache hits. */ export class RevisionReadCache { private readonly entries = new Map; bytes: number }>(); private revision: number | undefined; constructor(private readonly maxEntries = 8, private readonly maxBytes = 32 * 1024 * 1024) {} async read(key: string, currentRevision: () => Promise, load: () => Promise): Promise { for (let attempt = 0; attempt < 3; attempt += 1) { const before = await currentRevision(); if (!Number.isSafeInteger(before) || before < 0) throw new Error('Cannot verify the database revision.'); if (this.revision !== before) { this.entries.clear(); this.revision = before; } let entry = this.entries.get(key); if (!entry) { entry = { value: Promise.resolve().then(load), bytes: 0 }; this.entries.set(key, entry); while (this.entries.size > this.maxEntries) this.entries.delete(this.entries.keys().next().value!); } // Refresh insertion order for bounded least-recently-used retention. if (this.entries.get(key) === entry) { this.entries.delete(key); this.entries.set(key, entry); } try { const value = await entry.value; if (await currentRevision() !== before) { if (this.entries.get(key) === entry) this.entries.delete(key); continue; } if (this.entries.get(key) === entry && entry.bytes === 0) { entry.bytes = Buffer.byteLength(JSON.stringify(value), 'utf8'); let retainedBytes = [...this.entries.values()].reduce((sum, item) => sum + item.bytes, 0); while (retainedBytes > this.maxBytes && this.entries.size) { const oldest = this.entries.keys().next().value!; retainedBytes -= this.entries.get(oldest)!.bytes; this.entries.delete(oldest); } } return value; } catch (error) { if (this.entries.get(key) === entry) this.entries.delete(key); throw error; } } throw new Error('ASSESSOR data changed repeatedly while results were read. Please retry.'); } }