Fix compaction starvation: skip partitions with no new data, do the worst ones first - #670
Conversation
PR #658 already claims llp/0195 for upstream-less-gateway-idles. The filenames differ, so git merges both silently and the duplicate-numbers job cannot see it: it checks the checked-out tree, which on a PR head is master plus that one branch. 0196-0198 are claimed by two other unmerged branches, so 0199 is the next free number across all refs. The three @refs in maintenance.js are retargeted; they would have resolved to the wrong document rather than dangling.
Neutral review round 1 of 2 (adopted PR,
|
The renumber commit scoped its replace to src/ and llp/, so this test section header was left pointing at a number this branch no longer uses.
Neutral review round 2 of 2 (adopted PR) -
|
philcunliffe
left a comment
There was a problem hiding this comment.
Verdict: changes requested - but nothing blocking remains
Both review rounds are used, so under the adopted-PR rules the residual findings come back to
you rather than being deferred into a follow-up issue. To be clear about what that means
here: round 2 was clean, the blocking item is fixed, and the engineering is sound. This is
a hand-back, not a rejection.
What was blocking, and is fixed
llp/0195-maintenance-compaction-convergence.decision.md collided with PR #658, which also
claims 0195. Neutral renumbered it to 0199 and retargeted the four citations. Verified by
an unfiltered sweep: zero 0195 references remain, all LLP 0199 refs resolve to real
anchors, 0199 is uniquely owned across every branch, and the diff is numbering-only.
Two notes of neutral's own error, since they are on your branch:
- The first heal commit scoped its replace to
src/andllp/, missing a section header in
test/core/cache-retention-maintenance.test.js. Fixed indd2f73d. - The round-2 review comment was first posted with a fabricated full head SHA in its
marker. Neutral knew the short form and wrote out 33 characters it had not verified. The
comment has been corrected and carries a note saying so.
Why this collision keeps happening
Three contributors hit it in 24 hours. .github/workflows/llp-check.yml runs
find llp -name '[0-9][0-9][0-9][0-9]-*.md' | cut -c1-4 | sort | uniq -d against the
checked-out tree, which on a PR head is master plus one branch - it structurally cannot see
sibling branches, and only fails on push: [master] after the second doc merges. The
workflow's own header comment already says this. Master sits at 0194 while four unmerged
branches hold 0195-0199, so anyone computing the next number from master lands on a taken
one, and the @refs still resolve - to the wrong document - so no ref checker flags it.
Worth fixing at the source rather than per-PR: have /llp-create enumerate
git for-each-ref refs/remotes/origin instead of the working tree.
The one thing worth doing before merge
No test covers neediest-first ordering for the source-table layout. That is very likely
the production layout in your report: generationLayout never advances epoch for
source-table cursors, so "sat at epoch 0 with 700-1250 data files" is what a source-table
partition looks like by construction. Neutral verified by hand that your code is correct
there - built two source-table partitions (1 vs 4 files) and maintainCache returned
zzz_heavy:4, aaa_light:1 - so this is a missing test, not a defect. A third case mirroring
the order test with layout: 'source-table', tableDir: 'table' closes it.
Five smaller items, take or leave
- The LLP says the gate covers "the file-count heuristics", but the code gates all three
needsCompactionclauses includingmetadataBytes > 64MB. Bounded in practice, so no
live bug, but doc and code should agree. - Ranking runs before the loop and is not budget-checked, while the budget break sits at the
loop top. On a cache large enough that ranking alone exceedsmax_tick_ms, the loop breaks
at iteration 0 and maintenance does nothing, forever.if (processed > 0 && ...) breakis
cheap insurance. countDataFilesnow runs 2-3x per partition per tick, all synchronousreaddirSyncon the
daemon event loop. Threading the ranked count through avoids it. Also pure waste under
expireOnly.- No
Extended-by: LLP 0199back-ref on LLP 0027, which this generalizes. - The PR body claims two suite failures also fail on master; the suite is green here.
For the record, on the substance
Round 1 attacked both predicates and neither broke. The baseline gate does reach the starved
partitions (resettleBaselineFiles returns undefined for never-compacted ones, and
N !== undefined is always true - exactly your compaction: null production case). The
baseline is generation-consistent, no path lets data accumulate without moving the count,
stale cursors compact once and converge, and --force remains an operator escape hatch. The
two changes are load-bearing on each other: neediest-first would starve small partitions
without the convergence gate, and the gate alone would not fix walk order.
Push any commit and neutral re-engages with a fresh review at the new head.
|
Merged as Verified post-merge: no duplicate LLP numbers on Six non-blocking items from the review are now in
Neutral is not filing these as issues - that is the maintainer's call on priority. Label any |
Cache maintenance was rewriting the same few partitions every tick: the avg-file-size heuristic re-flags a partition forever because compacted output files come out far smaller than 32MB, so nothing ever graduates. On the production server the first four partitions in walk order had been recompacted 29-51 times while every org=hyperparam partition sat at epoch 0 with 700-1250 data files, never reached before the 30s tick budget ran out.
Two changes:
Design rationale in LLP 0195. Two new tests cover both behaviors; the two failing tests in the suite (blob-store, usage-policy-fold) also fail on master.