Repository navigation
perf(sessions): avoid idle scans of deferred relation receipts - #4810
Conversation
Probe the indexed next relation recovery deadline before reading the creation-order journal, and detect one extra due receipt so the bounded recovery worker continues without missing backlog. Extend database-backed recovery regressions for deferred idle reads, due-page continuation, and settled quiescence. Refs #4481
|
The shared bounded_query_limit helper already requests one sentinel row for has_more. Do not pad the caller's limit a second time. Refs #4481
The bounded query helper already fetched limit plus one before this PR. Keep the behavior regression and describe what it actually proves. Refs #4481
The one-row recovery pagination regression reused an applied receipt while setting its state to pending. The actual SQLite schema refuses that mixed state unless graph_watermark and applied_at are cleared in the same update. Restore the valid pending transition without weakening the receipt constraint or the two-page recovery and idle-queue assertions. Refs #4481
There was a problem hiding this comment.
Note
Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.
🔍 Devin Review: 1 flag
Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
Repair three hosted automation_runner_test failures by supplying the configured executable identity required by the production prefilter. Use the same identity for the prefilter and retained runner, preserving manual-schedule, exact-ledger, live-lock and lock-race assertions. Add a production-prefilter regression for unconfigured refusal, deduplication and same-occurrence recovery after binding, with zero backend calls and no effectful terminal. Do not relax backend admission, change timeouts, or alter the graph publication changes. Refs #4532
|
Review/ownership blocker before merging this #4481 slice: the PR head advanced from |
A synchronous OnceLock wait inside the asynchronous historical-ingest fixture blocked the worker that must poll live projection concurrently. Use a durable async watch latch to preserve release ordering while exercising the real interleaving and supersession journey. Refs #4481
|
Published |
|
New #4481 performance review blocker (current #4810 head The covering-index WHERE receipt.state = 'pending'
AND receipt.recovery_state IN ('pending', 'retryable')
AND receipt.recovery_next_attempt_at <= unixepoch()
ORDER BY receipt.created_at, receipt.session_id, receipt.generation
LIMIT ?1SQLite chooses Measured reproduction — query-level, not a daemon benchmark or Bazel test: SQLite 3.46.1, in-memory fixture with the repository's actual recovery-due/pending indexes, receipt/journal join and ordered query; 75,000 pending retryable receipts in Forcing Please preserve creation order and the one-sentinel pagination contract while bounding reads for both a sparse due receipt hidden behind deferred work and the all-due catch-up case. Add nonvacuous registered-store behavior and query-step evidence, followed by native daemon measurement. The existing 75k-all-deferred |
Use a bounded creation-order prefix for dense due work and indexed cardinality to choose between deadline and creation order when mixed. Retain due-time consistency and one-row pagination; exercise deferred older receipts with real registered-store recovery. Refs #4481
Replace full-cardinality reads with a deadline-index probe capped at 16,384 entries. Preserve sparse/dense plan selection and cover waking an entire deferred backlog through registered-store recovery. Refs #4481
|
Refs #4481 — published two exact-head, non-force fast-forwards on the existing issue-specific PR: Root cause / source fix. The prior Behavioral regression: the real registered-store test now adds 256 older FK-valid sleeping receipts before two existing due publication receipts. It checks first-page permanent settlement of the older poisoned receipt, second-page recovery, the future retry deadline, then wakes all 256 and checks that the dense creation-ordered path settles the oldest receipt and still advertises the next page. This extends the original malformed-journal/scheduler test; no mocked recovery result. Independent query-level reproduction, not a daemon benchmark or Rust test: SQLite 3.46.1, warmed in-memory 75,000-row schema using the repository's two receipt indexes and the candidate/journal join; 31 iterations per layout, median end-to-end SQL-plan selection and row selection. One due receipt behind 74,999 deferred: 11.86 ms original → 0.029 ms revised. All due: 0.005 → 0.021 ms. A final 20% due: 8.37 → 3.54 ms. A final 40% due: 5.96 → 7.53 ms, a measured intermediate-distribution tradeoff, not grounds to claim universal speedup. All result identities matched the original query. This does not prove macOS daemon CPU or 24-hour store growth. Exact-head Bazel CI 42554361971 is queued. No Rust tests were run locally because the checkout/Bazel toolchain are absent; no Cargo was used. Do not merge or close #4481 on this query-only evidence. Native idle-daemon CPU, retry-loop convergence and 24-hour bounded-store-growth acceptance are still outstanding; the stacked prerequisite PRs remain separate. |
|
Refs #4481 — exact-head CI infrastructure blocker on In run 42560172386, Clippy job 128983850650 and Dashboard job 128983850753 failed during Bazel external-repository loading, before application analysis/tests could complete. Their logs independently show HTTP 504 Gateway Time-out fetching the pinned I attempted targeted reruns of both failed jobs, but GitHub rejected each with HTTP 403: |
…covery-idle-probe
|
Refs #4481 — new recovery-query scaling blocker on current #4810 head The current Reproduced using SQLite 3.46.1, the actual index shapes, a warmed in-memory database, 75,000 older sleeping receipts, and later due receipts spread over eight distinct deadlines (all in one eligible state). An exact copy of the current probe choices selected
The comparison query used the PR's indexed The current head's Linux fleet is in progress and does not establish this scaling property. Please hold #4810's merge pending a real fix/behavioral evidence, alongside its stack prerequisites. No CI bypass or unrelated owner changes. |
Exercise 24 distinct due retry deadlines behind 512 sleeping receipts through successive one-item registered-store recovery pages. Assert each page settles the oldest due receipt and preserves the future retry wakeup. Refs #4481
|
Refs #4481. Published |
|
Refs #4481 — new exact-head CI blocker on #4810 at
The changed #4810 files are exclusively Run 42613918761 remains in progress with Windows running. Retry the failed fleet job only after the parent run finishes, then investigate readiness timing from the underlying fixture if it reproduces. Keep the 160-attempt readiness assertion and CI policy unchanged, and keep the #4810 merge hold: the separately documented highly fragmented query cost and native macOS daemon idle-CPU / 24-hour store-growth acceptance remain unproven on master. No merge, issue closure, protected-draft edit, or peer-owned change is justified. |
Current Linux prerequisite
The previous Linux fleet stopped after both anonymous launcher API reads returned 403 and their upstream release URLs returned 504. The fixed shared download is included through the draft fixture stack at
56a0798d58. The two feature-file patches are unchanged. The existing acceptance and draft prerequisite holds remain.Refs #4481. Keep the issue open for native macOS idle-CPU and 24-hour store-growth acceptance. HOLD MERGE pending independent review, CI, and the prerequisites below.
Relation receipt recovery
An idle scheduler pass reads the earliest eligible retry from the covering deadline index and returns that exact deadline. For due work, a short creation-order probe can finish a dense page immediately. When each eligible state has at most four due deadlines, equality seeks retrieve the first page plus one key from each state/deadline range. A bounded merge selects the global page in strict creation, session, generation order. With more fragmented deadlines, growing probes compare the creation-order distance to the next page against the size of the due population before choosing an index.
All probes share one read snapshot and one SQLite clock sample. Only returned page items hydrate journal data. The one-row sentinel carries keys, so its payload cannot consume the actor’s read budget. Scope mismatches, missing journals, cancellation, and retry wakeups retain their typed outcomes. The existing schema and indexes serve all paths. Owner review · Mixed backlog review
Verification
The production SQL ran with the bundled SQLite 3.53.2, QPSG enabled, 75,000 registered-schema receipts, real JSON journal rows, and a one-receipt page. Counts include the eligibility check, selection probes, and journal fetch. All ten tested distributions returned the original first identity and sentinel.
The highly fragmented last case still reads and orders due keys on successive pages. Its median query cost was 2.69 ms across 21 warm runs on macOS. With these two index orders, widely scattered deadlines and a long ineligible prefix can still make one small page linear in the smaller backlog. In the few-deadline case, the query plan used covering index range seeks, rowid lookups for bounded candidates, and primary-key journal lookups for page items.
On native macOS the registered-store daemon convergence path processed 21 consecutive one-item pages for each 75,000-row distribution. Median/p95 were 1.12/1.47 ms with a single late due receipt, 1.04/1.33 ms with all due, 1.14/1.30 ms with the permanent prefix and 997 deadlines, 1.37/1.70 ms with the sleeping prefix and three deadlines, and 4.51/5.45 ms with the sleeping prefix and 997 deadlines. The mounted refresh worker settled the sparse receipt with a typed scope mismatch in 7.44 ms, including observation. Two individually valid 34-MiB journals exceed the actor’s 64-MiB combined read budget. The production one-item page processed the first and returned the second as its sentinel without materializing both payloads.
On
7a1e6b1139, the complete macOS session-runtime suite passed all 196 tests and the session-temporal-store suite passed 186 with one existing ignore. The maintained registered-store tests cover tied creation times across both eligible states and several real deadlines, page boundaries, scope refusal, missing/malformed journals, cancellation, and the exact future wakeup. The SQLite plan-stability checker and Rust formatting passed.On
a5ddc7e69f, the hydration join explicitly puts the bounded page before the receipt table. The bundled SQLite 3.53.2 registered store used composite primary-key seeks into receipts and journals for all three candidate paths, both with the previous SQL and with the explicit join order. On 75,001 journal-backed receipts the production page processed the lone due row behind 75,000 sleepers (no sentinel), the first all-due row (sentinel), and the earliest of 37 fragmented due rows (sentinel). System SQLite 3.51.0 also used these two key seeks before and after ANALYZE. The four maintained relation recovery, order, corruption, and cancellation tests and the SQL plan-stability checker passed. Hydration reviewStack
This PR targets #4833. The prerequisites in order from master are #4830, concurrent LCM publication, #4831, foreground projection during history, #4832, daemon readiness in the storage fixture, and #4833, the dashboard retained-fact fixture.
The Linux fleet on
a5ddc7e69fpassed all 183 targets, with 63 executed. The global DB unit suite ran in 243.3s and the store-runtime unit suite in 59.2s. The separate Clippy and Dashboard checks stopped during dependency fetch with HTTP 504.The prior Linux fleet run passed all 89 dashboard API cases and 36 daemon cases and reported a scheduler supersession assertion and a native-host cold index deadline. The scheduler fixture correction passed locally. The cold index timeout did not reproduce across six native macOS mode/phase journeys or two independent Linux controls.
The current verification run checks
b429528654against #4833 at8d8de435cb. This head includes the Linux launcher download prerequisite. The 2-file feature diff has the same paths and stable patch ID after updating the prerequisite.