Skip to content

Commit cbec1ce

Browse files
manifest: move L0-specific fields from TableMetadata into l0Sublevels
TableMetadata contained four L0-specific fields (SubLevel, L0Index, minIntervalIndex, maxIntervalIndex) that were only meaningful for L0 files, only valid for the most recent Version's l0Sublevels, and written exclusively by l0Sublevels code. Storing them on the shared TableMetadata struct was fragile because any code could accidentally read stale values from a non-current Version. This change introduces an l0FileState struct and stores per-file state in l0Sublevels via a fileState slice (indexed by file position) and a fileStateMap (TableNum -> index). The L0Index concept is now implicit as the index into fileState. L0CompactionFiles.FilesIncluded is changed from bitSet (indexed by L0Index) to map[base.TableNum]struct{}, eliminating the need for L0Index to be accessible outside l0Sublevels. An L0Organizer.SubLevelOf method is added for external callers (e.g. generateSublevelInfo in compaction_picker.go) that need to look up a file's sublevel. Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
1 parent 56dd893 commit cbec1ce

8 files changed

Lines changed: 241 additions & 168 deletions

File tree

compaction_picker.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,13 @@ func (cl sublevelInfo) String() string {
143143

144144
// generateSublevelInfo will generate the level slices for each of the sublevels
145145
// from the level slice for all of L0.
146-
func generateSublevelInfo(cmp base.Compare, levelFiles manifest.LevelSlice) []sublevelInfo {
146+
func generateSublevelInfo(
147+
cmp base.Compare, levelFiles manifest.LevelSlice, l0Organizer *manifest.L0Organizer,
148+
) []sublevelInfo {
147149
sublevelMap := make(map[uint64][]*manifest.TableMetadata)
148150
for f := range levelFiles.All() {
149-
sublevelMap[uint64(f.SubLevel)] = append(sublevelMap[uint64(f.SubLevel)], f)
151+
sl := uint64(l0Organizer.SubLevelOf(f))
152+
sublevelMap[sl] = append(sublevelMap[sl], f)
150153
}
151154

152155
var sublevels []int
@@ -442,7 +445,7 @@ func (pc *pickedTableCompaction) setupInputs(
442445

443446
if inputLevel.level == 0 {
444447
// If L0 is involved, it should always be the startLevel of the compaction.
445-
pc.startLevel.l0SublevelInfo = generateSublevelInfo(cmp, pc.startLevel.files)
448+
pc.startLevel.l0SublevelInfo = generateSublevelInfo(cmp, pc.startLevel.files, pc.l0Organizer)
446449
}
447450

448451
if outputKeyRangeAlreadyCompacting(cmp, inProgressCompactions, pc) {
@@ -546,7 +549,7 @@ func (pc *pickedTableCompaction) maybeGrowL0ForBase(cmp base.Compare, maxExpande
546549
iter := pc.version.Levels[0].Iter()
547550
var sizeSum uint64
548551
for j, f := 0, iter.First(); f != nil; j, f = j+1, iter.Next() {
549-
if pc.lcf.FilesIncluded[f.L0Index] {
552+
if _, ok := pc.lcf.FilesIncluded[f.TableNum]; ok {
550553
newStartLevelFiles = append(newStartLevelFiles, f)
551554
sizeSum += f.Size
552555
}

compaction_picker_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,11 @@ func TestPickedCompactionSetupInputs(t *testing.T) {
10751075
pc.outputLevel.level = pc.startLevel.level + 1
10761076
}
10771077
pc.version = newVersion(opts, files)
1078+
if pc.startLevel.level == 0 {
1079+
l0Organizer := manifest.NewL0Organizer(opts.Comparer, opts.FlushSplitBytes)
1080+
l0Organizer.ResetForTesting(pc.version)
1081+
pc.l0Organizer = l0Organizer
1082+
}
10781083
pc.startLevel.files = pc.version.Overlaps(
10791084
pc.startLevel.level,
10801085
base.UserKeyBoundsInclusive([]byte(args[0].String()), []byte(args[1].String())),

compaction_test.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,7 +2368,6 @@ func TestCompactionCheckOrdering(t *testing.T) {
23682368
var sublevels []manifest.LevelSlice
23692369
var files *[]*manifest.TableMetadata
23702370
var sublevel []*manifest.TableMetadata
2371-
var sublevelNum int
23722371
var parsingSublevel bool
23732372
tableNum := base.TableNum(1)
23742373

@@ -2390,10 +2389,14 @@ func TestCompactionCheckOrdering(t *testing.T) {
23902389
if err != nil {
23912390
return err.Error()
23922391
}
2393-
sublevelNum, err = strconv.Atoi(data[3:])
2392+
sublevelNum, err := strconv.Atoi(data[3:])
23942393
if err != nil {
23952394
return err.Error()
23962395
}
2396+
if sublevelNum != len(sublevels) {
2397+
d.Fatalf(t, "L0 sublevels should be specified in order; expected L0.%d, got L0.%d", len(sublevels), sublevelNum)
2398+
}
2399+
23972400
if c.startLevel.level == -1 {
23982401
c.startLevel.level = level
23992402
files = &startFiles
@@ -2423,7 +2426,6 @@ func TestCompactionCheckOrdering(t *testing.T) {
24232426
tableNum++
24242427
*files = append(*files, meta)
24252428
if parsingSublevel {
2426-
meta.SubLevel = sublevelNum
24272429
sublevel = append(sublevel, meta)
24282430
}
24292431
}
@@ -2437,7 +2439,21 @@ func TestCompactionCheckOrdering(t *testing.T) {
24372439
}
24382440
if c.startLevel.level == 0 {
24392441
// We don't change the input files for the compaction beyond this point.
2440-
c.startLevel.l0SublevelInfo = generateSublevelInfo(c.comparer.Compare, c.startLevel.files)
2442+
// Build l0SublevelInfo directly from the explicitly-specified sublevels.
2443+
if len(sublevels) > 0 {
2444+
for i, sl := range sublevels {
2445+
c.startLevel.l0SublevelInfo = append(c.startLevel.l0SublevelInfo, sublevelInfo{
2446+
LevelSlice: sl,
2447+
sublevel: manifest.L0Sublevel(i),
2448+
})
2449+
}
2450+
} else {
2451+
// No explicit sublevels; put all files in sublevel 0.
2452+
c.startLevel.l0SublevelInfo = []sublevelInfo{{
2453+
LevelSlice: manifest.NewLevelSliceKeySorted(c.comparer.Compare, startFiles),
2454+
sublevel: manifest.L0Sublevel(0),
2455+
}}
2456+
}
24412457
}
24422458

24432459
newIters := func(

internal/compact/testdata/tombstone_elision_setup

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,21 +144,21 @@ L0 [a, z]: [a, j) [k, z)
144144
define
145145
L0
146146
1:[a#1,SET-b#inf,RANGEDEL]
147-
1:[c#1,SET-d#inf,RANGEDEL]
148-
1:[f#1,SET-g#inf,RANGEDEL]
149-
1:[i#1,SET-j#inf,RANGEDEL]
147+
2:[c#1,SET-d#inf,RANGEDEL]
148+
3:[f#1,SET-g#inf,RANGEDEL]
149+
4:[i#1,SET-j#inf,RANGEDEL]
150150
L6
151-
1:[a#0,SET-i#inf,RANGEDEL]
152-
1:[k#0,SET-z#inf,RANGEDEL]
151+
5:[a#0,SET-i#inf,RANGEDEL]
152+
6:[k#0,SET-z#inf,RANGEDEL]
153153
----
154154
L0.0:
155155
000001:[a#1,SET-b#inf,RANGEDEL]
156-
000001:[c#1,SET-d#inf,RANGEDEL]
157-
000001:[f#1,SET-g#inf,RANGEDEL]
158-
000001:[i#1,SET-j#inf,RANGEDEL]
156+
000002:[c#1,SET-d#inf,RANGEDEL]
157+
000003:[f#1,SET-g#inf,RANGEDEL]
158+
000004:[i#1,SET-j#inf,RANGEDEL]
159159
L6:
160-
000001:[a#0,SET-i#inf,RANGEDEL]
161-
000001:[k#0,SET-z#inf,RANGEDEL]
160+
000005:[a#0,SET-i#inf,RANGEDEL]
161+
000006:[k#0,SET-z#inf,RANGEDEL]
162162

163163
# L0 compaction should reflect the ranges in L0 as well.
164164
inuse-key-ranges

0 commit comments

Comments
 (0)