()
| 265 | /* ---- Disk cache load / save ---- */ |
| 266 | |
| 267 | export async function loadCacheData(): Promise<CacheData | null> { |
| 268 | try { |
| 269 | if (!fs.existsSync(CACHE_META) || !fs.existsSync(CACHE_FILE)) return null; |
| 270 | if (fs.statSync(CACHE_META).size > MAX_CACHE_META_BYTES) { |
| 271 | warnCore('Cache', 'Cache meta file exceeds size limit; ignoring and re-parsing'); |
| 272 | return null; |
| 273 | } |
| 274 | const meta = readCacheMetaPayload(JSON.parse(fs.readFileSync(CACHE_META, 'utf-8')) as unknown); |
| 275 | if (!meta || meta.version !== CACHE_VERSION) return null; // old format – full re-parse |
| 276 | |
| 277 | const cacheSize = (await fs.promises.stat(CACHE_FILE)).size; |
| 278 | if (cacheSize > MAX_CACHE_FILE_BYTES) { |
| 279 | warnCore('Cache', `Cache file exceeds size limit (${cacheSize} bytes); ignoring and re-parsing`); |
| 280 | return null; |
| 281 | } |
| 282 | |
| 283 | // Read async to avoid blocking the event loop on the 200+ MB cache file |
| 284 | const rawStr = await fs.promises.readFile(CACHE_FILE, 'utf-8'); |
| 285 | // Yield before the expensive JSON.parse so any pending IPC messages flush |
| 286 | await new Promise<void>(r => setTimeout(r, 0)); |
| 287 | const raw = readSerializedCachePayload(JSON.parse(rawStr) as unknown); |
| 288 | if (!raw) return null; |
| 289 | // Yield after parse to let the event loop breathe |
| 290 | await new Promise<void>(r => setTimeout(r, 0)); |
| 291 | const workspaces = new Map<string, Workspace>(raw.workspaces); |
| 292 | const editLocIndex = new Map<string, Map<string, number>>(); |
| 293 | for (const [k, v] of raw.editLocIndex) { |
| 294 | editLocIndex.set(k, new Map(v)); |
| 295 | } |
| 296 | const sessionSourceIndex = new Map<string, SessionSource>(raw.sessionSourceIndex); |
| 297 | return { |
| 298 | result: { workspaces, sessions: raw.sessions, editLocIndex, sessionSourceIndex }, |
| 299 | dirMetas: meta.dirMetas, |
| 300 | }; |
| 301 | } catch (e) { |
| 302 | console.debug('Cache load failed, treating as miss:', e instanceof Error ? e.message : e); |
| 303 | return null; |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | export function saveCacheData(result: ParseResult, dirMetas: DirMetas): void { |
| 308 | // Serialize immediately so the snapshot is captured before any in-memory |
no test coverage detected