@@ -270,6 +270,15 @@ type tableCompaction struct {
270270
271271 inputs []compactionLevel
272272
273+ // eventualOutputLevel is normally outputLevel.level, unless
274+ // outputLevel.level+1 has no overlap with the compaction bounds (in which
275+ // case it is the bottom-most consecutive level with no such overlap).
276+ //
277+ // Because of move compactions, we know that any sstables produced by this
278+ // compaction will be later moved to eventualOutputLevel. So we use
279+ // eventualOutputLevel when determining the target file size, compression
280+ // options, etc.
281+ eventualOutputLevel int
273282 // maxOutputFileSize is the maximum size of an individual table created
274283 // during compaction.
275284 maxOutputFileSize uint64
@@ -280,9 +289,10 @@ type tableCompaction struct {
280289 // The boundaries of the input data.
281290 bounds base.UserKeyBounds
282291
283- // grandparents are the tables in level+2 that overlap with the files being
284- // compacted. Used to determine output table boundaries. Do not assume that the actual files
285- // in the grandparent when this compaction finishes will be the same.
292+ // grandparents are the tables in eventualOutputLevel+2 that overlap with the
293+ // files being compacted. Used to determine output table boundaries. Do not
294+ // assume that the actual files in the grandparent when this compaction
295+ // finishes will be the same.
286296 grandparents manifest.LevelSlice
287297
288298 delElision compact.TombstoneElision
@@ -572,7 +582,18 @@ func newCompaction(
572582 grantHandle : grantHandle ,
573583 }
574584
575- targetFileSize := opts .TargetFileSize (pc .outputLevel .level , pc .baseLevel )
585+ // Determine eventual output level.
586+ c .eventualOutputLevel = pc .outputLevel .level
587+ // TODO(radu): for intra-L0 compactions, we could check if the compaction
588+ // includes all L0 files within the bounds.
589+ if pc .outputLevel .level != 0 {
590+ for c .eventualOutputLevel < manifest .NumLevels - 1 && ! c .version .HasOverlap (c .eventualOutputLevel + 1 , c .bounds ) {
591+ // All output tables are guaranteed to be moved down.
592+ c .eventualOutputLevel ++
593+ }
594+ }
595+
596+ targetFileSize := opts .TargetFileSize (c .eventualOutputLevel , pc .baseLevel )
576597 c .maxOutputFileSize = uint64 (targetFileSize )
577598 c .maxOverlapBytes = maxGrandparentOverlapBytes (targetFileSize )
578599
@@ -607,8 +628,8 @@ func newCompaction(
607628 }
608629 // Compute the set of outputLevel+1 files that overlap this compaction (these
609630 // are the grandparent sstables).
610- if c .outputLevel . level + 1 < numLevels {
611- c .grandparents = c .version .Overlaps (max (c .outputLevel . level + 1 , pc .baseLevel ), c .bounds )
631+ if c .eventualOutputLevel < manifest . NumLevels - 1 {
632+ c .grandparents = c .version .Overlaps (max (c .eventualOutputLevel + 1 , pc .baseLevel ), c .bounds )
612633 }
613634 c .delElision , c .rangeKeyElision = compact .SetupTombstoneElision (
614635 c .comparer .Compare , c .version , pc .l0Organizer , c .outputLevel .level , c .bounds ,
@@ -666,7 +687,10 @@ func (c *tableCompaction) maybeSwitchToMoveOrCopy(
666687 // We avoid a move or copy if there is lots of overlapping grandparent data.
667688 // Otherwise, the move could create a parent file that will require a very
668689 // expensive merge later on.
669- if c .grandparents .AggregateSizeSum () > c .maxOverlapBytes {
690+ //
691+ // Note that if eventualOutputLevel != outputLevel, there are no
692+ // "grandparents" on the output level.
693+ if c .eventualOutputLevel == c .outputLevel .level && c .grandparents .AggregateSizeSum () > c .maxOverlapBytes {
670694 return
671695 }
672696
@@ -840,13 +864,18 @@ func newFlush(
840864 logger : opts .Logger ,
841865 inputs : []compactionLevel {{level : - 1 }, {level : 0 }},
842866 getValueSeparation : getValueSeparation ,
843- maxOutputFileSize : math .MaxUint64 ,
844- maxOverlapBytes : math .MaxUint64 ,
845- grantHandle : noopGrantHandle {},
867+ // TODO(radu): consider calculating the eventual output level for flushes.
868+ // We expect the bounds to be very wide in practice, but perhaps we can do a
869+ // finer-grained overlap analysis.
870+ eventualOutputLevel : 0 ,
871+ maxOutputFileSize : math .MaxUint64 ,
872+ maxOverlapBytes : math .MaxUint64 ,
873+ grantHandle : noopGrantHandle {},
846874 metrics : compactionMetrics {
847875 beganAt : beganAt ,
848876 },
849877 }
878+
850879 c .flush .flushables = flushing
851880 c .flush .l0Limits = l0Organizer .FlushSplitKeys ()
852881 c .startLevel = & c .inputs [0 ]
@@ -3440,7 +3469,7 @@ func (d *DB) compactAndWrite(
34403469 }
34413470 spanPolicyValid = true
34423471 }
3443- writerOpts := d .makeWriterOptions (c .outputLevel . level )
3472+ writerOpts := d .makeWriterOptions (c .eventualOutputLevel )
34443473 if spanPolicy .ValueStoragePolicy .DisableSeparationBySuffix {
34453474 writerOpts .DisableValueBlocks = true
34463475 }
0 commit comments