jobs/cache: a joined check reads the database again every 20 s though nothing was stored under its keys (5,700 looks a second, 70 ms permit wait for every cache read) #57
Closed
opened 2026-11-13 08:16:21 +00:00 by xemmerling
·
0 comments
No Branch/Tag specified
main
dev/schema-step-order
t-join-release
t-work-booking
t-ahead-deadlock-wip
t-hotfix-9ae
t-width-work
t-id-token-renew
t-claim-unkept
t-resume-live
t-run-record
t-all-lockfiles
t-relay-offset
t-blame-event
t-freer-links
t-load-tests
t-jobserver2
t-starved-timeout
t-client-pack
t-offline-config
t-test-plan
t-told-resume2
t-jobserver
t-told-resume
t-outbound2
t-crash-open-bench
t-told-once
guest-never-below-given
admit-page-cache-active
pooled-admission
driver-give-back
no-sizes
one-driver-per-check
archive/vm-root-share
archive/build-out-kept
archive/cargo-perf
archive/virtiofs-readdir-alloc
archive/vm-outputs-stream
archive/stable-verify-priority
archive/agents-1
archive/stack-parallel
archive/cpu-admission
archive/narrow-from-every-log
archive/old-t
archive/worker-store-gc
archive/failing-builds-kept
archive/vm-cargo-home
archive/lifecycle
archive/bench-own-cores
archive/place-test-binaries-nocopy
archive/vm-net-upload-stall
archive/booking-current-use
archive/archive-dep-out-dirs
archive/any-arch-shards
archive/prepare-stall-progress-ns20
archive/s2
archive/next-set-20
archive/store-full-waits
archive/fetch-caps-by-node
archive/vm-step-phases
archive/arm-only-for-arm
archive/deploy-all-workers
archive/lifecycle-staging
archive/lifecycle-1-wire
archive/fast-gate
archive/cargo-key-narrow
archive/log-leads-followup
archive/gate-limit
archive/prepare-stall-vm-bytes
archive/lifecycle-2-ends
archive/cache-hits-bind
archive/failing-reused
archive/oci-archive-direct
archive/prepare-stall-progress
archive/test-quarantine
archive/crash-safe-on-18
archive/build-script-etxtbsy
archive/old-release
archive/next-set-19c
archive/wait-reasons
archive/cache-put-best-effort
archive/hang-not-t-time
archive/shard-test-results
archive/vm-carry-on-17
archive/check-test-filter
archive/artifact-path-beneath
archive/stall-room-xfs
archive/build-dir-no-recopy
archive/cache-hits-link
archive/outputs-no-follow-on-copy
archive/outputs-no-follow
archive/next-set-19
archive/hang-detect
archive/stable-verify-stable-plan
archive/freer-target-only
archive/lease-pricing-narrow
archive/vm-outputs-once
archive/queue-place-starved
archive/publish-reads
archive/disk-warning-scratch
archive/outputs-no-copy
archive/wd-probe-3min
archive/watchdog-on-d65
archive/log-leads-with-excerpt
archive/queue-place
archive/prep-watchdog-progress
archive/cache-put-stack-room
archive/cache-put-stack
archive/place-by-pace
archive/nested-sync-helper
archive/next-set-18y
archive/archive-bins-by-env-19
archive/next-set-18
archive/disk-want-held
archive/young-booking-back
archive/flaky-tests-1027b
archive/next-set-17
archive/prep-start-at-close
archive/unpack-error-on-17
archive/server-memory-high
archive/vm-start-held
archive/vm-carry-on-14
archive/space-trim-registry-room
archive/file-cache-ns16
archive/unpack-error-final
archive/crash-safe-worker
archive/server-space-trim
archive/status-big-runs
archive/nested-tmp-volatile
archive/publish-refresh
archive/gc-cache-quiet-reads
archive/next-set-16
archive/vm14-proof
archive/csw-node-kill
archive/unpack-link
archive/vm-tests-15
archive/seccomp-allow-field
archive/flaky-tests-1027-ns15
archive/shard-fail-fast
archive/server-node-check
archive/live-log-restart
archive/unpack-no-orphans
archive/flaky-tests-1027
archive/fetch-share-images
archive/fetch-images-red4
archive/forget-cached
archive/put-file-once-ns15
archive/recheck-rank-15
archive/fetch-images-red3
archive/unpack-no-orphans-red2
archive/fetch-io-pass-followups
archive/sandbox-no-fallback-ns15
archive/unpack-no-orphans-red
archive/archive-bins-by-env-ns15
archive/ns15-proof
archive/next-set-15
archive/archive-bins-by-env
archive/vm-guest-panic-15
archive/sandbox-no-fallback
archive/recheck-rank
archive/placement-ahead-bound
archive/carry-keeps-listing
archive/registry-parallel-pull
archive/sandbox-tests-15
archive/attempt-log-live-15
archive/follow-progress-16
archive/follow-progress-15
archive/ns15-archive-base
archive/fetch-io-max-on-13
archive/fetch-images-red2
archive/transient-build-fail-15
archive/test-ended-early-15
archive/archive-keep-cleanup
archive/main-merge-14
archive/sandbox-clone3-fallback
archive/vm-carry-on-13
archive/fetch-io-sweep-15
archive/vm-root-disk-fixes
archive/vm-guest-panic
archive/follow-progress-14
archive/archive-keep-on-demand
archive/vm-exit-unseen
archive/file-cache-share
archive/bwrap-root-userns
archive/transient-build-fail
archive/fetch-io-max
archive/file-cache-guard-11
archive/fetch-io-sweep
archive/archive-build-dir-skip
archive/next-set-14
archive/wrapper-one-read
archive/archive-tmp-links
archive/attempt-log-live
archive/fetch-share-and-order
archive/vm-hang-io-wait
archive/vm-carry-fixes
archive/image-cancel
archive/test-ended-early
archive/sim-on-train3-bundle
archive/hits-layer-wip
archive/t-old-putfile
archive/archive-links
archive/stall-on-13
archive/carried-prep-completes
archive/put-file-once
archive/preview-14
archive/follow-progress
archive/gc-reads-dont-protect
archive/admission-replay-people
archive/people-pickup
archive/gc-pass-visible
archive/hits-layer
archive/own-build-priced
archive/compact-stamps-followup
archive/prepare-timing
archive/sim-on-train3
archive/next-set-13
archive/next-set-12b
archive/sim-on-next-set-12
archive/deploy-doc-no-kill
archive/next-set-12
archive/attempt-logs-real
archive/sim-tests-green
archive/shard-label-index
archive/young-booking
archive/next-set-11
archive/data-dir-config-env
archive/vm-sync-not-host-store
archive/attempt-logs
archive/wrapper-ro
archive/tests-wait-on-events
archive/blame-git-optional-needs
archive/job-file-headroom-impl
archive/next-set-10
archive/blame-verdict-fresh-parent
archive/compact-touched-stamps
archive/interactive-incremental-off
archive/follow-lost-lines-counted
archive/evict-test
archive/next-set-trial
archive/keys-cover-output-bytes
archive/file-cache-guard
archive/blame-after-parent
archive/test-filter-matching-nothing-fails
archive/s1-on-d96
archive/draining-node-queues
archive/tprev-checks-prod-next
archive/s1-dead
archive/follow-live-run
archive/guard-stopped-setup-text
archive/io-error-cause
archive/source-layer-whole
archive/clippy-groups
archive/worker-silence-grace
archive/price-touched
archive/prod-next
archive/batch1
archive/s1-on-prod-next
archive/vmcache/sandbox-copyup-pin
archive/s1-xfs-store
archive/warm-script-builds
archive/vmcache/setup-tag-digest
archive/vmcache/setup-should-fixes
archive/vmcache/setup-any-arch
archive/guard-livelock
archive/host-budget
archive/wire-format-test
archive/admission-replay
archive/switch-safe
archive/stall-window
archive/upgrade-carries-preparing
archive/static-init
archive/switch-proof-b
archive/carry-tokens
archive/seals-together
archive/switch-safe-storage
archive/switch-safe-worker
archive/batch-b-prev
archive/vmcache/batch-b
archive/carry-vm-helpers
archive/small-llvm-args-failed-log
archive/batch-a
archive/stall-hotfix
archive/prev-pacing
archive/u-try-wip
archive/u-try
archive/u-try-wip2
archive/flatten-verify
archive/poll-free
archive/flatten-tiers
archive/hotfix-cross
archive/pool-stall
archive/disk-pacing
archive/u-builds-from-graph
archive/mac-idle
archive/ship-direct
archive/vmcache/shards
archive/soft-margin
archive/behind-no-target
archive/filtered-binaries
archive/vmcache/setup-layers
archive/direct-off-prev
archive/probe-budget
archive/vm-helper-exit
archive/jobs-soft-bound
archive/vmcache/vm-disks
archive/vmcache/failure-outputs
archive/narrowed-not-verdict
archive/scratch-direct-off
archive/handover-holds
archive/memory-lines
archive/drain-destroys
archive/pool-size
archive/drain-own-frees
archive/test-schema-drop
archive/deploy-disk
archive/deploy-disk-lines
archive/clone-aware-freeing
archive/absolute-headroom
archive/zfs-pool-size
archive/u-int5
archive/u-load
archive/u-warn
archive/u-steer
archive/revert-stall-once
archive/guard-headroom
archive/u-int3
archive/u-readsets
archive/u-hermetic
archive/mem-virtio
archive/u-buildjobs
archive/u-waits
archive/u-three
archive/u-zfs-stall
archive/u-config
archive/u-lean
archive/u-e2e
archive/u-integrate2
archive/u-jobenv
archive/u-cache-blobs
archive/u-observe2
archive/u-sched-nospread
archive/u-node-bound
archive/u-sched-oom
archive/u-review-store
archive/u-observe
archive/u-review-engine
archive/u-review-srv
archive/u-review-node
archive/u-review-sched
archive/preempt-measured
archive/u-integrate
archive/u-eng
archive/lock-off-runtime
archive/u-vm
archive/u-gone
archive/u-offline
archive/ready-starve
archive/u-notices
archive/heads-never-superseded
archive/u-learn
archive/int
archive/u-graph
archive/u-umount
archive/supersede-followed
archive/preparing-booking
archive/u-xdev
archive/u-env
archive/u-poll
archive/u-wrap
archive/u-room
archive/u-wrap-try
archive/u-fixed
archive/unstall
archive/u-fix3
archive/u-cwd
archive/resume-supersedes
archive/server-heap
archive/u-harness
archive/u-macos
archive/u-node
archive/u-eng2
archive/u-leader
archive/u-cutover
archive/u-cache
archive/u-sched
archive/u-engine
archive/chore/agpl-license
archive/note-x86-disk-room
archive/pass-cost
archive/prod-defects
archive/clippy-false-greens
archive/t-pace-variance-prototype
archive/outputs-reattach
archive/fix-retry-needs
archive/no-supersede-uncached
archive/fix/promoted-view-mtime
archive/rb-merge
archive/ft-sched
archive/ft-node
archive/ft-engine
archive/fx-sim
archive/fx2-mem
archive/fx2-store
archive/fx2-ci
archive/fx-work
archive/fx-ci
archive/fx-sched
archive/fx-req
archive/fx-store
archive/fx-cache
archive/rb-storage
archive/rb-scheduling
archive/rb-sweep
archive/rb-tracking
archive/rb-workers
archive/rb-client
archive/rb-profiles
archive/rebuild
archive/batch-deploy
archive/fix-roll
archive/work
archive/fix-busy
archive/fix-perf
archive/fix-suite
archive/fix-spread
archive/fix-sig
archive/fix-wait
archive/fix-init
archive/sizing
archive/fix-drift
archive/delivery
archive/fix-snap
archive/fix-own
archive/fix-rollout
archive/fix-hang
archive/fix-tree
archive/images
archive/fill
archive/sched-gate-preparing-after
archive/takeover-sim
archive/image-d244b22
archive/image-ce8a09e
archive/image-c9ff4f7
archive/image-489bec9
archive/image-7e07ffb
archive/image-583ea93
archive/image-8e1cd2c
archive/image-fbf0a9c
archive/image-6924e11
archive/image-29cabc3
archive/image-97ebb0e
archive/image-d0e23ac
archive/image-319fce9
archive/image-4f689e1
archive/image-feacbcd
archive/image-d5d9446
archive/image-6b86940
archive/fix/dedup-priority-promotion
archive/image-a5b0fe3
archive/image-462afb1
archive/image-f39d42c
archive/image-6e71fb4
archive/image-0c62329
archive/resources
archive/image-112b6a6
archive/image-8b06530
archive/image-5ae7cd8
archive/fmt-fix-in-t-toml
archive/image-arm64
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
tilo/t#57
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Update 12:09Z 2026-11-13: what
8210a6d7did to the database, an hour on. Its container on production (Prometheus, ten-minute rates):8210a6d7So until 10:57Z the server's every database call ran against a database throttled in two periods of three, and the per-look
kept_understatements were the load. The hour on8210a6d7otherwise: no job ended with a cause, no check told as an error, people's waits 1.2 s median and 3.8 s at the 95th percentile, seven heads judged in the 11:00 hour (one to five an hour before).Update 11:11Z 2026-11-13: the wait change is parked, not landed. In steady state on production (11:04 to 11:06Z on
8210a6d7, against 10:42 to 10:56Z on91b2c84d) there is little left for it to remove:91b2c84d8210a6d7The looks go on, but they cost at most a share of one core and nobody waits behind them. Removing them would take about 180 lines in the claim and lookup paths, new wakes on three write paths, and the end of the 20 s re-ask. That is not worth it now, so it stays off main. It is kept as a commit (4d7e8561 on
8210a6d7, saved as a patch on my side) with a Lean proof of same answers and a test at production size: 150,000 held waits add about 0.1 KB each and make 0 looks across three wakes and three holds, against 558,592 on8210a6d7. Worth picking up if the joined checks grow several times over or the looks show in a profile.What this issue did deliver, on production since 10:57Z: the batched
kept_underread (8210a6d7: permit wait 244 ms to none) and the missed wake's fix (9aa708c9: no more 20 s stalls when a build is handed down its line).Two leftovers found on the way, on main already, neither a hang; noted here for whoever next touches the claims:
firsttrue stays in that line after a later look computesfirstfalse, until its wait ends; a node's compile asking by the first key alone can be toldHeldbehind it;waitingdetects a change of holder overask.all_keys(),wait_holdinglooks the holder up overask.lines(); for an ask by read sets the first key is only in the former, so a holder on the first key can end the wait withWaitwithout the follower callingholding.Update 11:06Z 2026-11-13:
8210a6d7on production took the queue away. First minutes after the 10:57Z promote, with the restart's wave still in them, against 10:23 to 10:43Z on91b2c84d:91b2c84d8210a6d7So the read permits were held by the separate
kept_understatements, not by the looks' batched reads; folding them into the batch removed the wait for every reader. The looks themselves go on at the same rate, cheaply. What the wait change of this issue would still remove is about 1,300 short batched reads a second and the server's work for the looks. Whether that is worth a change of its size in the claim and lookup paths is being judged on the half-hour reading at 11:28Z and its production-size test; it stays off main until then.Update 11:00Z 2026-11-13: main's head
8210a6d7is on production since 10:57Z. That is the missed wake's fix (9aa708c9) and the batched "kept under a first key" read (8210a6d7). Promoted on the usual four conditions, 46 minutes after the 10:09Z promote; take-over clean (404 runs kept their checks in 14 s, no job given up, no statement cancelled, no deadlock). The wait change is c5bfd2a7 on8210a6d7, in its gate on testing, and held off main until a test at production size has run (about 150,000 held waits: bounded memory, no read after the first).Update 10:50Z 2026-11-13:
8210a6d7seen; the wait change is being rebased onto it.8210a6d7reads whether an entry is kept under a first key in the looks' batched read, which removes the second statement per look. The looks themselves remain: on production, 10:23 to 10:43Z, 146,642 checks joined made 7,470 looks a second, a look's keys took 955 ms mean with 707 ms of it waiting for a batched read's turn, and the cache's reads waited 244 ms for a permit. The wait change removes those looks. It conflicts with8210a6d7in src/jobs/cache/lookup.rs only and is being fitted to it with the batched read kept whole. To avoid a second conflict, please say here before changinglook_knowing,waitingorClaims::claimagain.Update 10:41Z 2026-11-13: the missed wake's fix is on main as
9aa708c9. Not on production yet. On testing, alternating pairs ofruns_handed_each_others_builds_finish, forced, the test's own seconds:919b5471and91b2c84d)The whole check set passed on it twice, none cached. The wait change of this issue sits on top of it and is in its own gate now: the handover test thirty times, then the whole set.
Update 10:22Z 2026-11-13: the missed wake is found; it came with
3e412eea.Claims::claimdecides a waiter's answer first and stands it in its lines after. Until3e412eea(2026-11-12, "a run waits in a key's line by its tier and age") a new waiter was pushed to the end of a line, so that order was sound. Since thenlininginserts by place, and a waiter can stand BEFORE the one that was first:Waitbehind a waiter it now stands before, with no holder, and nothing wakes it (liningwakes no one);Behindit in turn, and both wait until one'sproto::HOLDends and its run asks again;That is the 20 s in one of four runs of
runs_handed_each_others_builds_finishon testing, and on production since 2026-11-12 10:17Z a hand-over to an older run can wait up to 20 s with nobody holding the work. Only the server's own waits pass a place (waiting.rs), so nothing else is touched.Fix, being tested on testing now and landing as a commit of its own before the wait change: in
Claims::claima waiter given a place stands in its lines first, andmay_holdis asked again as it stands there; first in every line with no holder, it claims at once. Testa_wait_lining_ahead_of_the_first_in_line_claims_once_no_one_holds: 0.12 s with it, told nothing for 5 s without.Update 10:20Z 2026-11-13: not landed, and it uncovered a missed wake on main. The change (a server's own wait reads the database again only when something was stored under its keys, and holds no 20 s hold) passed two whole check sets on testing, then hung
drivers::cargo::tests::runs_handed_each_others_builds_finishto nextest's 180 s limit: twice in about 41 runs with it. Paired runs of that one test on testing, forced, alternating, the test's own seconds from each log,919b5471as the base:919b5471now + proto::HOLD), and this test's waits begin in its first seconds. A wake missed there is rescued at about 20 s plus those seconds. One base run in four carries that, once or twice.firstflips from true to false between two of its looks (claimlines only the newclaimed,may_holdchecks first-in-line only over it); something moving while a look reads the database;holder(ask.all_keys())inwaitingagainstholder(ask.lines())inwait_holding.The missed wake will be fixed as a commit of its own, with a test that needs no 20 s, before the wait change. If the claims or the joins are being changed elsewhere (
919b5471touched the callers ofwait_holding), say so here.Seen on t.tilo.so on 2026-11-13, on
ebbad1e3and the versions before it (the same on0f37ba87, whose code here is unchanged). A measurement with a proposed cut in the cache's read path. I am commissioning it on my side; say here if the claims are being changed elsewhere.What it costs. Production, 07:40 to 08:00Z (Prometheus, twenty-minute rates):
t_checks_joinedt_cache_key_reads_totalproto::HOLDt_cache_find_totalt_lookup_seconds{part="keys"},keys_turnt_db_read_seconds_count{by="cache"}permit,heldt_db_read_seconds_countSELECT 1 FROM entries WHERE key0 = $1 LIMIT 1three times in nine:kept_under(src/jobs/cache/lookup.rs), which thefirsttest inlook_knowingruns once per look for an ask by every file with no set. Inferred from that sample, not counted.Why.
Follower::wait_holding(src/jobs/flight.rs) loops oncache.wait_told.CacheServer::waiting(src/jobs/cache/waiting.rs) looks once, which reads the keys from the database, then waits forlistening.changed()orproto::HOLDand returnsWait. The follower asks again and the look reads the database again, though nothing was stored under its keys.watchin the same file already skips the read whileclaims.stored_at(keys)stands where its last read left it;waitingdoes not, and what it knew is lost between its calls.Proposed. A server's own wait reads the database when it first asks, and again only once the claims say something was stored under its keys (
Key::storedmoved). Between those it answers from the claims alone. Two shapes, the simpler first:waitingpast the hold, since no HTTP request has to be kept alive, and reads again only on a store;Storedmark back to the follower, which gives it to the next ask of the same keys.What has to hold, to be shown with the change (a Lean proof of same answers, as for every cut in the read path):
put.rsis the one caller ofClaims::storedtoday, and the inserts incollect.rs,retention.rs,misses.rsandknown.rsare to be read;ending,holding,unliningdo);firsttest's inputs change only by a store or a removal, and a removal leaves a wait a wait or turns it into a claim.Expected: looks from 5,700 to tens a second, the cache's reads from 3,250 to a few hundred, the permit wait from 70 ms to about none.
Relay messages to the claims' other author go to an inbox that is offline (no agent of that side was listed online at 08:11Z), so this is filed here.
c6dca088is on main for this (08:40Z 11-14)67588367.I leave this open until the reading after its promote.
On production since 08:57Z: the reading is gone
Thirty-minute rates before the promote of
c6dca088(08:55Z, on67588367) and a twenty-minute window after it without the takeover (09:29Z):Closed: head runs finish on this build (09:38Z 11-14)
The reading this issue was about is gone, and nothing is left waiting by the change. Closing.