Skip to content

Commit 657652f

Browse files
committed
perf: real LRU eviction in git diff cache + hoist newline regex
The prior gitDiffAccessOrder array was append-on-write, so it tracked insertion order, not recency — a real LRU needs touch-on-read. And shift() on eviction was O(n). Replace with a single Map that relies on insertion-order iteration: delete + re-set on read marks recent, keys().next() + delete on eviction is O(1). Also hoist the /\n/g regex in fs.ts stringify() to module scope; previously it was rebuilt on every JSON write.
1 parent d124401 commit 657652f

File tree

2 files changed

+26
-17
lines changed

2 files changed

+26
-17
lines changed

src/fs.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ import { naturalCompare } from './sorts'
5050

5151
const abortSignal = getAbortSignal()
5252

53+
// Module-level regex constants — avoid re-allocating on every call.
54+
const NEWLINE_REGEX = /\n/g
55+
5356
/**
5457
* Supported text encodings for Node.js Buffers.
5558
* Includes ASCII, UTF-8/16, base64, binary, and hexadecimal encodings.
@@ -450,7 +453,7 @@ function stringify(
450453
): string {
451454
const EOF = finalEOL ? EOL : ''
452455
const str = JSON.stringify(json, replacer, spaces)
453-
return `${str.replace(/\n/g, EOL)}${EOF}`
456+
return `${str.replace(NEWLINE_REGEX, EOL)}${EOF}`
454457
}
455458

456459
/**

src/git.ts

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,30 @@ interface GitDiffSpawnArgs {
156156
staged: SpawnArgs
157157
}
158158

159+
// LRU cache for git diff results. We exploit Map's insertion-order iteration
160+
// so eviction is O(1): delete the first key. Touching on read (delete + set)
161+
// keeps the most-recently-used entry at the back.
159162
const gitDiffCache = new Map<string, string[]>()
160-
const gitDiffAccessOrder: string[] = []
161163
const GIT_CACHE_MAX_SIZE = 100
162164

163-
function evictLRUGitCache() {
164-
if (
165-
gitDiffCache.size >= GIT_CACHE_MAX_SIZE &&
166-
gitDiffAccessOrder.length > 0
167-
) {
168-
const oldest = gitDiffAccessOrder.shift()
169-
if (oldest) {
165+
function getCachedGitDiff(key: string): string[] | undefined {
166+
const result = gitDiffCache.get(key)
167+
if (result) {
168+
// Re-insert to mark as most-recently-used.
169+
gitDiffCache.delete(key)
170+
gitDiffCache.set(key, result)
171+
}
172+
return result
173+
}
174+
175+
function setCachedGitDiff(key: string, result: string[]): void {
176+
if (gitDiffCache.size >= GIT_CACHE_MAX_SIZE) {
177+
const oldest = gitDiffCache.keys().next().value
178+
if (oldest !== undefined) {
170179
gitDiffCache.delete(oldest)
171180
}
172181
}
182+
gitDiffCache.set(key, result)
173183
}
174184

175185
// Cached git binary path to avoid repeated PATH searches.
@@ -317,7 +327,7 @@ async function innerDiff(
317327
const { cache = true, ...parseOptions } = { __proto__: null, ...options }
318328
const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined
319329
if (cache && cacheKey) {
320-
const result = gitDiffCache.get(cacheKey)
330+
const result = getCachedGitDiff(cacheKey)
321331
if (result) {
322332
return result
323333
}
@@ -349,9 +359,7 @@ async function innerDiff(
349359
return []
350360
}
351361
if (cache && cacheKey) {
352-
evictLRUGitCache()
353-
gitDiffCache.set(cacheKey, result)
354-
gitDiffAccessOrder.push(cacheKey)
362+
setCachedGitDiff(cacheKey, result)
355363
}
356364
return result
357365
}
@@ -373,7 +381,7 @@ function innerDiffSync(
373381
const { cache = true, ...parseOptions } = { __proto__: null, ...options }
374382
const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined
375383
if (cache && cacheKey) {
376-
const result = gitDiffCache.get(cacheKey)
384+
const result = getCachedGitDiff(cacheKey)
377385
if (result) {
378386
return result
379387
}
@@ -405,9 +413,7 @@ function innerDiffSync(
405413
return []
406414
}
407415
if (cache && cacheKey) {
408-
evictLRUGitCache()
409-
gitDiffCache.set(cacheKey, result)
410-
gitDiffAccessOrder.push(cacheKey)
416+
setCachedGitDiff(cacheKey, result)
411417
}
412418
return result
413419
}

0 commit comments

Comments
 (0)