Repository navigation
fix(storage): bound the transaction cleanup probes to the batch range - #1583
Merged
Merged
Conversation
The reference checks in cleanup_orphaned_transactions ran a correlated NOT EXISTS per transaction against the partitioned tables, whose partition key is not modify_tx, so every row cost one index probe per partition: 117 to 186 partitions across the three tables, 50k rows per batch, for the full 45-minute budget twice a day. That is the disk-read and CPU storm seen at 02:00 and 14:00 on base and bsc. Add the batch's id range to each subquery so the planner does one short range scan per partition per batch and an anti-join. The predicate is implied by the equality, so the same rows qualify. One 50k batch on dev: base 3.17 s to 54 ms, bsc 11.07 s to 56 ms, identical orphan counts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
tvinagre
approved these changes
Oct 12, 2026
zizou0x
enabled auto-merge
October 12, 2026 15:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
cleanup_orphaned_transactionskeeps its structure; each of its nine reference checks gains the batch's id range:The added predicate is implied by the equality, so the same rows qualify. The migration redefines the procedure with the body from
2026-07-03_incremental_transaction_cleanupplus these nine lines;down.sqlrestores the original body.How to review
PL/pgSQL has no partial edit, so the migration must carry the whole procedure body (
CREATE OR REPLACE) and git shows the file as new. The procedure body is a verbatim copy of the one in2026-07-03_incremental_transaction_cleanup/up.sqlexcept for the nineNOT EXISTSlines below;down.sqlis the verbatim original. To confirm nothing else differs:The full diff between the two bodies:
Why
component_balance,protocol_stateandcontract_storageare partitioned byvalid_to, not bymodify_tx, so the correlated probex.modify_tx = t.idcosts one index lookup in every partition for every transaction the sweep considers: 117 partitions across the three tables on dev-base, 186 on dev-bsc, 50,000 rows per batch, for the whole 45-minute budget, twice a day. That is the 02:00 and 14:00 load seen on base and bsc (4,000 to 7,000 read IOPS on base, 75 to 100% CPU on bsc), and the sweep never catches up on those chains, while on ethereum and fynd-prod-base, where it is caught up, it finishes in minutes.With the range in the subquery the planner runs one short range scan per partition per batch and anti-joins the results.
Measured
One 50,000-id batch at each DB's current cursor, read-only
SELECT count(*)with the same predicates, 2026-10-11:Those are warm-cache numbers; the real runs are cold, which is where the IOPS come from.
Test
test_cleanup_orphaned_transactions_serial_db(references survive, orphans are deleted) passes against the new body. Migration applied, reverted and re-applied locally;pg_procshows the ranged body after up and the original after down.Context: this replaces the index-rebuild approach in #1580, which measured no change in the cleanup's cost on 2026-10-10 because the rebuilt default-partition index is one of ~40 per table being probed.
🤖 Generated with Claude Code