Skip to content

Commit 8e65e15

Browse files
committed
pebble: setupInputs checks key range conflicts with in progress compactions
Previously, checking if a compaction had conflicts with an ongoing compaction was done in `setupInputs`, where we check if any of the input files are already marked as compacting, and also `inputRangeAlreadyCompacting`, where we check if the compaction range chosen overlaps with an ongoing compaction's range. `inputRangeAlreadyCompacting` was typically called right after `setupInputs`. This commit consolidates `inputRangeAlreadyCompacting` into `setupInputs`. Epic: none
1 parent 8dea64b commit 8e65e15

File tree

4 files changed

+264
-370
lines changed

4 files changed

+264
-370
lines changed

compaction_picker.go

Lines changed: 32 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,6 @@ func newPickedCompactionFromL0(
339339

340340
pc := newPickedTableCompaction(opts, vers, l0Organizer, 0, outputLevel, baseLevel)
341341
pc.lcf = lcf
342-
pc.outputLevel.level = outputLevel
343342

344343
// Manually build the compaction as opposed to calling
345344
// pickAutoHelper. This is because L0Sublevels has already added
@@ -416,11 +415,12 @@ func (pc *pickedTableCompaction) clone() *pickedTableCompaction {
416415
// pc.outputLevel. It returns false if a concurrent compaction is occurring on the start or
417416
// output level files. Note that inputLevel is not necessarily pc.startLevel. In multiLevel
418417
// compactions, inputs are set by calling setupInputs once for each adjacent pair of levels.
419-
// This will preserve level invariants when expanding the compaction. pc.smallest and pc.largest
420-
// will be updated to reflect the key range of the inputs.
418+
// This will preserve level invariants when expanding the compaction. pc.bounds will be updated
419+
// to reflect the key range of the inputs.
421420
func (pc *pickedTableCompaction) setupInputs(
422421
opts *Options,
423422
diskAvailBytes uint64,
423+
inProgressCompactions []compactionInfo,
424424
inputLevel *compactionLevel,
425425
problemSpans *problemspans.ByLevel,
426426
) bool {
@@ -462,7 +462,8 @@ func (pc *pickedTableCompaction) setupInputs(
462462
// If L0 is involved, it should always be the startLevel of the compaction.
463463
pc.startLevel.l0SublevelInfo = generateSublevelInfo(cmp, pc.startLevel.files)
464464
}
465-
return true
465+
466+
return !outputKeyRangeAlreadyCompacting(cmp, inProgressCompactions, pc)
466467
}
467468

468469
// grow grows the number of inputs at startLevel without changing the number of
@@ -586,17 +587,15 @@ func (pc *pickedTableCompaction) estimatedInputSize() uint64 {
586587

587588
// setupMultiLevelCandidate returns true if it successfully added another level
588589
// to the compaction.
589-
func (pc *pickedTableCompaction) setupMultiLevelCandidate(
590-
opts *Options, diskAvailBytes uint64,
591-
) bool {
590+
func (pc *pickedTableCompaction) setupMultiLevelCandidate(opts *Options, env compactionEnv) bool {
592591
pc.inputs = append(pc.inputs, compactionLevel{level: pc.outputLevel.level + 1})
593592

594593
// Recalibrate startLevel and outputLevel:
595594
// - startLevel and outputLevel pointers may be obsolete after appending to pc.inputs.
596595
// - push outputLevel to extraLevels and move the new level to outputLevel
597596
pc.startLevel = &pc.inputs[0]
598597
pc.outputLevel = &pc.inputs[2]
599-
return pc.setupInputs(opts, diskAvailBytes, &pc.inputs[1], nil /* TODO(radu) */)
598+
return pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, &pc.inputs[1], nil /* TODO(radu) */)
600599
}
601600

602601
// canCompactTables returns true if the tables in the level slice are not
@@ -1398,9 +1397,7 @@ func (p *compactionPickerByScore) pickAutoScore(env compactionEnv) pickedCompact
13981397

13991398
if info.level == 0 {
14001399
ptc := pickL0(env, p.opts, p.vers, p.latestVersionState.l0Organizer, p.baseLevel)
1401-
// Fail-safe to protect against compacting the same sstable
1402-
// concurrently.
1403-
if ptc != nil && !inputRangeAlreadyCompacting(p.opts.Comparer.Compare, env, ptc) {
1400+
if ptc != nil {
14041401
p.addScoresToPickedCompactionMetrics(ptc, scores)
14051402
ptc.score = info.score
14061403
if false {
@@ -1419,8 +1416,7 @@ func (p *compactionPickerByScore) pickAutoScore(env compactionEnv) pickedCompact
14191416
}
14201417

14211418
pc := pickAutoLPositive(env, p.opts, p.vers, p.latestVersionState.l0Organizer, *info, p.baseLevel)
1422-
// Fail-safe to protect against compacting the same sstable concurrently.
1423-
if pc != nil && !inputRangeAlreadyCompacting(p.opts.Comparer.Compare, env, pc) {
1419+
if pc != nil {
14241420
p.addScoresToPickedCompactionMetrics(pc, scores)
14251421
pc.score = info.score
14261422
if false {
@@ -1612,17 +1608,10 @@ func (p *compactionPickerByScore) pickedCompactionFromCandidateFile(
16121608
startLevel, outputLevel, p.baseLevel)
16131609
pc.kind = kind
16141610
pc.startLevel.files = inputs
1615-
pc.bounds = manifest.KeyRange(p.opts.Comparer.Compare, pc.startLevel.files.All())
16161611

1617-
// Fail-safe to protect against compacting the same sstable concurrently.
1618-
if inputRangeAlreadyCompacting(p.opts.Comparer.Compare, env, pc) {
1612+
if !pc.setupInputs(p.opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, env.problemSpans) {
16191613
return nil
16201614
}
1621-
1622-
if !pc.setupInputs(p.opts, env.diskAvailBytes, pc.startLevel, env.problemSpans) {
1623-
return nil
1624-
}
1625-
16261615
return pc
16271616
}
16281617

@@ -1787,15 +1776,15 @@ func pickAutoLPositive(
17871776
}
17881777
pc.startLevel.files = cInfo.file.Slice()
17891778

1790-
if !pc.setupInputs(opts, env.diskAvailBytes, pc.startLevel, env.problemSpans) {
1779+
if !pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, env.problemSpans) {
17911780
return nil
17921781
}
1793-
return pc.maybeAddLevel(opts, env.diskAvailBytes)
1782+
return pc.maybeAddLevel(opts, env)
17941783
}
17951784

17961785
// maybeAddLevel maybe adds a level to the picked compaction.
17971786
func (pc *pickedTableCompaction) maybeAddLevel(
1798-
opts *Options, diskAvailBytes uint64,
1787+
opts *Options, env compactionEnv,
17991788
) *pickedTableCompaction {
18001789
pc.pickerMetrics.singleLevelOverlappingRatio = pc.overlappingRatio()
18011790
if pc.outputLevel.level == numLevels-1 {
@@ -1806,17 +1795,17 @@ func (pc *pickedTableCompaction) maybeAddLevel(
18061795
return pc
18071796
}
18081797
targetFileSize := opts.TargetFileSize(pc.outputLevel.level, pc.baseLevel)
1809-
if pc.estimatedInputSize() > expandedCompactionByteSizeLimit(opts, targetFileSize, diskAvailBytes) {
1798+
if pc.estimatedInputSize() > expandedCompactionByteSizeLimit(opts, targetFileSize, env.diskAvailBytes) {
18101799
// Don't add a level if the current compaction exceeds the compaction size limit
18111800
return pc
18121801
}
1813-
return opts.Experimental.MultiLevelCompactionHeuristic.pick(pc, opts, diskAvailBytes)
1802+
return opts.Experimental.MultiLevelCompactionHeuristic.pick(pc, opts, env)
18141803
}
18151804

18161805
// MultiLevelHeuristic evaluates whether to add files from the next level into the compaction.
18171806
type MultiLevelHeuristic interface {
18181807
// Evaluate returns the preferred compaction.
1819-
pick(pc *pickedTableCompaction, opts *Options, diskAvailBytes uint64) *pickedTableCompaction
1808+
pick(pc *pickedTableCompaction, opts *Options, env compactionEnv) *pickedTableCompaction
18201809

18211810
// Returns if the heuristic allows L0 to be involved in ML compaction
18221811
allowL0() bool
@@ -1831,7 +1820,7 @@ type NoMultiLevel struct{}
18311820
var _ MultiLevelHeuristic = (*NoMultiLevel)(nil)
18321821

18331822
func (nml NoMultiLevel) pick(
1834-
pc *pickedTableCompaction, opts *Options, diskAvailBytes uint64,
1823+
pc *pickedTableCompaction, opts *Options, env compactionEnv,
18351824
) *pickedTableCompaction {
18361825
return pc
18371826
}
@@ -1887,17 +1876,17 @@ var _ MultiLevelHeuristic = (*WriteAmpHeuristic)(nil)
18871876
// in-progress flushes and compactions from completing, etc. Consider ways to
18881877
// deduplicate work, given that setupInputs has already been called.
18891878
func (wa WriteAmpHeuristic) pick(
1890-
pcOrig *pickedTableCompaction, opts *Options, diskAvailBytes uint64,
1879+
pcOrig *pickedTableCompaction, opts *Options, env compactionEnv,
18911880
) *pickedTableCompaction {
18921881
pcMulti := pcOrig.clone()
1893-
if !pcMulti.setupMultiLevelCandidate(opts, diskAvailBytes) {
1882+
if !pcMulti.setupMultiLevelCandidate(opts, env) {
18941883
return pcOrig
18951884
}
18961885
// We consider the addition of a level as an "expansion" of the compaction.
18971886
// If pcMulti is past the expanded compaction byte size limit already,
18981887
// we don't consider it.
18991888
targetFileSize := opts.TargetFileSize(pcMulti.outputLevel.level, pcMulti.baseLevel)
1900-
if pcMulti.estimatedInputSize() >= expandedCompactionByteSizeLimit(opts, targetFileSize, diskAvailBytes) {
1889+
if pcMulti.estimatedInputSize() >= expandedCompactionByteSizeLimit(opts, targetFileSize, env.diskAvailBytes) {
19011890
return pcOrig
19021891
}
19031892
picked := pcOrig
@@ -1937,11 +1926,11 @@ func pickL0(
19371926
lcf := l0Organizer.PickBaseCompaction(opts.Logger, 1, vers.Levels[baseLevel].Slice(), baseLevel, env.problemSpans)
19381927
if lcf != nil {
19391928
pc := newPickedCompactionFromL0(lcf, opts, vers, l0Organizer, baseLevel, true)
1940-
if pc.setupInputs(opts, env.diskAvailBytes, pc.startLevel, env.problemSpans) {
1929+
if pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, env.problemSpans) {
19411930
if pc.startLevel.files.Empty() {
19421931
opts.Logger.Errorf("%v", base.AssertionFailedf("empty compaction chosen"))
19431932
}
1944-
return pc.maybeAddLevel(opts, env.diskAvailBytes)
1933+
return pc.maybeAddLevel(opts, env)
19451934
}
19461935
// TODO(radu): investigate why this happens.
19471936
// opts.Logger.Errorf("%v", base.AssertionFailedf("setupInputs failed"))
@@ -1954,7 +1943,7 @@ func pickL0(
19541943
lcf = l0Organizer.PickIntraL0Compaction(env.earliestUnflushedSeqNum, minIntraL0Count, env.problemSpans)
19551944
if lcf != nil {
19561945
pc := newPickedCompactionFromL0(lcf, opts, vers, l0Organizer, baseLevel, false)
1957-
if pc.setupInputs(opts, env.diskAvailBytes, pc.startLevel, env.problemSpans) {
1946+
if pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, env.problemSpans) {
19581947
if pc.startLevel.files.Empty() {
19591948
opts.Logger.Fatalf("empty compaction chosen")
19601949
}
@@ -2009,12 +1998,12 @@ func newPickedManualCompaction(
20091998
}
20101999
// We use nil problemSpans because we don't want problem spans to prevent
20112000
// manual compactions.
2012-
if !pc.setupInputs(opts, env.diskAvailBytes, pc.startLevel, nil /* problemSpans */) {
2001+
if !pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, nil /* problemSpans */) {
20132002
// setupInputs returned false indicating there's a conflicting
20142003
// concurrent compaction.
20152004
return nil, true
20162005
}
2017-
if pc = pc.maybeAddLevel(opts, env.diskAvailBytes); pc == nil {
2006+
if pc = pc.maybeAddLevel(opts, env); pc == nil {
20182007
return nil, false
20192008
}
20202009
if pc.outputLevel.level != outputLevel {
@@ -2024,10 +2013,6 @@ func newPickedManualCompaction(
20242013
panic("pebble: compaction picked unexpected output level")
20252014
}
20262015
}
2027-
// Fail-safe to protect against compacting the same sstable concurrently.
2028-
if inputRangeAlreadyCompacting(opts.Comparer.Compare, env, pc) {
2029-
return nil, true
2030-
}
20312016
return pc, false
20322017
}
20332018

@@ -2054,18 +2039,14 @@ func pickDownloadCompaction(
20542039
pc = newPickedTableCompaction(opts, vers, l0Organizer, level, level, baseLevel)
20552040
pc.kind = kind
20562041
pc.startLevel.files = manifest.NewLevelSliceKeySorted(opts.Comparer.Compare, []*manifest.TableMetadata{file})
2057-
if !pc.setupInputs(opts, env.diskAvailBytes, pc.startLevel, nil /* problemSpans */) {
2042+
if !pc.setupInputs(opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, nil /* problemSpans */) {
20582043
// setupInputs returned false indicating there's a conflicting
20592044
// concurrent compaction.
20602045
return nil
20612046
}
20622047
if pc.outputLevel.level != level {
20632048
panic("pebble: download compaction picked unexpected output level")
20642049
}
2065-
// Fail-safe to protect against compacting the same sstable concurrently.
2066-
if inputRangeAlreadyCompacting(opts.Comparer.Compare, env, pc) {
2067-
return nil
2068-
}
20692050
return pc
20702051
}
20712052

@@ -2106,10 +2087,7 @@ func pickReadTriggeredCompactionHelper(
21062087
rc.level, defaultOutputLevel(rc.level, p.baseLevel), p.baseLevel)
21072088

21082089
pc.startLevel.files = overlapSlice
2109-
if !pc.setupInputs(p.opts, env.diskAvailBytes, pc.startLevel, env.problemSpans) {
2110-
return nil
2111-
}
2112-
if inputRangeAlreadyCompacting(p.opts.Comparer.Compare, env, pc) {
2090+
if !pc.setupInputs(p.opts, env.diskAvailBytes, env.inProgressCompactions, pc.startLevel, env.problemSpans) {
21132091
return nil
21142092
}
21152093
pc.kind = compactionKindRead
@@ -2134,17 +2112,11 @@ func (p *compactionPickerByScore) forceBaseLevel1() {
21342112
p.baseLevel = 1
21352113
}
21362114

2137-
func inputRangeAlreadyCompacting(
2138-
cmp base.Compare, env compactionEnv, pc *pickedTableCompaction,
2115+
// outputKeyRangeAlreadyCompacting checks if the input range of the picked
2116+
// compaction is already being written to by an in-progress compaction.
2117+
func outputKeyRangeAlreadyCompacting(
2118+
cmp base.Compare, inProgressCompactions []compactionInfo, pc *pickedTableCompaction,
21392119
) bool {
2140-
for _, cl := range pc.inputs {
2141-
for f := range cl.files.All() {
2142-
if f.IsCompacting() {
2143-
return true
2144-
}
2145-
}
2146-
}
2147-
21482120
// Look for active compactions outputting to the same region of the key
21492121
// space in the same output level. Two potential compactions may conflict
21502122
// without sharing input files if there are no files in the output level
@@ -2174,7 +2146,7 @@ func inputRangeAlreadyCompacting(
21742146
//
21752147
// * - currently compacting
21762148
if pc.outputLevel != nil && pc.outputLevel.level != 0 {
2177-
for _, c := range env.inProgressCompactions {
2149+
for _, c := range inProgressCompactions {
21782150
if pc.outputLevel.level != c.outputLevel {
21792151
continue
21802152
}

0 commit comments

Comments
 (0)