mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
perf(ai-vault): bound scope cache write batch enumeration (#31950)
* perf(ai-vault): bound scope cache write batch enumeration * test(ai-vault): type scope cache stamp fixture --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -25,7 +25,12 @@ import {
|
||||
type SessionParseStats
|
||||
} from './session-scanner-parse-cache'
|
||||
import type * as ParseCacheModule from './session-scanner-parse-cache'
|
||||
import { getSessionParseCacheEntry, storeSessionParseCacheEntry } from './session-parse-cache-store'
|
||||
import {
|
||||
getSessionParseCacheEntry,
|
||||
storeSessionParseCacheEntry,
|
||||
storeSessionScopeCwd,
|
||||
type SessionScopeCwdStamp
|
||||
} from './session-parse-cache-store'
|
||||
import type { SessionSidecarObservation } from './session-sidecar-stat'
|
||||
import { isolatedScanRoots } from './session-scanner-test-fixtures'
|
||||
import { parseClaudeSessionFile } from './session-scanner-primary-parsers'
|
||||
@@ -163,6 +168,40 @@ describe('session parse cache persistence', () => {
|
||||
expect(snapshot).not.toBe(configured)
|
||||
})
|
||||
|
||||
it('persists scope rows across chunks and keeps replacements queued during a yield', async () => {
|
||||
const root = await makeTempDir()
|
||||
const cacheFile = join(root, 'session-parse-cache.json')
|
||||
initSessionParseCachePersistence({ filePath: cacheFile, appVersion: APP_VERSION })
|
||||
const paths = Array.from({ length: 1_001 }, (_, index) => join(root, `session-${index}`))
|
||||
const stamp: SessionScopeCwdStamp = {
|
||||
mtimeMs: 1,
|
||||
sizeBytes: 10,
|
||||
platform: 'linux',
|
||||
cwd: '/original'
|
||||
}
|
||||
for (const path of paths) {
|
||||
storeSessionScopeCwd(path, stamp)
|
||||
}
|
||||
const flushing = flushSessionParseCachePersist()
|
||||
const replacement = { ...stamp, mtimeMs: 2, cwd: '/updated' }
|
||||
storeSessionScopeCwd(paths[0]!, replacement)
|
||||
storeSessionScopeCwd(paths[750]!, replacement)
|
||||
await flushing
|
||||
resetSessionParseCachePersistenceForTests()
|
||||
resetSessionParseCacheForTests()
|
||||
|
||||
const database = new SessionParseCacheDatabase(join(root, 'session-parse-cache.sqlite'))
|
||||
try {
|
||||
const stored = database.readScopeCwds(paths).found
|
||||
expect(stored.size).toBe(paths.length)
|
||||
for (const [index, path] of paths.entries()) {
|
||||
expect(stored.get(path)?.read).toEqual(index === 0 || index === 750 ? replacement : stamp)
|
||||
}
|
||||
} finally {
|
||||
database.close()
|
||||
}
|
||||
})
|
||||
|
||||
it('round-trips: a persisted entry is a reused hit after a restart, without reading the transcript', async () => {
|
||||
const root = await makeTempDir()
|
||||
const cacheFile = join(root, 'vault-state', 'session-parse-cache.json')
|
||||
|
||||
@@ -88,24 +88,14 @@ export function resetSessionParseCachePersistenceForTests(): void {
|
||||
export async function flushSessionParseCachePersist(): Promise<void> {
|
||||
clearWriteTimer()
|
||||
while (pendingWrites.size > 0) {
|
||||
const chunk: [string, PersistedSessionParseCacheEntry][] = []
|
||||
for (const row of pendingWrites) {
|
||||
chunk.push(row)
|
||||
pendingWrites.delete(row[0])
|
||||
if (chunk.length === WRITE_CHUNK_ROWS) {
|
||||
break
|
||||
}
|
||||
}
|
||||
const chunk = takeWriteChunk(pendingWrites)
|
||||
openedDatabase()?.write(chunk, Date.now())
|
||||
if (pendingWrites.size > 0) {
|
||||
await yieldToEventLoop()
|
||||
}
|
||||
}
|
||||
while (pendingScopeCwds.size > 0) {
|
||||
const chunk = [...pendingScopeCwds].slice(0, WRITE_CHUNK_ROWS)
|
||||
for (const [path] of chunk) {
|
||||
pendingScopeCwds.delete(path)
|
||||
}
|
||||
const chunk = takeWriteChunk(pendingScopeCwds)
|
||||
openedDatabase()?.writeScopeCwds(chunk, Date.now())
|
||||
if (pendingScopeCwds.size > 0) {
|
||||
await yieldToEventLoop()
|
||||
@@ -113,6 +103,18 @@ export async function flushSessionParseCachePersist(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
function takeWriteChunk<T>(pending: Map<string, T>): [string, T][] {
|
||||
const chunk: [string, T][] = []
|
||||
for (const row of pending) {
|
||||
chunk.push(row)
|
||||
pending.delete(row[0])
|
||||
if (chunk.length === WRITE_CHUNK_ROWS) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return chunk
|
||||
}
|
||||
|
||||
// Opened on first need, so Electron main (which never looks rows up) never opens it.
|
||||
function openedDatabase(): SessionParseCacheDatabase | null {
|
||||
if (database !== undefined || !owner || options === null) {
|
||||
|
||||
Reference in New Issue
Block a user