fix(sync): stop directory cache thrashing when a project is expanded
Expanding a project with more worktrees and sessions than MAX_DIR_STORES put the sidebar into an endless request loop (#1472). Every sidebar row calls ensureChild during render, but the pin that protects the directory is only taken in an effect after commit. ensureChild marked the directory and ran eviction synchronously, so directories that were actively rendering looked unpinned and were disposed. The next render recreated them with a loading status, which issued another bootstrap request, and the cycle repeated for as long as the project stayed expanded. Raising the limit only moves the cliff, so the limit is now a soft target instead: a directory touched within a grace window is never an overflow victim. A burst of live directories overflows the cache briefly rather than thrashing, while idle-time eviction still bounds it. Eviction is also coalesced into one deferred pass per tick, so a render that mounts many rows no longer sorts and scans every directory once per row, and a whole commit's pin effects settle before anything is considered for disposal. Releasing the final consumer stays synchronous, since that is an explicit lifecycle edge. The idle profiler gains --expand-projects to reach this state. Not yet verified end to end: reproducing the loop needs many worktrees under one project, which this development environment does not have.
This commit is contained in:
@@ -42,6 +42,9 @@ Options:
|
||||
--then-tab <name> After settling, navigate to this tab without a
|
||||
reload, then record. Use it to measure what a
|
||||
surface keeps doing after the user leaves it.
|
||||
--expand-projects Expand every project in the sidebar before
|
||||
recording, which mounts a row per worktree and
|
||||
session directory
|
||||
--panel <mode[=target]> Open the context panel on this surface before
|
||||
recording (chat, preview, terminal, git, pr, notes,
|
||||
file, diff, plan, context, browser, walkthrough).
|
||||
@@ -70,6 +73,7 @@ const parseArgs = (argv) => {
|
||||
tab: null,
|
||||
thenTab: null,
|
||||
panels: [],
|
||||
expandProjects: false,
|
||||
duration: 30,
|
||||
settle: 15,
|
||||
output: null,
|
||||
@@ -94,6 +98,7 @@ const parseArgs = (argv) => {
|
||||
else if (value === "--tab") options.tab = argv[++index]
|
||||
else if (value === "--then-tab") options.thenTab = argv[++index]
|
||||
else if (value === "--panel") options.panels.push(argv[++index])
|
||||
else if (value === "--expand-projects") options.expandProjects = true
|
||||
else if (value === "--label") options.label = argv[++index]
|
||||
else if (value === "--duration") options.duration = Number(argv[++index])
|
||||
else if (value === "--settle") options.settle = Number(argv[++index])
|
||||
@@ -351,8 +356,16 @@ const main = async () => {
|
||||
await client.send("Page.navigate", { url: options.url })
|
||||
await loaded
|
||||
|
||||
if (options.panels.length > 0) {
|
||||
await seedContextPanel(client, options.panels, options.session)
|
||||
if (options.expandProjects) {
|
||||
// The sidebar persists the ids of collapsed projects, so an empty list
|
||||
// expands everything. This is the state in issue #1472: one mounted
|
||||
// directory-bound row per worktree and session.
|
||||
await evaluateValue(client, `localStorage.setItem("oc.sessions.projectCollapse", "[]")`)
|
||||
console.log("Expanded every project in the sidebar.")
|
||||
}
|
||||
|
||||
if (options.panels.length > 0 || options.expandProjects) {
|
||||
if (options.panels.length > 0) await seedContextPanel(client, options.panels, options.session)
|
||||
const reloaded = client.once("Page.loadEventFired", 60_000)
|
||||
await client.send("Page.reload", { ignoreCache: false })
|
||||
await reloaded
|
||||
|
||||
Reference in New Issue
Block a user