codeburn/tests/fixtures/session-cache-io.ts
iamtoruk 0bfdfa372a perf(cache): shard the session cache per provider
A warm launch rewrote the entire session cache whenever any provider
appended a few KB: on a 6 GB corpus that is a 155 MB stringify + fsync
every run. The on-disk cache is now a version-suffixed directory holding
one shard per provider plus a small envelope, and a save rewrites only
the providers marked dirty.

- Dirtiness is tracked per provider (markCacheDirty) instead of one
  global flag, so an appended Claude session no longer republishes
  Codex, Copilot and the rest.
- Shards carry a nonce in their filename and the envelope is renamed
  last, so a save is published at a single point: readers never see a
  half-updated set, and a writer that loses the refresh ownership fence
  leaves the canonical shards untouched.
- A shard that fails validation is treated as an absent provider rather
  than rejecting the whole cache, so one malformed turn costs one
  provider's re-parse instead of every provider's history.
- v7 migrates losslessly: the blob is re-laid-out into shards and
  removed only once that save publishes. Nothing re-parses.
- Cold-parse progress saves now trigger every N files parsed rather than
  every 5s, so a slow cold parse no longer rewrites the growing cache on
  a wall clock.
2026-08-16 19:03:12 -07:00

35 lines
1.2 KiB
TypeScript

// Test-side IO for the sharded session cache: the on-disk form is a directory
// (envelope + one shard per provider), so tests read and write it through the
// real load/save path instead of touching a single JSON file.
import { readFile, readdir } from 'fs/promises'
import { join } from 'path'
import {
clearLoadCacheMemo,
loadCache,
markCacheDirty,
saveCache,
sessionCacheDir,
type SessionCache,
} from '../../src/session-cache.js'
/** The cache exactly as it is on disk, bypassing the in-process memo. */
export async function readCacheOnDisk(): Promise<SessionCache> {
clearLoadCacheMemo()
return loadCache()
}
/** Publish `cache`, rewriting every provider's shard. */
export async function writeCacheOnDisk(cache: SessionCache): Promise<void> {
for (const provider of Object.keys(cache.providers)) markCacheDirty(cache, provider)
await saveCache(cache)
clearLoadCacheMemo()
}
/** Byte-level snapshot of the whole cache directory (names + contents). */
export async function cacheDirSnapshot(): Promise<string> {
const dir = sessionCacheDir()
const names = (await readdir(dir)).sort()
const parts = await Promise.all(names.map(async name => `${name}:${await readFile(join(dir, name), 'utf-8')}`))
return parts.join('\n')
}