Public: anyone can read this; the crew can change it.

A second read of an unmoved pull serves its diff from memory: `diff` under 5 ms when neither tip moved #8171

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/8160-a-second-read-of-an-unmoved-pull-serves → main 5 commits fork 2 threads · 2 unresolved

  • Merged. mason/8160-a-second-read-of-an-unmoved-pull-serves was merged into main as 5986e05.

Review

Sign in to review this change.
7 files changed +489 −7
src/git/diff-memory.ts added +133
@@ -0,0 +1,133 @@
1 /**
2 * Diffs between two commits, and the merge base a pull's diff starts from,
3 * kept for the next reader of the same pair.
4 *
5 * A diff between two object ids never changes, so the second reader of an
6 * unmoved pull — a reviewer, the terminal, an agent through the API — is
7 * served from here and spawns no git. The key carries the repository's
8 * directory as well as both oids: a diff read in one repository is never
9 * answered to a reader of another, whatever oids they name.
10 *
11 * Bounded by estimated bytes, least recently used out first. One diff over
12 * `MAX_DIFF_BYTES` is never kept, so a single huge change cannot empty the
13 * memory for everyone else. Values are deeply frozen: every reader shares
14 * one copy and none can change another's. A failed git run is not kept.
15 * Nothing is allocated until a process reads a diff, and it lives only as
16 * long as that process.
17 */
18
19 import type { Diff } from "./diff.ts";
20
21 /** All kept diffs together, estimated as their parsed size. */
22 export const MAX_BYTES = 32 * 1024 * 1024;
23 /** One diff larger than this is served but never kept. */
24 export const MAX_DIFF_BYTES = 4 * 1024 * 1024;
25
26 const kept = new Map<string, { diff: Diff; bytes: number }>();
27 let total = 0;
28
29 export function diffMemoryKey(dir: string, from: string, to: string): string {
30 return `${dir}\0${from}\0${to}`;
31 }
32
33 /**
34 * What a parsed diff holds in memory, roughly: each line's text twice over
35 * (strings are UTF-16) plus the row object around it.
36 */
37 export function sizeOfDiff(diff: Diff): number {
38 let n = 0;
39 for (const file of diff.files) {
40 n += 128 + file.path.length * 2;
41 for (const hunk of file.hunks) {
42 n += 64 + hunk.section.length * 2;
43 for (const line of hunk.lines) n += 48 + line.content.length * 2;
44 }
45 }
46 return n;
47 }
48
49 /** The kept diff for `key`, freshened as most recently used. */
50 export function recalled(key: string): Diff | undefined {
51 const known = kept.get(key);
52 if (known === undefined) return undefined;
53 kept.delete(key);
54 kept.set(key, known);
55 return known.diff;
56 }
57
58 /** Keep `diff` under `key` when it fits; returns the frozen value to serve. */
59 export function remember(key: string, diff: Diff): Diff {
60 const frozen = deepFreeze(diff);
61 const bytes = sizeOfDiff(frozen);
62 if (bytes > MAX_DIFF_BYTES) return frozen;
63 const known = kept.get(key);
64 if (known !== undefined) {
65 total -= known.bytes;
66 kept.delete(key);
67 }
68 kept.set(key, { diff: frozen, bytes });
69 total += bytes;
70 while (total > MAX_BYTES) {
71 const oldest = kept.keys().next().value as string;
72 total -= kept.get(oldest)!.bytes;
73 kept.delete(oldest);
74 }
75 return frozen;
76 }
77
78 /** What is held now, for tests. */
79 export function diffMemoryCounts(): { entries: number; bytes: number } {
80 return { entries: kept.size, bytes: total };
81 }
82
83 /** Forget every kept diff and merge base (tests). */
outdated

The comment mentions a Server-Timing note, but nothing outside tests calls this. Correct the comment or use it.

84 export function forgetDiffs(): void {
85 kept.clear();
86 total = 0;
87 mergeBases.clear();
88 }
89
90 // ---- merge bases ----
91 //
92 // The fork point a pull's diff is measured from is as fixed as the diff:
93 // two commits have one merge base. Each entry is three short strings, so
94 // these are bounded by count, least recently used out first.
95
96 /** How many merge bases are kept: a few hundred bytes each. */
97 export const MERGE_BASES_KEPT = 4096;
98 const mergeBases = new Map<string, string>();
99
100 /** The kept merge base for `key` (`diffMemoryKey`), freshened as most recently used. */
101 export function recalledBase(key: string): string | undefined {
102 const known = mergeBases.get(key);
103 if (known === undefined) return undefined;
104 mergeBases.delete(key);
105 mergeBases.set(key, known);
106 return known;
107 }
108
109 /** Keep the merge base found for `key`; never call this with a failed lookup. */
110 export function rememberBase(key: string, base: string): void {
111 mergeBases.delete(key);
112 mergeBases.set(key, base);
113 if (mergeBases.size > MERGE_BASES_KEPT) mergeBases.delete(mergeBases.keys().next().value as string);
114 }
115
116 /** How many merge bases are held now, for tests. */
117 export function mergeBaseCount(): number {
118 return mergeBases.size;
119 }
120
121 function deepFreeze(diff: Diff): Diff {
122 for (const file of diff.files) {
123 for (const hunk of file.hunks) {
124 for (const line of hunk.lines) Object.freeze(line);
125 Object.freeze(hunk.lines);
126 Object.freeze(hunk);
127 }
128 Object.freeze(file.hunks);
129 Object.freeze(file);
130 }
131 Object.freeze(diff.files);
132 return Object.freeze(diff);
133 }
src/git/diff.ts +20 −1
@@ -6,6 +6,7 @@
66 */
77
88 import { err, ok, type Result } from "../kernel/result.ts";
9 import { diffMemoryKey, recalled, remember } from "./diff-memory.ts";
910 import { runGitRaw, type GitFailure } from "./env.ts";
1011 import { isSafeOid, isSafeRef } from "./guard.ts";
1112
@@ -77,9 +78,27 @@ export async function diffRange(
7778 ): Promise<Result<Diff, GitFailure | "unsafe_rev">> {
7879 if (!safeRange(base, head)) return err("unsafe_rev");
7980 // `git diff A B` compares two tree-ish and needs no work tree.
80 return runDiff(dir, ["diff", ...DIFF_FLAGS, base, head, "--"], laps);
81 const run = () => runDiff(dir, ["diff", ...DIFF_FLAGS, base, head, "--"], laps);
82 // A ref can move; two object ids cannot, so only their diff is remembered.
83 if (!isSafeOid(base) || !isSafeOid(head)) return run();
84 const key = diffMemoryKey(dir, base, head);
85 const known = recalled(key);
86 if (known !== undefined) return ok(known);
87 // Readers arriving while git runs wait for that run rather than start one.
88 const pending = running.get(key);
89 if (pending !== undefined) return pending;
90 const started = run().then((result) => (result.ok ? ok(remember(key, result.value)) : result));
91 running.set(key, started);
92 try {
93 return await started;
94 } finally {
95 running.delete(key);
96 }
8197 }
8298
99 /** Range diffs git is producing right now, by memory key. */
100 const running = new Map<string, Promise<Result<Diff, GitFailure>>>();
101
83102 /** Diff a commit against its first parent (or the empty tree for a root). */
84103 export async function diffCommit(
85104 dir: string,
src/git/merge.ts +9 −1
@@ -6,6 +6,7 @@
66 */
77
88 import { err, ok, type Result } from "../kernel/result.ts";
9 import { diffMemoryKey, recalledBase, rememberBase } from "./diff-memory.ts";
910 import { runGit, runGitCapture } from "./env.ts";
1011 import { isSafeOid, isSafeRef, isSafeTreePath } from "./guard.ts";
1112
@@ -295,8 +296,15 @@ export async function mergeBase(
295296 b: string,
296297 ): Promise<string | undefined> {
297298 if (!isSafeOid(a) || !isSafeOid(b)) return undefined;
299 // Two commits' merge base never changes: the next asker reads it from memory.
outdated

Use diffMemoryKey here, or move this memory into diff-memory.ts. Add a test for the 4096 bound and the LRU order, which has none.

300 const key = diffMemoryKey(dir, a, b);
301 const known = recalledBase(key);
302 if (known !== undefined) return known;
298303 const result = await runGit(["merge-base", a, b], { cwd: dir });
299 return result.ok ? result.value.trim() : undefined;
304 if (!result.ok) return undefined;
305 const base = result.value.trim();
306 rememberBase(key, base);
307 return base;
300308 }
301309
302310 /**
src/http/api.ts +6 −5
@@ -257,7 +257,7 @@ import { carriedBy } from "../core/carried.ts";
257257 import { readGateLog } from "../checks/gate_log.ts";
258258 import { recentGates } from "../checks/gate_result.ts";
259259 import { readRunLog, subscribeRunLog } from "../runs/log.ts";
260 import { blobForRender, commitLog, listRefs, listTree } from "../git/read.ts";
260 import { blobForRender, commitLog, listRefs, listTree, refTip } from "../git/read.ts";
261261 import { repoDir } from "../git/repos.ts";
262262 import { carriedPulls, pullPath } from "../story/wave_pulls.ts";
263263 import { pullRefs, readWave, readWaves } from "../story/waves.ts";
@@ -960,6 +960,10 @@ async function pullHeadOid(ctx: Ctx, repo: Repo, pull: Pull): Promise<string> {
960960 return (await resolveOid(await pullDirOf(ctx, repo, pull), ref)) ?? pull.headOid;
961961 }
962962
963 /** A branch's tip from its ref file (no process); git is asked only when that cannot be read. */
964 const baseTip = async (dir: string, ref: string): Promise<string | undefined> =>
965 (await refTip(dir, ref)) ?? (await resolveOid(dir, ref));
966
963967 /** Where a pull's objects are (`pullDir`): its base, or a sealed one's own place. */
964968 const pullDirOf = (ctx: Ctx, repo: Repo, pull: Pull): Promise<string> =>
965969 pullDir(ctx.app.db, ctx.app.reposRoot, repo, pull);
@@ -2400,10 +2404,7 @@ export function apiRoutes(router: Router<Handler>): void {
24002404 live &&
24012405 checkStale(
24022406 checkSummary(ctx.app.db, found.pull.id, status.headOid).run,
2403 await resolveOid(
2404 await pullDirOf(ctx, found.repo, found.pull),
2405 `refs/heads/${found.pull.baseBranch}`,
2406 ),
2407 await baseTip(await pullDirOf(ctx, found.repo, found.pull), `refs/heads/${found.pull.baseBranch}`),
24072408 ),
24082409 );
24092410 return timePhase(ctx.request, "render", () => {
test/diff-memory.test.ts added +216
@@ -0,0 +1,216 @@
1 /** A second read of the same two commits is served from memory, never git (#8160). */
2 import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
3 import { mkdir, mkdtemp, rename, rm } from "node:fs/promises";
4 import { tmpdir } from "node:os";
5 import { join } from "node:path";
6 import { diffRange, type Diff } from "../src/git/diff.ts";
7 import {
8 diffMemoryCounts,
9 diffMemoryKey,
10 forgetDiffs,
11 MAX_BYTES,
12 MAX_DIFF_BYTES,
13 MERGE_BASES_KEPT,
14 mergeBaseCount,
15 recalled,
16 recalledBase,
17 remember,
18 rememberBase,
19 sizeOfDiff,
20 } from "../src/git/diff-memory.ts";
21 import { mergeBase } from "../src/git/merge.ts";
22 import { initBareRepo } from "../src/git/repos.ts";
23 import { unwrap } from "../src/kernel/result.ts";
24 import { gitClientEnv } from "./helpers/git-client.ts";
25
26 const env = gitClientEnv({
27 GIT_AUTHOR_NAME: "D",
28 GIT_AUTHOR_EMAIL: "[email protected]",
29 GIT_COMMITTER_NAME: "D",
30 GIT_COMMITTER_EMAIL: "[email protected]",
31 });
32
33 async function sh(args: string[], cwd: string): Promise<string> {
34 const p = Bun.spawn(args, { cwd, env, stdout: "pipe", stderr: "pipe" });
35 const [out, errText, code] = await Promise.all([
36 new Response(p.stdout).text(),
37 new Response(p.stderr).text(),
38 p.exited,
39 ]);
40 if (code !== 0) throw new Error(`${args.join(" ")}: ${errText}`);
41 return out.trim();
42 }
43
44 let root: string;
45 let dir: string;
46 let first: string;
47 let second: string;
48
49 beforeAll(async () => {
50 root = await mkdtemp(join(tmpdir(), "forge-diff-memory-"));
51 dir = join(root, "repo.git");
52 unwrap(await initBareRepo(dir));
53 const work = join(root, "work");
54 await sh(["git", "clone", dir, work], root);
55 await Bun.write(join(work, "a.txt"), "one\ntwo\n");
56 await sh(["git", "add", "."], work);
57 await sh(["git", "commit", "-m", "first"], work);
58 first = await sh(["git", "rev-parse", "HEAD"], work);
59 await Bun.write(join(work, "a.txt"), "one\nTWO\nthree\n");
60 await sh(["git", "commit", "-am", "second"], work);
61 second = await sh(["git", "rev-parse", "HEAD"], work);
62 await sh(["git", "push", "origin", "HEAD:refs/heads/main"], work);
63 });
64
65 afterAll(async () => {
66 await rm(root, { recursive: true, force: true });
67 });
68
69 beforeEach(() => {
70 forgetDiffs();
71 });
72
73 /** Swap the repository for an empty directory: any git run inside it then fails. */
74 async function withoutRepo<T>(work: () => Promise<T>): Promise<T> {
75 const away = `${dir}.away`;
76 await rename(dir, away);
77 await mkdir(dir);
78 try {
79 return await work();
80 } finally {
81 await rm(dir, { recursive: true });
82 await rename(away, dir);
83 }
84 }
85
86 describe("diffRange between two oids", () => {
87 test("the second read of the same pair runs no git", async () => {
88 const once = unwrap(await diffRange(dir, first, second));
89 expect(once.additions).toBe(2);
90 const again = await withoutRepo(() => diffRange(dir, first, second));
91 expect(again.ok).toBe(true);
92 expect(again.ok && again.value).toBe(once);
93 });
94
95 test("readers share one frozen value no one can change", async () => {
96 const diff = unwrap(await diffRange(dir, first, second));
97 expect(Object.isFrozen(diff)).toBe(true);
98 expect(() => (diff.files as unknown[]).push({})).toThrow();
99 expect(() => {
100 (diff.files[0]!.hunks[0]!.lines[0] as { content: string }).content = "changed";
101 }).toThrow();
102 const again = unwrap(await diffRange(dir, first, second));
103 expect(again.files[0]!.hunks[0]!.lines[0]!.content).toBe("one");
104 });
105
106 test("a failed run is not kept: the next call asks git again", async () => {
107 const failed = await withoutRepo(() => diffRange(dir, first, second));
108 expect(failed.ok).toBe(false);
109 expect(diffMemoryCounts().entries).toBe(0);
110 const retried = await diffRange(dir, first, second);
111 expect(retried.ok).toBe(true);
112 });
113
114 test("a ref can move, so a range naming one is never kept", async () => {
115 unwrap(await diffRange(dir, first, "main"));
116 expect(diffMemoryCounts().entries).toBe(0);
117 const later = await withoutRepo(() => diffRange(dir, first, "main"));
118 expect(later.ok).toBe(false);
119 });
120
121 test("the memory is per repository, whatever oids a reader names", async () => {
122 unwrap(await diffRange(dir, first, second));
123 const other = join(root, "other.git");
124 await mkdir(other, { recursive: true });
125 const elsewhere = await diffRange(other, first, second);
126 expect(elsewhere.ok).toBe(false);
127 });
128
129 test("readers arriving together share one run", async () => {
130 const [a, b] = await Promise.all([diffRange(dir, first, second), diffRange(dir, first, second)]);
131 expect(a.ok && b.ok && a.value === b.value).toBe(true);
132 });
133 });
134
135 describe("mergeBase", () => {
136 test("the second lookup of the same pair runs no git", async () => {
137 const once = await mergeBase(dir, first, second);
138 expect(once).toBe(first);
139 expect(await withoutRepo(() => mergeBase(dir, first, second))).toBe(first);
140 });
141
142 test("a failed lookup is asked again", async () => {
143 expect(await withoutRepo(() => mergeBase(dir, first, second))).toBeUndefined();
144 expect(await mergeBase(dir, first, second)).toBe(first);
145 });
146
147 test("holds at most MERGE_BASES_KEPT, the least recently used out first", () => {
148 for (let i = 0; i < MERGE_BASES_KEPT + 2; i++) {
149 rememberBase(diffMemoryKey("d", `a${i}`, "b"), `base${i}`);
150 // Reading the first keeps it the most recently used.
151 recalledBase(diffMemoryKey("d", "a0", "b"));
152 }
153 expect(mergeBaseCount()).toBe(MERGE_BASES_KEPT);
154 expect(recalledBase(diffMemoryKey("d", "a0", "b"))).toBe("base0");
155 expect(recalledBase(diffMemoryKey("d", "a1", "b"))).toBeUndefined();
156 expect(recalledBase(diffMemoryKey("d", "a2", "b"))).toBeUndefined();
157 expect(recalledBase(diffMemoryKey("d", "a3", "b"))).toBe("base3");
158 expect(recalledBase(diffMemoryKey("d", `a${MERGE_BASES_KEPT + 1}`, "b"))).toBe(`base${MERGE_BASES_KEPT + 1}`);
159 });
160 });
161
162 describe("the byte bound", () => {
163 const diffOf = (chars: number): Diff => ({
164 additions: 1,
165 deletions: 0,
166 files: [
167 {
168 status: "added",
169 oldPath: null,
170 newPath: "f",
171 path: "f",
172 binary: false,
173 additions: 1,
174 deletions: 0,
175 similarity: null,
176 hunks: [
177 {
178 oldStart: 0,
179 oldLines: 0,
180 newStart: 1,
181 newLines: 1,
182 section: "",
183 lines: [{ kind: "add", oldNumber: null, newNumber: 1, content: "x".repeat(chars), noNewline: false }],
184 },
185 ],
186 },
187 ],
188 });
189
190 test("holds under the total, the least recently used out first", () => {
191 const each = sizeOfDiff(diffOf(1024 * 1024));
192 const fits = Math.floor(MAX_BYTES / each);
193 for (let i = 0; i < fits + 3; i++) {
194 remember(diffMemoryKey("d", `a${i}`, "b"), diffOf(1024 * 1024));
195 // Reading the first keeps it the most recently used.
196 recalled(diffMemoryKey("d", "a0", "b"));
197 }
198 const counts = diffMemoryCounts();
199 expect(counts.bytes).toBeLessThanOrEqual(MAX_BYTES);
200 expect(counts.entries).toBe(fits);
201 expect(recalled(diffMemoryKey("d", "a0", "b"))).toBeDefined();
202 expect(recalled(diffMemoryKey("d", "a1", "b"))).toBeUndefined();
203 expect(recalled(diffMemoryKey("d", `a${fits + 2}`, "b"))).toBeDefined();
204 });
205
206 test("one diff over the cap is served but evicts nothing", () => {
207 remember(diffMemoryKey("d", "small", "b"), diffOf(10));
208 const huge = diffOf(MAX_DIFF_BYTES);
209 expect(sizeOfDiff(huge)).toBeGreaterThan(MAX_DIFF_BYTES);
210 const served = remember(diffMemoryKey("d", "huge", "b"), huge);
211 expect(served.files[0]!.hunks[0]!.lines[0]!.content.length).toBe(MAX_DIFF_BYTES);
212 expect(recalled(diffMemoryKey("d", "huge", "b"))).toBeUndefined();
213 expect(recalled(diffMemoryKey("d", "small", "b"))).toBeDefined();
214 expect(diffMemoryCounts().entries).toBe(1);
215 });
216 });
test/pull-diff-memory.test.ts added +101
@@ -0,0 +1,101 @@
1 /** A second read of an unmoved pull, through `pullDiff` and the API, runs no git (#8160). */
2 import { afterAll, afterEach, beforeAll, beforeEach, expect, spyOn, test } from "bun:test";
3 import { mkdtemp, rm } from "node:fs/promises";
4 import { tmpdir } from "node:os";
5 import { join } from "node:path";
6 import { createApp, type App } from "../src/app.ts";
7 import { openPull } from "../src/actions/pulls.ts";
8 import { commitToBranch, createRepo } from "../src/actions/repos.ts";
9 import { getPull, pullDiff } from "../src/core/pulls.ts";
10 import { createUser } from "../src/core/users.ts";
11 import { forgetDiffs } from "../src/git/diff-memory.ts";
12 import { repoDir } from "../src/git/repos.ts";
13 import { serve, type Servers } from "../src/http/server.ts";
14 import { quietLogs } from "./helpers/globals.ts";
15
16 quietLogs();
17
18 let dataDir: string;
19 let app: App;
20 let servers: Servers;
21 let dir: string;
22 let repoId = "";
23 let number = 0;
24 const cells = process.env["FORGE_CELLS"];
25
26 beforeAll(async () => {
27 process.env["FORGE_CELLS"] = "off";
28 dataDir = await mkdtemp(join(tmpdir(), "forge-pull-diff-memory-"));
29 app = createApp({ dataDir, port: 0 });
30 servers = await serve(app);
31 const made = await createUser(app.db, {
32 origin: "seed", trusted: true, username: "alice", email: "[email protected]",
33 password: "a-good-passphrase", adminIfFirst: true,
34 });
35 if (!made.ok) throw new Error(String(made.error));
36 const alice = made.value;
37 const repo = await createRepo(app, alice, { name: "r", visibility: "public" });
38 if (!repo.ok) throw new Error(String(repo.error));
39 repoId = repo.value.id;
40 dir = repoDir(app.reposRoot, "alice", "r");
41 const commit = (path: string, content: string, branch?: string) =>
42 commitToBranch(app, alice, repo.value, {
43 ...(branch === undefined ? {} : { branch }),
44 message: "change",
45 files: [{ path, content }],
46 });
47 for (const done of [await commit("a.txt", "one\n"), await commit("b.txt", "two\n", "topic")])
48 if (!done.ok) throw new Error(JSON.stringify(done.error));
49 const pull = await openPull(app, alice, repo.value, { title: "t", body: "", baseBranch: "main", headBranch: "topic" });
50 if (!pull.ok) throw new Error(JSON.stringify(pull.error));
51 number = pull.value.number;
52 });
53
54 let spawned: string[][] = [];
55 let spy: ReturnType<typeof spyOn> | undefined;
56
57 beforeEach(() => {
58 forgetDiffs();
59 spawned = [];
60 const real = Bun.spawn;
61 spy = spyOn(Bun, "spawn").mockImplementation(((cmd: string[], options?: { cwd?: string }) => {
62 if (cmd[0] === "git" && options?.cwd === dir) spawned.push(cmd.slice(1));
63 return real(cmd, options as Parameters<typeof Bun.spawn>[1]);
64 }) as typeof Bun.spawn);
65 });
66
67 afterEach(() => spy?.mockRestore());
68
69 afterAll(async () => {
70 await servers.stop();
71 app.close();
72 if (cells === undefined) delete process.env["FORGE_CELLS"];
73 else process.env["FORGE_CELLS"] = cells;
74 await rm(dataDir, { recursive: true, force: true });
75 });
76
77 test("pullDiff reads git once, then answers the same tips from memory", async () => {
78 const pull = getPull(app.db, repoId, number)!;
79 const first = await pullDiff(dir, pull);
80 expect(first.diff.files.map((f) => f.path)).toEqual(["b.txt"]);
81 expect(spawned.some((args) => args[0] === "diff")).toBe(true);
82 spawned = [];
83 const again = await pullDiff(dir, pull);
84 expect(again.diff).toBe(first.diff);
85 expect(spawned).toEqual([]);
86 });
87
88 test("the API's second read of an unmoved pull spawns no git in its diff phase", async () => {
89 const url = `${servers.url}/api/v1/repos/alice/r/pulls/${number}`;
90 const first = await fetch(url);
91 expect(first.status).toBe(200);
92 expect(((await first.json()) as { diff: { files: unknown[] } }).diff.files).toHaveLength(1);
93 expect(spawned.length).toBeGreaterThan(0);
94 spawned = [];
95 const again = await fetch(url);
96 expect(again.status).toBe(200);
97 expect(((await again.json()) as { diff: { files: unknown[] } }).diff.files).toHaveLength(1);
98 expect(spawned).toEqual([]);
99 const timing = again.headers.get("server-timing") ?? "";
100 expect(timing).toContain("diff;dur=");
101 });
test/pull-files-stretches.test.ts +4
@@ -8,6 +8,7 @@ import { addReview, openPull } from "../src/actions/pulls.ts";
88 import { commitToBranch, createRepo } from "../src/actions/repos.ts";
99 import { createUser } from "../src/core/users.ts";
1010 import { serve, type Servers } from "../src/http/server.ts";
11 import { forgetDiffs } from "../src/git/diff-memory.ts";
1112 import { clearDiffCache } from "../src/web/diff-cache.ts";
1213 import { clearHeadReads } from "../src/web/head-reads.ts";
1314 import { quietLogs } from "./helpers/globals.ts";
@@ -71,7 +72,10 @@ const phase = (header: string, name: string) => {
7172 };
7273
7374 test("a 3,000-line, 20-file diff names its stretches cold and draws under 30 ms warm, comments on their lines", async () => {
75 // Cold means nothing remembered anywhere: the page's cache, and git's own
76 // memory of the pair and its merge base, which opening the pull filled.
7477 clearDiffCache();
78 forgetDiffs();
7579 clearHeadReads();
7680 const first = await fetch(url);
7781 await first.arrayBuffer();

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs