mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
perf(shared): index git history merge parents lazily (#17469)
This commit is contained in:
@@ -29,6 +29,19 @@ function item(
|
||||
}
|
||||
}
|
||||
|
||||
function trackedItem(id: string, parentIds: string[], reads: { count: number }): GitHistoryItem {
|
||||
const result = item(id, parentIds)
|
||||
Object.defineProperty(result, 'id', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
reads.count += 1
|
||||
return id
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
function branch(name: string, revision: string): GitHistoryItemRef {
|
||||
return {
|
||||
id: `refs/heads/${name}`,
|
||||
@@ -80,6 +93,60 @@ describe('git history graph model', () => {
|
||||
expect(getGitHistoryMergeParentLaneIndex(viewModels[0]!, 'B')).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps the first matching parent when history contains duplicate ids', () => {
|
||||
const headRef = branch('head', 'merge')
|
||||
const firstParentRef = branch('first', 'duplicate')
|
||||
const laterParentRef = remote('later', 'duplicate')
|
||||
const colorMap = buildDefaultGitHistoryColorMap({
|
||||
currentRef: headRef,
|
||||
remoteRef: firstParentRef,
|
||||
baseRef: laterParentRef
|
||||
})
|
||||
const viewModels = buildGitHistoryViewModels(
|
||||
[
|
||||
item('merge', ['base', 'duplicate'], [headRef]),
|
||||
item('base', []),
|
||||
item('duplicate', [], [firstParentRef]),
|
||||
item('duplicate', [], [laterParentRef])
|
||||
],
|
||||
colorMap,
|
||||
headRef
|
||||
)
|
||||
|
||||
expect(viewModels[0]!.outputSwimlanes[1]!.color).toBe(GIT_HISTORY_REMOTE_REF_COLOR)
|
||||
})
|
||||
|
||||
it('avoids building a parent index for linear history', () => {
|
||||
const count = 64
|
||||
const reads = { count: 0 }
|
||||
const historyItems = Array.from({ length: count }, (_, index) =>
|
||||
trackedItem(`commit-${index}`, index + 1 < count ? [`commit-${index + 1}`] : [], reads)
|
||||
)
|
||||
|
||||
buildGitHistoryViewModels(historyItems)
|
||||
|
||||
// A linear graph reads each item while projecting; an eager index would add one read per row.
|
||||
expect(reads.count).toBeLessThanOrEqual(count * 5)
|
||||
})
|
||||
|
||||
it('indexes merge parents once instead of rescanning a large history', () => {
|
||||
const mergeCount = 64
|
||||
const targetId = `target-${mergeCount}`
|
||||
const reads = { count: 0 }
|
||||
const historyItems: GitHistoryItem[] = []
|
||||
for (let index = 0; index < mergeCount; index += 1) {
|
||||
historyItems.push(trackedItem(`merge-${index}`, [`missing-${index}`, targetId], reads))
|
||||
// Reset swimlanes between merges so this measures parent lookup, not lane growth.
|
||||
historyItems.push(trackedItem(`leaf-${index}`, [], reads))
|
||||
}
|
||||
historyItems.push(trackedItem(targetId, [], reads))
|
||||
|
||||
buildGitHistoryViewModels(historyItems)
|
||||
|
||||
// Repeated Array#find scans grow with rows; one index build stays within a linear read budget.
|
||||
expect(reads.count).toBeLessThan(historyItems.length * 8)
|
||||
})
|
||||
|
||||
it('inserts incoming and outgoing boundary rows at the merge base', () => {
|
||||
const currentRef = branch('feature', 'A')
|
||||
const remoteRef = remote('origin/feature', 'R')
|
||||
|
||||
@@ -103,6 +103,7 @@ export function buildGitHistoryViewModels(
|
||||
): GitHistoryItemViewModel[] {
|
||||
let colorIndex = -1
|
||||
const viewModels: GitHistoryItemViewModel[] = []
|
||||
let historyItemsById: Map<string, GitHistoryItem> | undefined
|
||||
|
||||
for (const historyItem of historyItems) {
|
||||
const kind = historyItem.id === currentRef?.revision ? 'HEAD' : 'node'
|
||||
@@ -131,7 +132,18 @@ export function buildGitHistoryViewModels(
|
||||
if (index === 0) {
|
||||
colorIdentifier = getLabelColorIdentifier(historyItem, colorMap)
|
||||
} else {
|
||||
const parent = historyItems.find((item) => item.id === historyItem.parentIds[index])
|
||||
// Side-parent colors need a lookup; defer indexing so linear histories pay no map cost.
|
||||
if (!historyItemsById) {
|
||||
historyItemsById = new Map()
|
||||
for (const candidate of historyItems) {
|
||||
// Array#find returns the first duplicate, so retain first-wins ordering here.
|
||||
const candidateId = candidate.id
|
||||
if (!historyItemsById.has(candidateId)) {
|
||||
historyItemsById.set(candidateId, candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
const parent = historyItemsById.get(historyItem.parentIds[index]!)
|
||||
colorIdentifier = parent ? getLabelColorIdentifier(parent, colorMap) : undefined
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user