Repository navigation
Conversation
…s block A commit that only a branch's `__manifest` buffers was found by listing every live branch ref and checking out branch manifests one after another, on every lookup, and a diff side or a commit's own changes looks the same commit up two or three times. A graph handle's history cache now remembers, per history block, the branch a lookup found a buffered commit on, and the coordinator asks that branch first: one `__manifest` open and one branch scan. The hint only chooses where to look; a branch that no longer holds the commit drops it and the lookup runs as before.
|
Revise this change before merge. Why. A by-id read that misses the current branch scans every live What. The handle remembers the native branch where it last found a commit of a history block. The next read of a commit in that block opens that branch first. Then it reads How. Impact. The second and later commits of a known block open one branch and scan one branch. The first lookup of a block still scans every live branch. Issue 972 stays open. On the current code a warm handle can also fail a read that Blocking1. A missing branch tree stops the lookup
Branch delete copies the commits that branch wrote into The next The new cost test does not catch this. After delete, checkout of the retired tree still succeeds. The test says the commit is found in Fix the miss in Add a regression in 2. The merge into current main does not compileCI run 40477076158 is a Lint, Test Workspace, and Storage Upgrade fail with Azurite fails the same way in CI Gate fails because those jobs fail. Main push run 40440899362 at
Optional
The hint is read against the current root, so it does not return stale commit bytes. After the Tradeoff and liabilityThe change removes a scan of every live branch on the second and later commits of a block this handle already found. That matches a history walk on one branch. The first lookup of a block still scans every live branch. This pull request does not close issue 972. A durable commit-to-branch address remains the general fix. No other open pull request owns this lookup. Pull request 818 caches a different fact, the version a write committed. The change adds a process-local hint. The hint is not a second source of truth when a miss continues into
Reading the branch buffer before A fork stored as the home of a block the writer later extends causes one miss and then a full scan. The result stays correct. ValidationReviewed head Same command on both commits, from isolated checkouts, with The third name is a temporary test. It is not in the pull request. I removed it after the runs. Head result. The cost test passed. The neighbor test Merge-base result. The temporary test passed. The cost test failed with The scan count is the performance difference. The lost read after tree removal is the behavior regression. It fails on the head and passes on the merge base. CI run 40477076158 on merge Lance inspection. LimitationsI did not rerun workspace clippy, the full workspace test graph, GQT, or DST on this machine. I did not measure hosted-graph wall time. The local proof is the open count and the scan count. The local tree removal was Temporary edits were restored. I did not push. Recommendation: revise. Inline comment,
Branch delete leaves the tree. Cleanup later removes Treat Local proof on Inline comment, This unboxed async read is inlined into callers that already meet the compiler depth limit. CI run 40477076158 builds merge Box the await the way |
ragnorc
left a comment
There was a problem hiding this comment.
Review of head b5916cbc (base da1c4636; main has moved on).
Why, what, how, impact
- Why: A commit that only a branch's
__manifestholds is found by a scan of every live branch. Tools that read a branch's commits one by one pay that scan on each read (#972). - What: A handle now remembers which branch held a history block's commit. The next lookup for a commit of that block reads that branch first.
- How:
HistoryCache.homesmaps block to branch.ManifestCoordinator::record_in_hinted_branchis tried before__historyinresolve_commitand in the newrecord_held_elsewhere. A miss orRefNotFounddrops the hint. - Impact: The second and later commits of a block cost one open and one scan, not one scan per live branch.
Blocking findings
None. The hint only picks where to look first. The record still comes from a branch's own __manifest, as the scan reads it. Records are immutable by commit id, so answering before __history gives the same record. commit_state still runs the incarnation check after the lookup. I found no input that gives a wrong answer.
Optional findings
- The test does not prove that the hint is dropped (
warm_read_cost.rs, new test). Afterbranch_delete("task")it checks only the result. The commit would also resolve with noforget_block_homecall, because the later steps fall back to__history. Please assert the open and scan counts of that lookup (one wasted open, then__history) and of a second lookup (no wasted open). Add a released or merged case too. The PR text claims these cases but no test covers them. - The hint can flip back and forth. The scan stores a hint, and a miss removes it. If a block has commits both still buffered and already in
__history, alternate lookups of those commits pay one extra open and scan each time. I did not check whether a block can be in that mixed state, so this is unverified. If it cannot happen, a one-line comment saying so would remove the doubt. - Eviction clears all hints. At 4,096 blocks,
remember_block_homeclears the whole map. A workload that cycles through more than 4,096 blocks then gets no benefit and does extra work. This is probably rare. A bound that evicts one entry, or a comment that names the assumption, would be safer. - A hint error fails the lookup. An error other than
RefNotFound(for example a storage error oncheckout_branch) returnsErrbefore__historyis tried. The old order could have answered from__history. The scan already behaves this way, so this is consistent. Still, the PR text says "the hint only chooses where to look first". Treating a hint error as a miss would match that text. Hiding storage errors has a cost too, so I leave this to you. - The test hard-codes
(1, 6)scan counts. They depend on scan order (own branch, main, newest branch first). The neighbouring lookup-order test has the same coupling, so this is acceptable. Keep the two tests in step if the order changes.
Tradeoffs and software liability
- Added: one cache field with a manual size bound, three small methods, one read-only coordinator surface, and one more step in the lookup order. About 190 lines in total, most of them the test.
- Removed: nothing. This is a cache on top of a scan that stays. Five similar changes would give five hints with five invalidation rules.
- Better owner: #972's durable address removes the scan and the hint together. This PR is a stop-gap with a clear exit, and the PR text says so. I accept it on that basis. Please link the removal to #972 in the code comment.
- Single source of truth:
homescopies facts that live in branch__manifestfiles. It cannot hold a wrong record, because the record is always re-read. It can only cost an extra read. - Future direction: I did not see a conflict with the open RFC PRs that touch history or branch bases. #1235 and #1234 change how branch bases follow a copied root. The hint stores native branch names, not paths, so I expect it to survive them. This is unverified.
Validation
- Local, new test on the PR head
b5916cbc:CARGO_TARGET_DIR=<shared target> RUST_MIN_STACK=16777216 cargo test -p omnigraph-engine --test integration by_id_read_of_a_block_found_beforepassed (1 passed, 641 filtered out). - Local, same test before the fix: I restored the production files of
crates/omnigraph-catalogandcrates/omnigraph/srcto baseda1c4636and kept the PR's test. It failed atwarm_read_cost.rs:2443withleft: (1, 6),right: (1, 1). The cause is the predicted one: the second lookup scanned all six branches. I restored all edits afterwards. - Local, neighbouring test on the PR head:
by_id_read_of_a_commit_held_elsewhere_scans_the_likely_branches_firstpassed. - GQT: The contract is storage I/O counts, which GQT cannot express.
warm_read_cost.rsis the right owner, so I asked for no GQT case. - CI: The run on this head has red checks (
Lint (clippy),Test Workspace,Storage Upgrade Compatibility,Azurite,CI Gate). The logs I read showqueries overflow the depth limitwhile compilingomnigraph-bench, which this diff does not touch. The run dates from 2026-10-27, and the branch is behindmain. Please rebase and rerun before merge. I did not run the full suite, clippy or GQT locally. - Not verified: the 13–14 s to 1 scan improvement on a hosted graph. The PR states it was not measured there, and I did not measure it either.
Part of #972. A commit that only a branch's
__manifestbuffers (every commit of an unmerged branch) was found by listing every live branch ref and checking out branch manifests one after another, newest first, on every lookup. A diff side spelled as such a commit looks it up twice, and a commit's own changes up to three times. On a hosted graph with nine live branches,GET /commits/{id}/changeson a one-change branch commit took 13–14 s and a diff of a branch head against itself 13.6 s (measurements in the #972 comment). OmniGraph Studio reads a branch's commits one after another for history and review, so it pays this on every read.A graph handle's
HistoryCachenow remembers, per history block, the branch a lookup found a buffered commit on. One native branch writes a block, so the block's other commits stay buffered there until they are released or merged.resolve_commit,commit_stateandpublished_recordask that branch first, before__historyand the scan of every live branch: one__manifestopen and one branch scan. The guard is that the hint only chooses where to look first. The record still comes from that branch's own__manifest, read the way the scan reads it. A branch that no longer holds the commit, whether released, merged, deleted or recreated under a new native name, drops the hint and the lookup runs as before. The incarnation check that answers 404 for a deleted branch's commit is unchanged. The cache holds at most 4,096 block names per handle, and the newManifestCoordinator::record_in_hinted_branchis registered as a read-only coordinator surface.warm_read_cost::by_id_read_of_a_block_found_before_scans_only_its_branchreads two commits of one block from a handle onmainwith four newer branches. The first lookup scans six branches and the second one; with the hint disabled the second also scans six. The graph as of the hint-found commit reads its rows correctly, and after the branch is deleted the commit still resolves through__history. The neighbouring lookup-order test keeps its counts. The catalog and engine suites pass with the 16 MiB stack CI sets (composite_flow_multi_branch_sequential_mergesoverflows the default debug stack onmainas well), and clippy passes on the pinned 1.97.1 toolchain.For review: the decision to challenge is answering from the hinted branch's copy of a record before
__history. The scan already returns whichever branch holds the commit first, in an order that depends on the handle's own branch, so this relies on nothing the scan did not already rely on. The first lookup of each block still scans every branch; #972's durable address is the fix for that, and this PR leaves it open. I could not run the GQT corpus locally: on this machine under load, every debug case that failed exceeded its 10 s wall-time budget, none with an assertion failure, and one that timed out under load (branch_create_at_a_commit) passed in 8 s alone; CI's GQT job is the check for the corpus. Not measured on the hosted graph.