fix(store): stop a killed compaction from reselecting the group that killed it - #260
Merged
Merged
Conversation
…killed it The completion marker is written after PrepareReplacement, so a process that dies during the merge leaves nothing on disk saying it ever tried. The next start reads the same batch metadata, applies the same selection rules, picks the same group and dies the same way. Nothing in the system observes the loop, and the only external symptom is a process that keeps restarting. A merge is the largest allocation the process makes, so being killed during one is the expected failure, not an exotic one. CompactParquet now records the size of a pass before starting the merge and clears it once the pass completes. A start that finds a record halves the ceiling, so repeated kills walk the group down -- 128, 64, 32 -- until a pass fits and clears the record, after which the ceiling returns to normal. Clearing on success matters as much as the halving: without it the first kill would permanently halve compaction. The floor is a pair, because selection always admits two inputs however large they are and a lower floor would stop compaction rather than shrink it. A merge that still dies at two inputs is one file too large to merge, which a smaller group cannot fix. The record is a file because it has to survive SIGKILL, and a missing or damaged one reads as "no attempt": losing it costs one oversized merge, while treating it as fatal would cost the ability to compact at all. selectCompactionBatches no longer refuses a ceiling below minCompactionInputs. That threshold is a "worth the effort" policy and belongs to the caller, which still applies it to the ceiling it was asked for; inside selection the only real floor is what a merge needs. Keeping the old guard there made the halved ceiling select nothing, which stopped compaction at exactly the moment it most needed to make smaller progress.
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Third item of #254, and the last one I'd call major. Follows #255, #256.
The loop
COMPACTION.jsonis written afterPrepareReplacement. A process that dies during the merge leaves nothing on disk saying it tried. The next start reads the same batch metadata, applies the same selection rules, picks the same group, and dies the same way.Nothing in the system observes this. The only external symptom is a process that keeps restarting, which is exactly what production shows — 8 kills in 17 days at 7.4–7.5 GiB, on a host whose 20ms ingest admission windows produce small batches. Compaction fits that pattern better than ingest does.
A merge is the largest allocation the process makes, so being killed during one is the expected failure, not an exotic one.
Fix
Record the size of a pass before the merge; clear it once the pass completes. A start that finds a record halves the ceiling.
Clearing on success matters as much as the halving. Without it the first kill would permanently halve compaction.
The floor is a pair. Selection always admits two inputs however large (#256), so a lower floor would stop compaction rather than shrink it. A merge that still dies at two is one file too large to merge, which no smaller group can fix — a different problem, and one this does not claim to solve.
The record is a file because it has to survive
SIGKILL. A missing or damaged one reads as "no attempt": losing it costs one oversized merge, whereas treating it as fatal would cost the ability to compact at all.One behaviour change worth review
selectCompactionBatchesno longer refuses a ceiling belowminCompactionInputs(8).That threshold is a "worth the effort" policy. It belongs to the caller, which still applies it to the ceiling it was asked for. Inside selection the only real floor is what a merge needs — two.
I hit this the honest way: the integration test failed with
compacted nothing, because halving 8 to 4 tripped that guard and stopped compaction at exactly the moment it most needed to make smaller progress. Normal callers pass 8 or more and are unaffected; the guard only differs for ceilings of 2–7, which is precisely the recovery case.Tests
TestCompactionBatchCapHalvesAfterAnInterruptedPass— table over the cap arithmetic, including the pair floor and a nonsensical record that must not raise the ceiling.TestCompactionAttemptRoundTripsAndToleratesDamage— round trip, plus a truncated file reading as "no attempt", plus idempotent clear.TestCompactParquetShrinksAfterAnInterruptedPassAndRecovers— end to end: a record left behind shrinks the next pass, and a completed pass clears it so the group can grow back.All written first and verified failing.
just checkpasses.Still open in #254
Zero-copy conversion, byte-weighted batch limit, admission control, and three sizing defects.
debug.SetMemoryLimitdeliberately stays last: it is a soft limit, and set below the real working set it converts an OOM kill into a GC death spiral rather than preventing anything. It has to follow the working-set reductions, not lead them.