Skip to content

Commit edebc31

Browse files
committed
*: use iter.Seq for ranging over TableMetadata
Use the new Go 1.23 iter.Seq type to range over collections of TableMetadata. The LevelMetadata and LevelSlice types are updated with All methods, returning an iter.Seq[*TableMetadata].
1 parent 21441fa commit edebc31

28 files changed

+155
-195
lines changed

compaction.go

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bytes"
99
"context"
1010
"fmt"
11+
"iter"
1112
"math"
1213
"runtime/pprof"
1314
"slices"
@@ -294,9 +295,9 @@ type compaction struct {
294295
func (c *compaction) inputLargestSeqNumAbsolute() base.SeqNum {
295296
var seqNum base.SeqNum
296297
for _, cl := range c.inputs {
297-
cl.files.Each(func(m *manifest.TableMetadata) {
298+
for m := range cl.files.All() {
298299
seqNum = max(seqNum, m.LargestSeqNumAbsolute)
299-
})
300+
}
300301
}
301302
return seqNum
302303
}
@@ -313,8 +314,7 @@ func (c *compaction) makeInfo(jobID JobID) CompactionInfo {
313314
}
314315
for _, cl := range c.inputs {
315316
inputInfo := LevelInfo{Level: cl.level, Tables: nil}
316-
iter := cl.files.Iter()
317-
for m := iter.First(); m != nil; m = iter.Next() {
317+
for m := range cl.files.All() {
318318
inputInfo.Tables = append(inputInfo.Tables, m.TableInfo())
319319
}
320320
info.Input = append(info.Input, inputInfo)
@@ -454,9 +454,9 @@ func newDeleteOnlyCompaction(
454454
}
455455

456456
// Set c.smallest, c.largest.
457-
files := make([]manifest.LevelIterator, 0, len(inputs))
457+
files := make([]iter.Seq[*manifest.TableMetadata], 0, len(inputs))
458458
for _, in := range inputs {
459-
files = append(files, in.files.Iter())
459+
files = append(files, in.files.All())
460460
}
461461
c.smallest, c.largest = manifest.KeyRange(opts.Comparer.Compare, files...)
462462
return c
@@ -981,8 +981,7 @@ func (c *compaction) String() string {
981981
for level := c.startLevel.level; level <= c.outputLevel.level; level++ {
982982
i := level - c.startLevel.level
983983
fmt.Fprintf(&buf, "%d:", level)
984-
iter := c.inputs[i].files.Iter()
985-
for f := iter.First(); f != nil; f = iter.Next() {
984+
for f := range c.inputs[i].files.All() {
986985
fmt.Fprintf(&buf, " %s:%s-%s", f.FileNum, f.Smallest, f.Largest)
987986
}
988987
fmt.Fprintf(&buf, "\n")
@@ -1019,8 +1018,7 @@ func (d *DB) addInProgressCompaction(c *compaction) {
10191018
d.mu.compact.inProgress[c] = struct{}{}
10201019
var isBase, isIntraL0 bool
10211020
for _, cl := range c.inputs {
1022-
iter := cl.files.Iter()
1023-
for f := iter.First(); f != nil; f = iter.Next() {
1021+
for f := range cl.files.All() {
10241022
if f.IsCompacting() {
10251023
d.opts.Logger.Fatalf("L%d->L%d: %s already being compacted", c.startLevel.level, c.outputLevel.level, f.FileNum)
10261024
}
@@ -1057,8 +1055,7 @@ func (d *DB) addInProgressCompaction(c *compaction) {
10571055
func (d *DB) clearCompactingState(c *compaction, rollback bool) {
10581056
c.versionEditApplied = true
10591057
for _, cl := range c.inputs {
1060-
iter := cl.files.Iter()
1061-
for f := iter.First(); f != nil; f = iter.Next() {
1058+
for f := range cl.files.All() {
10621059
if !f.IsCompacting() {
10631060
d.opts.Logger.Fatalf("L%d->L%d: %s not being compacted", c.startLevel.level, c.outputLevel.level, f.FileNum)
10641061
}
@@ -1344,9 +1341,7 @@ func (d *DB) runIngestFlush(c *compaction) (*manifest.VersionEdit, error) {
13441341
// Iterate through all levels and find files that intersect with exciseSpan.
13451342
for l := range c.version.Levels {
13461343
overlaps := c.version.Overlaps(l, base.UserKeyBoundsEndExclusive(ingestFlushable.exciseSpan.Start, ingestFlushable.exciseSpan.End))
1347-
iter := overlaps.Iter()
1348-
1349-
for m := iter.First(); m != nil; m = iter.Next() {
1344+
for m := range overlaps.All() {
13501345
newFiles, err := d.excise(context.TODO(), ingestFlushable.exciseSpan.UserKeyBounds(), m, ve, l)
13511346
if err != nil {
13521347
return nil, err
@@ -1566,8 +1561,7 @@ func (d *DB) flush1() (bytesFlushed uint64, err error) {
15661561
// cancel the compaction.
15671562
for c2 := range d.mu.compact.inProgress {
15681563
for i := range c2.inputs {
1569-
iter := c2.inputs[i].files.Iter()
1570-
for f := iter.First(); f != nil; f = iter.Next() {
1564+
for f := range c2.inputs[i].files.All() {
15711565
if _, ok := ve.DeletedTables[deletedFileEntry{FileNum: f.FileNum, Level: c2.inputs[i].level}]; ok {
15721566
c2.cancel.Store(true)
15731567
break
@@ -2246,10 +2240,7 @@ func checkDeleteCompactionHints(
22462240
filesDeletedByCurrentHint := 0
22472241
var filesDeletedByLevel [7][]*tableMetadata
22482242
for l := h.tombstoneLevel + 1; l < numLevels; l++ {
2249-
overlaps := v.Overlaps(l, base.UserKeyBoundsEndExclusive(h.start, h.end))
2250-
iter := overlaps.Iter()
2251-
2252-
for m := iter.First(); m != nil; m = iter.Next() {
2243+
for m := range v.Overlaps(l, base.UserKeyBoundsEndExclusive(h.start, h.end)).All() {
22532244
doesHintApply := h.canDeleteOrExcise(cmp, m, snapshots, exciseEnabled)
22542245
if m.IsCompacting() || doesHintApply == hintDoesNotApply || files[m] {
22552246
continue
@@ -2768,17 +2759,16 @@ func (d *DB) runDeleteOnlyCompactionForLevel(
27682759
fragments []deleteCompactionHintFragment,
27692760
exciseEnabled bool,
27702761
) error {
2771-
curFragment := 0
2772-
iter := cl.files.Iter()
27732762
if cl.level == 0 {
27742763
panic("cannot run delete-only compaction for L0")
27752764
}
2765+
curFragment := 0
27762766

27772767
// Outer loop loops on files. Middle loop loops on fragments. Inner loop
27782768
// loops on raw fragments of hints. Number of fragments are bounded by
27792769
// the number of hints this compaction was created with, which is capped
27802770
// in the compaction picker to avoid very CPU-hot loops here.
2781-
for f := iter.First(); f != nil; f = iter.Next() {
2771+
for f := range cl.files.All() {
27822772
// curFile usually matches f, except if f got excised in which case
27832773
// it maps to a virtual file that replaces f, or nil if f got removed
27842774
// in its entirety.
@@ -3170,8 +3160,7 @@ func (c *compaction) makeVersionEdit(result compact.Result) (*versionEdit, error
31703160
DeletedTables: map[deletedFileEntry]*tableMetadata{},
31713161
}
31723162
for _, cl := range c.inputs {
3173-
iter := cl.files.Iter()
3174-
for f := iter.First(); f != nil; f = iter.Next() {
3163+
for f := range cl.files.All() {
31753164
ve.DeletedTables[deletedFileEntry{
31763165
Level: cl.level,
31773166
FileNum: f.FileNum,

compaction_picker.go

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package pebble
77
import (
88
"bytes"
99
"fmt"
10+
"iter"
1011
"math"
1112
"sort"
1213
"strings"
@@ -79,9 +80,9 @@ func (info compactionInfo) String() string {
7980
fmt.Fprintf(&buf, " -> ")
8081
}
8182
fmt.Fprintf(&buf, "L%d", in.level)
82-
in.files.Each(func(m *tableMetadata) {
83-
fmt.Fprintf(&buf, " %s", m.FileNum)
84-
})
83+
for f := range in.files.All() {
84+
fmt.Fprintf(&buf, " %s", f.FileNum)
85+
}
8586
if largest < in.level {
8687
largest = in.level
8788
}
@@ -148,8 +149,7 @@ func (cl sublevelInfo) String() string {
148149
// from the level slice for all of L0.
149150
func generateSublevelInfo(cmp base.Compare, levelFiles manifest.LevelSlice) []sublevelInfo {
150151
sublevelMap := make(map[uint64][]*tableMetadata)
151-
it := levelFiles.Iter()
152-
for f := it.First(); f != nil; f = it.Next() {
152+
for f := range levelFiles.All() {
153153
sublevelMap[uint64(f.SubLevel)] = append(sublevelMap[uint64(f.SubLevel)], f)
154154
}
155155

@@ -301,8 +301,7 @@ func newPickedCompactionFromL0(
301301
// because compactions built by L0SSTables do not necessarily
302302
// pick contiguous sequences of files in pc.version.Levels[0].
303303
files := make([]*manifest.TableMetadata, 0, len(lcf.Files))
304-
iter := vers.Levels[0].Iter()
305-
for f := iter.First(); f != nil; f = iter.Next() {
304+
for f := range vers.Levels[0].All() {
306305
if lcf.FilesIncluded[f.L0Index] {
307306
files = append(files, f)
308307
}
@@ -417,7 +416,7 @@ func (pc *pickedCompaction) setupInputs(
417416
return false
418417
}
419418

420-
pc.maybeExpandBounds(manifest.KeyRange(pc.cmp, startLevel.files.Iter()))
419+
pc.maybeExpandBounds(manifest.KeyRange(pc.cmp, startLevel.files.All()))
421420

422421
// Determine the sstables in the output level which overlap with the input
423422
// sstables. No need to do this for intra-L0 compactions; outputLevel.files is
@@ -429,7 +428,7 @@ func (pc *pickedCompaction) setupInputs(
429428
}
430429

431430
pc.maybeExpandBounds(manifest.KeyRange(pc.cmp,
432-
startLevel.files.Iter(), pc.outputLevel.files.Iter()))
431+
startLevel.files.All(), pc.outputLevel.files.All()))
433432
}
434433

435434
// Grow the sstables in startLevel.level as long as it doesn't affect the number
@@ -489,14 +488,14 @@ func (pc *pickedCompaction) setupInputs(
489488
if sizeSum+pc.outputLevel.files.SizeSum() < maxExpandedBytes {
490489
startLevel.files = manifest.NewLevelSliceSeqSorted(newStartLevelFiles)
491490
pc.smallest, pc.largest = manifest.KeyRange(pc.cmp,
492-
startLevel.files.Iter(), pc.outputLevel.files.Iter())
491+
startLevel.files.All(), pc.outputLevel.files.All())
493492
} else {
494493
*pc.lcf = *oldLcf
495494
}
496495
}
497496
} else if pc.grow(pc.smallest, pc.largest, maxExpandedBytes, startLevel) {
498497
pc.maybeExpandBounds(manifest.KeyRange(pc.cmp,
499-
startLevel.files.Iter(), pc.outputLevel.files.Iter()))
498+
startLevel.files.All(), pc.outputLevel.files.All()))
500499
}
501500

502501
if pc.startLevel.level == 0 {
@@ -528,7 +527,7 @@ func (pc *pickedCompaction) grow(
528527
}
529528
// We need to include the outputLevel iter because without it, in a multiLevel scenario,
530529
// sm1 and la1 could shift the output level keyspace when pc.outputLevel.files is set to grow1.
531-
sm1, la1 := manifest.KeyRange(pc.cmp, grow0.Iter(), pc.outputLevel.files.Iter())
530+
sm1, la1 := manifest.KeyRange(pc.cmp, grow0.All(), pc.outputLevel.files.All())
532531
grow1 := pc.version.Overlaps(pc.outputLevel.level, base.UserKeyBoundsFromInternal(sm1, la1))
533532
if anyTablesCompacting(grow1) {
534533
return false
@@ -566,8 +565,7 @@ func (pc *pickedCompaction) setupMultiLevelCandidate(opts *Options, diskAvailByt
566565
// anyTablesCompacting returns true if any tables in the level slice are
567566
// compacting.
568567
func anyTablesCompacting(inputs manifest.LevelSlice) bool {
569-
it := inputs.Iter()
570-
for f := it.First(); f != nil; f = it.Next() {
568+
for f := range inputs.All() {
571569
if f.IsCompacting() {
572570
return true
573571
}
@@ -649,9 +647,9 @@ var compensatedSizeAnnotator = manifest.SumAnnotator(func(f *tableMetadata) (uin
649647
// iterator. Note that this function is linear in the files available to the
650648
// iterator. Use the compensatedSizeAnnotator if querying the total
651649
// compensated size of a level.
652-
func totalCompensatedSize(iter manifest.LevelIterator) uint64 {
650+
func totalCompensatedSize(iter iter.Seq[*manifest.TableMetadata]) uint64 {
653651
var sz uint64
654-
for f := iter.First(); f != nil; f = iter.Next() {
652+
for f := range iter {
655653
sz += compensatedSize(f)
656654
}
657655
return sz
@@ -870,7 +868,7 @@ func calculateSizeAdjust(inProgressCompactions []compactionInfo) [numLevels]leve
870868

871869
for _, input := range c.inputs {
872870
actualSize := input.files.SizeSum()
873-
compensatedSize := totalCompensatedSize(input.files.Iter())
871+
compensatedSize := totalCompensatedSize(input.files.All())
874872

875873
if input.level != c.outputLevel {
876874
sizeAdjust[input.level].outgoingCompensatedBytes += compensatedSize
@@ -1231,7 +1229,7 @@ func (p *compactionPickerByScore) pickAuto(env compactionEnv) (pc *pickedCompact
12311229
marker, info.level, info.compensatedScoreRatio, info.compensatedScore,
12321230
info.uncompensatedScoreRatio, info.uncompensatedScore,
12331231
humanize.Bytes.Int64(int64(totalCompensatedSize(
1234-
p.vers.Levels[info.level].Iter(),
1232+
p.vers.Levels[info.level].All(),
12351233
))),
12361234
humanize.Bytes.Int64(p.levelMaxBytes[info.level]),
12371235
)
@@ -1461,11 +1459,11 @@ func (p *compactionPickerByScore) pickedCompactionFromCandidateFile(
14611459
}
14621460
if invariants.Enabled {
14631461
found := false
1464-
inputs.Each(func(f *tableMetadata) {
1462+
for f := range inputs.All() {
14651463
if f.FileNum == candidate.FileNum {
14661464
found = true
14671465
}
1468-
})
1466+
}
14691467
if !found {
14701468
panic(fmt.Sprintf("file %s not found in level %d as expected", candidate.FileNum, startLevel))
14711469
}
@@ -1474,7 +1472,7 @@ func (p *compactionPickerByScore) pickedCompactionFromCandidateFile(
14741472
pc := newPickedCompaction(p.opts, p.vers, startLevel, outputLevel, p.baseLevel)
14751473
pc.kind = kind
14761474
pc.startLevel.files = inputs
1477-
pc.smallest, pc.largest = manifest.KeyRange(pc.cmp, pc.startLevel.files.Iter())
1475+
pc.smallest, pc.largest = manifest.KeyRange(pc.cmp, pc.startLevel.files.All())
14781476

14791477
// Fail-safe to protect against compacting the same sstable concurrently.
14801478
if inputRangeAlreadyCompacting(env, pc) {
@@ -1604,7 +1602,7 @@ func pickAutoLPositive(
16041602
// Files in level 0 may overlap each other, so pick up all overlapping ones.
16051603
if pc.startLevel.level == 0 {
16061604
cmp := opts.Comparer.Compare
1607-
smallest, largest := manifest.KeyRange(cmp, pc.startLevel.files.Iter())
1605+
smallest, largest := manifest.KeyRange(cmp, pc.startLevel.files.All())
16081606
pc.startLevel.files = vers.Overlaps(0, base.UserKeyBoundsFromInternal(smallest, largest))
16091607
if pc.startLevel.files.Empty() {
16101608
panic("pebble: empty compaction")
@@ -1777,7 +1775,7 @@ func pickL0(env compactionEnv, opts *Options, vers *version, baseLevel int) *pic
17771775
}
17781776
// A single-file intra-L0 compaction is unproductive.
17791777
if iter := pc.startLevel.files.Iter(); iter.First() != nil && iter.Next() != nil {
1780-
pc.smallest, pc.largest = manifest.KeyRange(pc.cmp, pc.startLevel.files.Iter())
1778+
pc.smallest, pc.largest = manifest.KeyRange(pc.cmp, pc.startLevel.files.All())
17811779
return pc
17821780
}
17831781
} else {
@@ -1900,16 +1898,8 @@ func pickReadTriggeredCompactionHelper(
19001898
p *compactionPickerByScore, rc *readCompaction, env compactionEnv,
19011899
) (pc *pickedCompaction) {
19021900
overlapSlice := p.vers.Overlaps(rc.level, base.UserKeyBoundsInclusive(rc.start, rc.end))
1903-
if overlapSlice.Empty() {
1904-
// If there is no overlap, then the file with the key range
1905-
// must have been compacted away. So, we don't proceed to
1906-
// compact the same key range again.
1907-
return nil
1908-
}
1909-
1910-
iter := overlapSlice.Iter()
19111901
var fileMatches bool
1912-
for f := iter.First(); f != nil; f = iter.Next() {
1902+
for f := range overlapSlice.All() {
19131903
if f.FileNum == rc.fileNum {
19141904
fileMatches = true
19151905
break
@@ -1952,8 +1942,7 @@ func (p *compactionPickerByScore) forceBaseLevel1() {
19521942

19531943
func inputRangeAlreadyCompacting(env compactionEnv, pc *pickedCompaction) bool {
19541944
for _, cl := range pc.inputs {
1955-
iter := cl.files.Iter()
1956-
for f := iter.First(); f != nil; f = iter.Next() {
1945+
for f := range cl.files.All() {
19571946
if f.IsCompacting() {
19581947
return true
19591948
}

0 commit comments

Comments
 (0)