Files
orca/src/shared/git-status-line-stats-write-token.ts
T
Jinjing debf4affe7 Display total lines of code change in branch header (#12771)
* Add branch line total chip to source control header

Display the total lines added and removed across a branch from its fork point, measured via `git diff <mergeBase>`. Only computed when the chip is visible (request gate on merge base OID), with 500ms soft deadline to protect status latency and 15s hard timeout. Deduplicated across concurrent pollers and cached alongside line stats. Omitted on failure — always shows exact or nothing, never a partial estimate. Updates throughout the stack: native git status, relay, renderer store/API, and UI components.

* Pin branch line total to app locale

Format line counts using the app's configured locale instead of the system
locale, ensuring consistent cross-platform display and test reliability.

* test: wait for coalescer joins instead of fixed sleep

Hold the diff until the second status pass actually takes the
branch-total coalescer lease instead of using a fixed 400ms sleep.
Fixes timing-dependent flakiness on slow machines.
2026-08-05 14:46:00 -07:00

70 lines
2.4 KiB
TypeScript

/**
* Generation bookkeeping that decides whether a git-status line-stats scan may
* still write. Split from the cache itself so the snapshot store stays readable.
*/
export type GitStatusLineStatsWriteToken = {
cacheKey: string
globalGeneration: number
keyGeneration: number
beginSeq: number
}
const GIT_STATUS_LINE_STATS_WRITE_KEYS_MAX_ENTRIES = 1024
// Why: mutation invalidation must retire scans that began before it. A scan
// captures these generations at begin; a mismatch at store/clear time means an
// invalidation happened mid-scan and the derived stats may be pre-mutation.
let globalInvalidationGeneration = 0
const keyInvalidationGenerationByWorktree = new Map<string, number>()
// Why: overlapping recomputes must resolve latest-begun-wins without letting a
// reuse-only read (which never stores) starve an older recompute's store.
const lastStoredBeginSeqByWorktree = new Map<string, number>()
let nextBeginSeq = 0
function bumpBoundedKeyMap(map: Map<string, number>, cacheKey: string, value: number): void {
map.delete(cacheKey)
map.set(cacheKey, value)
while (map.size > GIT_STATUS_LINE_STATS_WRITE_KEYS_MAX_ENTRIES) {
const oldestKey = map.keys().next().value
if (oldestKey === undefined) {
return
}
map.delete(oldestKey)
}
}
export function beginGitStatusLineStatsCacheWrite(cacheKey: string): GitStatusLineStatsWriteToken {
return {
cacheKey,
globalGeneration: globalInvalidationGeneration,
keyGeneration: keyInvalidationGenerationByWorktree.get(cacheKey) ?? 0,
beginSeq: ++nextBeginSeq
}
}
export function isWriteTokenCurrent(token: GitStatusLineStatsWriteToken): boolean {
return (
token.globalGeneration === globalInvalidationGeneration &&
token.keyGeneration === (keyInvalidationGenerationByWorktree.get(token.cacheKey) ?? 0) &&
token.beginSeq >= (lastStoredBeginSeqByWorktree.get(token.cacheKey) ?? 0)
)
}
export function markGitStatusLineStatsStored(cacheKey: string, beginSeq: number): void {
bumpBoundedKeyMap(lastStoredBeginSeqByWorktree, cacheKey, beginSeq)
}
export function bumpGitStatusLineStatsKeyGeneration(cacheKey: string): void {
bumpBoundedKeyMap(
keyInvalidationGenerationByWorktree,
cacheKey,
(keyInvalidationGenerationByWorktree.get(cacheKey) ?? 0) + 1
)
}
export function resetGitStatusLineStatsWriteGenerations(): void {
globalInvalidationGeneration += 1
keyInvalidationGenerationByWorktree.clear()
lastStoredBeginSeqByWorktree.clear()
}