Files
orca/src/main/opencode-usage/persisted-state-normalization.ts
T
09aff1b94d perf(usage): keep per-source usage caches off the main thread (#26980)
* perf(usage): keep per-source usage caches off the main thread

The usage stores kept every provider's per-source scan cache
(processedFiles / processedDatabases) inside the one JSON file main
loads at startup. On a large Claude history that file is 56 MB, 43 MB
of it per-source records only a scan reads, so main paid a sync
read+parse at launch, a structured clone of the whole cache to and
from the scan worker on every scan, and a pretty-printed rewrite
after every scan.

The usage scan worker now owns those records in a sidecar
(`<cache>-sources.json`): it reads it before a scan, writes it after
(compact, durable rename), and returns only sessions and daily
aggregates. Main keeps and writes only that report, compact. A cache
still carrying inline records is split on the worker the first time
it is loaded (above 8 MB); smaller ones parse on main and rescan cold.
Sync IPC getters and automation lookups wait for the load.

Synthetic 56 MB cache, same machine, interleaved runs:
- first launch: 108 ms sync parse -> 18 ms main busy, 4 ms longest block
- later launches: ~69 ms -> ~7 ms
- forced scan, longest main-thread block: 89 ms -> 11 ms
  (real built app, headless: 84-94 ms -> 11-13 ms)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(usage): preserve cache attribution and legacy warm scans

* fix(usage): reclaim cache temps after worker retirement

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Neil <neil@stably.ai>
2026-10-09 17:19:29 -07:00

44 lines
1.2 KiB
TypeScript

import type { OpenCodeUsagePersistedState } from './types'
import { OPENCODE_USAGE_SCHEMA_VERSION } from './opencode-usage-provider'
import {
normalizeDailyAggregateCost,
normalizeOpenCodeUsagePersistedDatabases,
normalizeSessionCost
} from './persisted-database-normalization'
const SCHEMA_VERSION = OPENCODE_USAGE_SCHEMA_VERSION
export function getDefaultState(): OpenCodeUsagePersistedState {
return {
schemaVersion: SCHEMA_VERSION,
worktreeFingerprint: null,
processedDatabases: [],
sessions: [],
dailyAggregates: [],
scanState: {
enabled: false,
lastScanStartedAt: null,
lastScanCompletedAt: null,
lastScanError: null
}
}
}
export function normalizePersistedState(
state: OpenCodeUsagePersistedState
): OpenCodeUsagePersistedState {
if (state.schemaVersion !== SCHEMA_VERSION) {
const defaults = getDefaultState()
return {
...defaults,
scanState: { ...defaults.scanState, enabled: state.scanState?.enabled ?? false }
}
}
return {
...state,
processedDatabases: normalizeOpenCodeUsagePersistedDatabases(state.processedDatabases),
sessions: state.sessions.map(normalizeSessionCost),
dailyAggregates: state.dailyAggregates.map(normalizeDailyAggregateCost)
}
}