ContractTrunkPreloadParallel classifies each frontier entry per Run call by looking it up in the dbBranches overlay it was handed (sortAndPartitionFrontier). Entries not found there become file misses and go to the batch resolver.
A pathKey that was a db-hit on one Run but got deferred into p.frontier by the budget carries no record of that. On a later Run the caller supplies a fresh overlay, and if the key is no longer in it and the file layer also lacks it (it existed only in the overlay), resolve() returns nil and the v == nil { continue } path drops it silently — indistinguishable from a genuine BFS-fringe absence, where a set afterMap bit names a leaf with no branch record.
The entry is skipped and its children are never queued, so the preload under-pins that subtree.
Impact is performance, not correctness. A missing pin is a BranchCache miss, and commitment falls back to reading the entry from the db/file layer as it would without any preload at all. No wrong data, no wrong root.
Why it matters now. AdaptivePinController.runExtensionLocked keeps one preload instance alive across blocks and calls it with a fresh overlay each time, so budget-deferred waves resuming into a rotated overlay is the normal path. Before #23066 such a wave either hung or drained within a single Run, so this was largely unreachable in practice.
Reported by @awskii in review of #23066 and deliberately left out of that PR, which is a livelock fix.
No test covers a db-hit surviving a deferral into a Run whose overlay no longer contains it — worth adding alongside whatever fix lands.
ContractTrunkPreloadParallelclassifies each frontier entry perRuncall by looking it up in thedbBranchesoverlay it was handed (sortAndPartitionFrontier). Entries not found there become file misses and go to the batch resolver.A
pathKeythat was a db-hit on oneRunbut got deferred intop.frontierby the budget carries no record of that. On a laterRunthe caller supplies a fresh overlay, and if the key is no longer in it and the file layer also lacks it (it existed only in the overlay),resolve()returns nil and thev == nil { continue }path drops it silently — indistinguishable from a genuine BFS-fringe absence, where a setafterMapbit names a leaf with no branch record.The entry is skipped and its children are never queued, so the preload under-pins that subtree.
Impact is performance, not correctness. A missing pin is a
BranchCachemiss, and commitment falls back to reading the entry from the db/file layer as it would without any preload at all. No wrong data, no wrong root.Why it matters now.
AdaptivePinController.runExtensionLockedkeeps one preload instance alive across blocks and calls it with a fresh overlay each time, so budget-deferred waves resuming into a rotated overlay is the normal path. Before #23066 such a wave either hung or drained within a singleRun, so this was largely unreachable in practice.Reported by @awskii in review of #23066 and deliberately left out of that PR, which is a livelock fix.
No test covers a db-hit surviving a deferral into a
Runwhose overlay no longer contains it — worth adding alongside whatever fix lands.