Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,33 @@ stalls denies credit, so a queued leaf may fail at one budget, as it did before.
What the credit cannot see is a leaf stuck OUTSIDE every pool while the lanes advance for others. So
the total credit is capped at **four budgets** (`QueueCreditBudgets`); past that, the watchdog fails
as before, and the line names the pools (`IoPoolQueueReport`). Pinned by
`DeleteCommitQueuedBehindAMovingLaneTest`: a leaf queued behind twelve 600 ms writers on a 4 s budget
completes in its turn, and a leaf admitted and hung in its own lane fails inside two budgets while an
`DeleteCommitQueuedBehindAMovingLaneTest`: a leaf queued behind at least nine 600 ms writers that are
at the gate when it asks for its slot (`QueuedAhead` β€” 5.4 s of queue on a 4 s budget) completes in
its turn, and a leaf admitted and hung in its own lane fails inside two budgets while an
unrelated lane keeps advancing. With the stalled-lane condition removed, the second case ran to 27 s.

🚨 **A pool's `Waiting` is not its queue order β€” read `BehindCap` before claiming a leaf is behind
other work.** A pool counts a leaf as waiting from the moment it is ACCEPTED, one ThreadPool hop
before the leaf reaches the gate (`IoPoolAdmission.BeforeGate`), and the gate is first-come-first-served
among the leaves that have REACHED it. The first version of that test loaded the lane with twelve
holders, waited for `CurrentlyWaiting >= 11` and started the delete. Run alone it passed; run with the
whole project in one process (macOS arm64, Release) it failed four runs out of four with
`Expected 00:00:01.8188890 to be greater than 00:00:04`: the delete's leaf reached the gate behind
three of the twelve accepted holders, was served after 3 Γ— 600 ms, and the watchdog was never
involved. The same reading is reproduced with no load at all by parking nine holder prologues before
the gate (`IoPool.OnLeafPrologueStarting`): `11 waiting, 1 in flight` with `before the gate 9, behind
the cap 2`, and the delete returns in 1.9 s. So the test now reads the load where the order is decided
(`BehindCap`), keeps the queue at depth until the delete's leaf asks for its slot, and compares
the budget with the leaf's own wait, measured by the store it queued in β€” never with a wall clock
Comment thread
Copilot marked this conversation as resolved.
started at the request, which also charges the watchdog for every stage before the commit. A
replacement holder is itself only ACCEPTED until it has had a thread, so the queue ahead of the leaf
is pinned rather than hoped for: the instant the leaf asks β€” before the pool has heard of it β€” the
test counts the holders at the gate (all ahead of the leaf by construction) and stops the lane
draining, and it lets the lane move again only when nothing accepted is still before the gate, which
is the leaf having joined the queue behind exactly the holders that were counted. The
product was not at fault here, and the credit's own rule is unaffected: a lane whose work is still
before the gate reads as busy-and-not-advancing, which denies credit β€” the conservative direction.

🚨 **Raising the budget is not a fix for either half** β€” the question is never "how much headroom
does this need", it is "is the bound measuring the right quantity, and does the check look at the
whole subtree".
Expand Down
Loading
Loading