diff --git a/compaction.go b/compaction.go index e210da8185..196132fbac 100644 --- a/compaction.go +++ b/compaction.go @@ -733,7 +733,7 @@ func newCompaction( // Compute the set of outputLevel+1 files that overlap this compaction (these // are the grandparent sstables). if c.outputLevel.level+1 < numLevels { - c.grandparents = c.version.Overlaps(c.outputLevel.level+1, c.cmp, + c.grandparents = c.version.Overlaps(c.outputLevel.level+1, c.smallest.UserKey, c.largest.UserKey, c.largest.IsExclusiveSentinel()) } c.setupInuseKeyRanges() @@ -972,7 +972,7 @@ func newFlush( if opts.FlushSplitBytes > 0 { c.maxOutputFileSize = uint64(opts.Level(0).TargetFileSize) c.maxOverlapBytes = maxGrandparentOverlapBytes(opts, 0) - c.grandparents = c.version.Overlaps(baseLevel, c.cmp, c.smallest.UserKey, + c.grandparents = c.version.Overlaps(baseLevel, c.smallest.UserKey, c.largest.UserKey, c.largest.IsExclusiveSentinel()) adjustGrandparentOverlapBytesForFlush(c, flushingBytes) } @@ -1002,7 +1002,7 @@ func (c *compaction) setupInuseKeyRanges() { // calculateInuseKeyRanges will return a series of sorted spans. Overlapping // or abutting spans have already been merged. c.inuseKeyRanges = c.version.CalculateInuseKeyRanges( - c.cmp, level, numLevels-1, c.smallest.UserKey, c.largest.UserKey, + level, numLevels-1, c.smallest.UserKey, c.largest.UserKey, ) // Check if there's a single in-use span that encompasses the entire key // range of the compaction. This is an optimization to avoid key comparisons @@ -2176,7 +2176,7 @@ func (d *DB) maybeScheduleDownloadCompaction(env compactionEnv, maxConcurrentCom var err error var level int for i := range v.Levels { - overlaps := v.Overlaps(i, d.cmp, download.start, download.end, true /* exclusiveEnd */) + overlaps := v.Overlaps(i, download.start, download.end, true /* exclusiveEnd */) iter := overlaps.Iter() provider := d.objProvider for f := iter.First(); f != nil; f = iter.Next() { @@ -2565,7 +2565,7 @@ func checkDeleteCompactionHints( // The hint h will be resolved and dropped, regardless of whether // there are any tables that can be deleted. for l := h.tombstoneLevel + 1; l < numLevels; l++ { - overlaps := v.Overlaps(l, cmp, h.start, h.end, true /* exclusiveEnd */) + overlaps := v.Overlaps(l, h.start, h.end, true /* exclusiveEnd */) iter := overlaps.Iter() for m := iter.First(); m != nil; m = iter.Next() { if m.IsCompacting() || !h.canDelete(cmp, m, snapshots) || files[m] { diff --git a/compaction_picker.go b/compaction_picker.go index f4208b27db..578328c284 100644 --- a/compaction_picker.go +++ b/compaction_picker.go @@ -420,7 +420,7 @@ func (pc *pickedCompaction) setupInputs( // sstables. No need to do this for intra-L0 compactions; outputLevel.files is // left empty for those. if startLevel.level != pc.outputLevel.level { - pc.outputLevel.files = pc.version.Overlaps(pc.outputLevel.level, pc.cmp, pc.smallest.UserKey, + pc.outputLevel.files = pc.version.Overlaps(pc.outputLevel.level, pc.smallest.UserKey, pc.largest.UserKey, pc.largest.IsExclusiveSentinel()) if anyTablesCompacting(pc.outputLevel.files) { return false @@ -514,7 +514,7 @@ func (pc *pickedCompaction) grow( if pc.outputLevel.files.Empty() { return false } - grow0 := pc.version.Overlaps(startLevel.level, pc.cmp, sm.UserKey, + grow0 := pc.version.Overlaps(startLevel.level, sm.UserKey, la.UserKey, la.IsExclusiveSentinel()) if anyTablesCompacting(grow0) { return false @@ -528,7 +528,7 @@ func (pc *pickedCompaction) grow( // We need to include the outputLevel iter because without it, in a multiLevel scenario, // sm1 and la1 could shift the output level keyspace when pc.outputLevel.files is set to grow1. sm1, la1 := manifest.KeyRange(pc.cmp, grow0.Iter(), pc.outputLevel.files.Iter()) - grow1 := pc.version.Overlaps(pc.outputLevel.level, pc.cmp, sm1.UserKey, + grow1 := pc.version.Overlaps(pc.outputLevel.level, sm1.UserKey, la1.UserKey, la1.IsExclusiveSentinel()) if anyTablesCompacting(grow1) { return false @@ -1560,7 +1560,7 @@ func pickAutoLPositive( if pc.startLevel.level == 0 { cmp := opts.Comparer.Compare smallest, largest := manifest.KeyRange(cmp, pc.startLevel.files.Iter()) - pc.startLevel.files = vers.Overlaps(0, cmp, smallest.UserKey, + pc.startLevel.files = vers.Overlaps(0, smallest.UserKey, largest.UserKey, largest.IsExclusiveSentinel()) if pc.startLevel.files.Empty() { panic("pebble: empty compaction") @@ -1768,7 +1768,7 @@ func pickManualCompaction( } pc = newPickedCompaction(opts, vers, manual.level, defaultOutputLevel(manual.level, baseLevel), baseLevel) manual.outputLevel = pc.outputLevel.level - pc.startLevel.files = vers.Overlaps(manual.level, opts.Comparer.Compare, manual.start, manual.end, false) + pc.startLevel.files = vers.Overlaps(manual.level, manual.start, manual.end, false) if pc.startLevel.files.Empty() { // Nothing to do return nil, false @@ -1854,8 +1854,7 @@ func (p *compactionPickerByScore) pickReadTriggeredCompaction( func pickReadTriggeredCompactionHelper( p *compactionPickerByScore, rc *readCompaction, env compactionEnv, ) (pc *pickedCompaction) { - cmp := p.opts.Comparer.Compare - overlapSlice := p.vers.Overlaps(rc.level, cmp, rc.start, rc.end, false /* exclusiveEnd */) + overlapSlice := p.vers.Overlaps(rc.level, rc.start, rc.end, false /* exclusiveEnd */) if overlapSlice.Empty() { // If there is no overlap, then the file with the key range // must have been compacted away. So, we don't proceed to @@ -1888,7 +1887,7 @@ func pickReadTriggeredCompactionHelper( // Prevent read compactions which are too wide. outputOverlaps := pc.version.Overlaps( - pc.outputLevel.level, pc.cmp, pc.smallest.UserKey, + pc.outputLevel.level, pc.smallest.UserKey, pc.largest.UserKey, pc.largest.IsExclusiveSentinel()) if outputOverlaps.SizeSum() > pc.maxReadCompactionBytes { return nil diff --git a/compaction_picker_test.go b/compaction_picker_test.go index 4fcdf67d2e..d6940fe2d5 100644 --- a/compaction_picker_test.go +++ b/compaction_picker_test.go @@ -501,9 +501,8 @@ func TestCompactionPickerL0(t *testing.T) { version := newVersion(opts, fileMetas) version.L0Sublevels.InitCompactingFileInfo(inProgressL0Compactions(inProgressCompactions)) vs := &versionSet{ - opts: opts, - cmp: DefaultComparer.Compare, - cmpName: DefaultComparer.Name, + opts: opts, + cmp: DefaultComparer, } vs.versions.Init(nil) vs.append(version) @@ -725,9 +724,8 @@ func TestCompactionPickerConcurrency(t *testing.T) { version := newVersion(opts, fileMetas) version.L0Sublevels.InitCompactingFileInfo(inProgressL0Compactions(inProgressCompactions)) vs := &versionSet{ - opts: opts, - cmp: DefaultComparer.Compare, - cmpName: DefaultComparer.Name, + opts: opts, + cmp: DefaultComparer, } vs.versions.Init(nil) vs.append(version) @@ -843,9 +841,8 @@ func TestCompactionPickerPickReadTriggered(t *testing.T) { vers = newVersion(opts, fileMetas) vs := &versionSet{ - opts: opts, - cmp: DefaultComparer.Compare, - cmpName: DefaultComparer.Name, + opts: opts, + cmp: DefaultComparer, } vs.versions.Init(nil) vs.append(vers) @@ -1049,7 +1046,7 @@ func TestPickedCompactionSetupInputs(t *testing.T) { pc.outputLevel.level = pc.startLevel.level + 1 } pc.version = newVersion(opts, files) - pc.startLevel.files = pc.version.Overlaps(pc.startLevel.level, pc.cmp, + pc.startLevel.files = pc.version.Overlaps(pc.startLevel.level, []byte(args[0].String()), []byte(args[1].String()), false /* exclusiveEnd */) var isCompacting bool @@ -1263,9 +1260,8 @@ func TestCompactionOutputFileSize(t *testing.T) { vers = newVersion(opts, fileMetas) vs := &versionSet{ - opts: opts, - cmp: DefaultComparer.Compare, - cmpName: DefaultComparer.Name, + opts: opts, + cmp: DefaultComparer, } vs.versions.Init(nil) vs.append(vers) diff --git a/compaction_test.go b/compaction_test.go index b860d188d5..7c846a05cc 100644 --- a/compaction_test.go +++ b/compaction_test.go @@ -41,8 +41,7 @@ import ( func newVersion(opts *Options, files [numLevels][]*fileMetadata) *version { return manifest.NewVersion( - opts.Comparer.Compare, - opts.Comparer.FormatKey, + opts.Comparer, opts.FlushSplitBytes, files) } @@ -506,9 +505,8 @@ func TestPickCompaction(t *testing.T) { for _, tc := range testCases { vs := &versionSet{ - opts: opts, - cmp: DefaultComparer.Compare, - cmpName: DefaultComparer.Name, + opts: opts, + cmp: DefaultComparer, } vs.versions.Init(nil) vs.append(tc.version) @@ -566,7 +564,7 @@ func TestElideTombstone(t *testing.T) { return err.Error() } if td.HasArg("verbose") { - return d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + return d.mu.versions.currentVersion().DebugString() } return d.mu.versions.currentVersion().String() case "elide": @@ -1213,8 +1211,8 @@ func TestManualCompaction(t *testing.T) { ongoingCompaction.outputLevel = &ongoingCompaction.inputs[1] // Mark files as compacting. curr := d.mu.versions.currentVersion() - ongoingCompaction.startLevel.files = curr.Overlaps(startLevel, d.cmp, start, end, false) - ongoingCompaction.outputLevel.files = curr.Overlaps(outputLevel, d.cmp, start, end, false) + ongoingCompaction.startLevel.files = curr.Overlaps(startLevel, start, end, false) + ongoingCompaction.outputLevel.files = curr.Overlaps(outputLevel, start, end, false) for _, cl := range ongoingCompaction.inputs { iter := cl.files.Iter() for f := iter.First(); f != nil; f = iter.Next() { @@ -1268,7 +1266,7 @@ func TestManualCompaction(t *testing.T) { d.mu.Lock() s := d.mu.versions.currentVersion().String() if verbose { - s = d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + s = d.mu.versions.currentVersion().DebugString() } d.mu.Unlock() if td.HasArg("hide-file-num") { @@ -1303,7 +1301,7 @@ func TestManualCompaction(t *testing.T) { s := d.mu.versions.currentVersion().String() if verbose { - s = d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + s = d.mu.versions.currentVersion().DebugString() } return s @@ -1317,7 +1315,7 @@ func TestManualCompaction(t *testing.T) { d.mu.Lock() s := d.mu.versions.currentVersion().String() if verbose { - s = d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + s = d.mu.versions.currentVersion().DebugString() } d.mu.Unlock() return s @@ -1329,7 +1327,7 @@ func TestManualCompaction(t *testing.T) { d.mu.Lock() s := d.mu.versions.currentVersion().String() if verbose { - s = d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + s = d.mu.versions.currentVersion().DebugString() } d.mu.Unlock() return s @@ -1677,7 +1675,7 @@ func TestCompactionFindL0Limit(t *testing.T) { } } - vers = manifest.NewVersion(DefaultComparer.Compare, base.DefaultFormatter, flushSplitBytes, fileMetas) + vers = manifest.NewVersion(DefaultComparer, flushSplitBytes, fileMetas) flushSplitKeys := vers.L0Sublevels.FlushSplitKeys() var buf strings.Builder @@ -1726,7 +1724,7 @@ func TestCompactionFindL0Limit(t *testing.T) { func TestCompactionOutputLevel(t *testing.T) { opts := (*Options)(nil).EnsureDefaults() - version := &version{} + version := manifest.TestingNewVersion(opts.Comparer) datadriven.RunTest(t, "testdata/compaction_output_level", func(t *testing.T, d *datadriven.TestData) (res string) { @@ -2493,14 +2491,14 @@ func TestCompactionInuseKeyRangesRandomized(t *testing.T) { }) } v := newVersion(opts, files) - t.Log(v.DebugString(opts.Comparer.FormatKey)) + t.Log(v.DebugString()) for i := 0; i < 1000; i++ { l := rng.Intn(numLevels) s := rng.Intn(endKeyspace) maxWidth := rng.Intn(endKeyspace-s) + 1 e := rng.Intn(maxWidth) + s sKey, eKey := makeUserKey(s), makeUserKey(e) - keyRanges := v.CalculateInuseKeyRanges(opts.Comparer.Compare, l, numLevels-1, sKey, eKey) + keyRanges := v.CalculateInuseKeyRanges(l, numLevels-1, sKey, eKey) for level := l; level < numLevels; level++ { for _, f := range files[level] { @@ -3172,7 +3170,6 @@ func TestCompactionInvalidBounds(t *testing.T) { func Test_calculateInuseKeyRanges(t *testing.T) { opts := (*Options)(nil).EnsureDefaults() - cmp := base.DefaultComparer.Compare newFileMeta := func(fileNum FileNum, size uint64, smallest, largest base.InternalKey) *fileMetadata { m := (&fileMetadata{ FileNum: fileNum, @@ -3401,7 +3398,7 @@ func Test_calculateInuseKeyRanges(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.v.CalculateInuseKeyRanges(cmp, tt.level, tt.depth, tt.smallest, tt.largest); !reflect.DeepEqual(got, tt.want) { + if got := tt.v.CalculateInuseKeyRanges(tt.level, tt.depth, tt.smallest, tt.largest); !reflect.DeepEqual(got, tt.want) { t.Errorf("CalculateInuseKeyRanges() = %v, want %v", got, tt.want) } }) @@ -3468,7 +3465,7 @@ func TestMarkedForCompaction(t *testing.T) { t = t.Add(time.Second) return t } - s := d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + s := d.mu.versions.currentVersion().DebugString() return s case "mark-for-compaction": @@ -3500,7 +3497,7 @@ func TestMarkedForCompaction(t *testing.T) { d.mu.compact.cond.Wait() } - fmt.Fprintln(&buf, d.mu.versions.currentVersion().DebugString(base.DefaultFormatter)) + fmt.Fprintln(&buf, d.mu.versions.currentVersion().DebugString()) s := strings.TrimSpace(buf.String()) buf.Reset() opts.DisableAutomaticCompactions = true diff --git a/data_test.go b/data_test.go index 5ab1f117c6..286d6d9fb6 100644 --- a/data_test.go +++ b/data_test.go @@ -1337,7 +1337,7 @@ func runLSMCmd(td *datadriven.TestData, d *DB) string { d.mu.Lock() defer d.mu.Unlock() if td.HasArg("verbose") { - return d.mu.versions.currentVersion().DebugString(d.opts.Comparer.FormatKey) + return d.mu.versions.currentVersion().DebugString() } return d.mu.versions.currentVersion().String() } diff --git a/db.go b/db.go index 61538346ac..817b9ecc93 100644 --- a/db.go +++ b/db.go @@ -1742,7 +1742,7 @@ func (d *DB) Compact(start, end []byte, parallelize bool) error { maxLevelWithFiles := 1 cur := d.mu.versions.currentVersion() for level := 0; level < numLevels; level++ { - overlaps := cur.Overlaps(level, d.cmp, start, end, false) + overlaps := cur.Overlaps(level, start, end, false) if !overlaps.Empty() { maxLevelWithFiles = level + 1 } @@ -1819,7 +1819,7 @@ func (d *DB) Compact(start, end []byte, parallelize bool) error { func (d *DB) manualCompact(start, end []byte, level int, parallelize bool) error { d.mu.Lock() curr := d.mu.versions.currentVersion() - files := curr.Overlaps(level, d.cmp, start, end, false) + files := curr.Overlaps(level, start, end, false) if files.Empty() { d.mu.Unlock() return nil @@ -1866,7 +1866,7 @@ func (d *DB) splitManualCompaction( if level == 0 { endLevel = baseLevel } - keyRanges := curr.CalculateInuseKeyRanges(d.cmp, level, endLevel, start, end) + keyRanges := curr.CalculateInuseKeyRanges(level, endLevel, start, end) for _, keyRange := range keyRanges { splitCompactions = append(splitCompactions, &manualCompaction{ level: level, @@ -1931,7 +1931,7 @@ func (d *DB) downloadSpan(ctx context.Context, span DownloadSpan) error { if vers.Levels[i].Empty() { continue } - overlap := vers.Overlaps(i, d.cmp, span.StartKey, span.EndKey, true /* exclusiveEnd */) + overlap := vers.Overlaps(i, span.StartKey, span.EndKey, true /* exclusiveEnd */) foundExternalFile := false overlap.Each(func(metadata *manifest.FileMetadata) { objMeta, err := d.objProvider.Lookup(fileTypeTable, metadata.FileBacking.DiskFileNum) @@ -2407,7 +2407,7 @@ func (d *DB) EstimateDiskUsageByBackingType( // We can only use `Overlaps` to restrict `files` at L1+ since at L0 it // expands the range iteratively until it has found a set of files that // do not overlap any other L0 files outside that set. - overlaps := readState.current.Overlaps(level, d.opts.Comparer.Compare, start, end, false /* exclusiveEnd */) + overlaps := readState.current.Overlaps(level, start, end, false /* exclusiveEnd */) iter = overlaps.Iter() } for file := iter.First(); file != nil; file = iter.Next() { @@ -3087,5 +3087,5 @@ func (d *DB) checkVirtualBounds(m *fileMetadata) { func (d *DB) DebugString() string { d.mu.Lock() defer d.mu.Unlock() - return d.mu.versions.currentVersion().DebugString(base.DefaultFormatter) + return d.mu.versions.currentVersion().DebugString() } diff --git a/get_iter_test.go b/get_iter_test.go index a0c93d0118..1becb1dad9 100644 --- a/get_iter_test.go +++ b/get_iter_test.go @@ -379,7 +379,7 @@ func TestGetIter(t *testing.T) { }, } - cmp := testkeys.Comparer.Compare + cmp := testkeys.Comparer for _, tc := range testCases { desc := tc.description[:strings.Index(tc.description, ":")] @@ -412,7 +412,7 @@ func TestGetIter(t *testing.T) { t.Fatalf("desc=%q: memtable Set: %v", desc, err) } - meta.ExtendPointKeyBounds(cmp, ikey, ikey) + meta.ExtendPointKeyBounds(cmp.Compare, ikey, ikey) if i == 0 { meta.SmallestSeqNum = ikey.SeqNum() meta.LargestSeqNum = ikey.SeqNum() @@ -428,8 +428,8 @@ func TestGetIter(t *testing.T) { files[tt.level] = append(files[tt.level], meta) } - v := manifest.NewVersion(cmp, base.DefaultFormatter, 10<<20, files) - err := v.CheckOrdering(cmp, base.DefaultFormatter) + v := manifest.NewVersion(cmp, 10<<20, files) + err := v.CheckOrdering() if tc.badOrdering && err == nil { t.Errorf("desc=%q: want bad ordering, got nil error", desc) continue diff --git a/ingest.go b/ingest.go index e96299dc00..2ad6a5f8bc 100644 --- a/ingest.go +++ b/ingest.go @@ -172,7 +172,7 @@ func ingestSynthesizeShared( // ingestLoad1External loads the fileMetadata for one external sstable. // Sequence number and target level calculation happens during prepare/apply. func ingestLoad1External( - opts *Options, e ExternalFile, fileNum base.FileNum, objProvider objstorage.Provider, jobID int, + opts *Options, e ExternalFile, fileNum base.FileNum, ) (*fileMetadata, error) { if e.Size == 0 { // Disallow 0 file sizes @@ -474,7 +474,7 @@ func ingestLoad( } result.external = make([]ingestExternalMeta, 0, len(external)) for i := range external { - m, err := ingestLoad1External(opts, external[i], externalFileNums[i], objProvider, jobID) + m, err := ingestLoad1External(opts, external[i], externalFileNums[i]) if err != nil { return ingestLoadResult{}, err } @@ -961,7 +961,7 @@ func ingestTargetLevel( // Check boundary overlap. var candidateSplitFile *fileMetadata - boundaryOverlaps := v.Overlaps(level, comparer.Compare, meta.Smallest.UserKey, + boundaryOverlaps := v.Overlaps(level, meta.Smallest.UserKey, meta.Largest.UserKey, meta.Largest.IsExclusiveSentinel()) if !boundaryOverlaps.Empty() { // We are already guaranteed to not have any data overlaps with files @@ -2284,7 +2284,7 @@ func (d *DB) ingestApply( // for files, and if they are, we should signal those compactions to error // out. for level := range current.Levels { - overlaps := current.Overlaps(level, d.cmp, exciseSpan.Start, exciseSpan.End, true /* exclusiveEnd */) + overlaps := current.Overlaps(level, exciseSpan.Start, exciseSpan.End, true /* exclusiveEnd */) iter := overlaps.Iter() for m := iter.First(); m != nil; m = iter.Next() { @@ -2458,7 +2458,7 @@ func (d *DB) validateSSTables() { for _, f := range pending { // The file may have been moved or deleted since it was ingested, in // which case we skip. - if !rs.current.Contains(f.Level, d.cmp, f.Meta) { + if !rs.current.Contains(f.Level, f.Meta) { // Assume the file was moved to a lower level. It is rare enough // that a table is moved or deleted between the time it was ingested // and the time the validation routine runs that the overall cost of @@ -2466,7 +2466,7 @@ func (d *DB) validateSSTables() { // ingested tables. found := false for i := f.Level + 1; i < numLevels; i++ { - if rs.current.Contains(i, d.cmp, f.Meta) { + if rs.current.Contains(i, f.Meta) { found = true break } diff --git a/ingest_test.go b/ingest_test.go index b4f34a2d65..8d6fbe7522 100644 --- a/ingest_test.go +++ b/ingest_test.go @@ -3624,6 +3624,6 @@ func runBenchmarkManySSTablesInUseKeyRanges(b *testing.B, d *DB, count int) { smallest := []byte("0") largest := []byte("z") for i := 0; i < b.N; i++ { - _ = v.CalculateInuseKeyRanges(d.cmp, 0, numLevels-1, smallest, largest) + _ = v.CalculateInuseKeyRanges(0, numLevels-1, smallest, largest) } } diff --git a/internal/keyspan/keyspanimpl/level_iter_test.go b/internal/keyspan/keyspanimpl/level_iter_test.go index 019270acf6..5205642a2b 100644 --- a/internal/keyspan/keyspanimpl/level_iter_test.go +++ b/internal/keyspan/keyspanimpl/level_iter_test.go @@ -310,7 +310,7 @@ func TestLevelIterEquivalence(t *testing.T) { amap[metas[i].FileNum] = metas[i] } b.Added[6] = amap - v, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0, nil) + v, err := b.Apply(nil, base.DefaultComparer, 0, 0, nil) require.NoError(t, err) levelIter.Init( keyspan.SpanIterOptions{}, base.DefaultComparer.Compare, tableNewIters, @@ -454,7 +454,7 @@ func TestLevelIter(t *testing.T) { amap[metas[i].FileNum] = metas[i] } b.Added[6] = amap - v, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0, nil) + v, err := b.Apply(nil, base.DefaultComparer, 0, 0, nil) require.NoError(t, err) iter = NewLevelIter( keyspan.SpanIterOptions{}, base.DefaultComparer.Compare, diff --git a/internal/manifest/l0_sublevels_test.go b/internal/manifest/l0_sublevels_test.go index 2b007fca9e..f944077eda 100644 --- a/internal/manifest/l0_sublevels_test.go +++ b/internal/manifest/l0_sublevels_test.go @@ -51,7 +51,7 @@ func readManifest(filename string) (*Version, error) { if err := bve.Accumulate(&ve); err != nil { return nil, err } - if v, err = bve.Apply(v, base.DefaultComparer.Compare, base.DefaultFormatter, 10<<20, 32000, nil); err != nil { + if v, err = bve.Apply(v, base.DefaultComparer, 10<<20, 32000, nil); err != nil { return nil, err } } diff --git a/internal/manifest/manifest_test.go b/internal/manifest/manifest_test.go index 700c2297e1..e159a99f06 100644 --- a/internal/manifest/manifest_test.go +++ b/internal/manifest/manifest_test.go @@ -41,7 +41,7 @@ func TestInuseKeyRangesRandomized(t *testing.T) { } t.Log("Constructed test database state") v := replayManifest(t, testOpts.Opts, "") - t.Log(v.DebugString(base.DefaultFormatter)) + t.Log(v.DebugString()) const maxKeyLen = 12 const maxSuffix = 20 @@ -59,14 +59,14 @@ func TestInuseKeyRangesRandomized(t *testing.T) { level := rng.Intn(manifest.NumLevels) cmp := testOpts.Opts.Comparer.Compare - keyRanges := v.CalculateInuseKeyRanges(cmp, level, manifest.NumLevels-1, smallest, largest) + keyRanges := v.CalculateInuseKeyRanges(level, manifest.NumLevels-1, smallest, largest) t.Logf("%d: [%s, %s] levels L%d-L6: ", i, smallest, largest, level) for _, kr := range keyRanges { t.Logf(" [%s,%s]", kr.Start, kr.End) } for l := level; l < manifest.NumLevels; l++ { - o := v.Overlaps(l, cmp, smallest, largest, false /* exclusiveEnd */) + o := v.Overlaps(l, smallest, largest, false /* exclusiveEnd */) iter := o.Iter() for f := iter.First(); f != nil; f = iter.Next() { // CalculateInuseKeyRanges only guarantees that it returns key @@ -123,7 +123,7 @@ func replayManifest(t *testing.T, opts *pebble.Options, dirname string) *manifes require.NoError(t, bve.Accumulate(&ve)) } v, err := bve.Apply( - nil /* version */, cmp.Compare, base.DefaultFormatter, opts.FlushSplitBytes, + nil /* version */, cmp, opts.FlushSplitBytes, opts.Experimental.ReadCompactionRate, nil /* zombies */) require.NoError(t, err) return v diff --git a/internal/manifest/version.go b/internal/manifest/version.go index 4cccff82e7..8f39c75f70 100644 --- a/internal/manifest/version.go +++ b/internal/manifest/version.go @@ -1066,9 +1066,11 @@ const NumLevels = 7 // NewVersion constructs a new Version with the provided files. It requires // the provided files are already well-ordered. It's intended for testing. func NewVersion( - cmp Compare, formatKey base.FormatKey, flushSplitBytes int64, files [NumLevels][]*FileMetadata, + comparer *base.Comparer, flushSplitBytes int64, files [NumLevels][]*FileMetadata, ) *Version { - var v Version + v := &Version{ + cmp: comparer, + } for l := range files { // NB: We specifically insert `files` into the B-Tree in the order // they appear within `files`. Some tests depend on this behavior in @@ -1080,16 +1082,23 @@ func NewVersion( if l == 0 { v.Levels[l].tree.cmp = btreeCmpSeqNum } else { - v.Levels[l].tree.cmp = btreeCmpSmallestKey(cmp) + v.Levels[l].tree.cmp = btreeCmpSmallestKey(comparer.Compare) } for _, f := range files[l] { v.Levels[l].totalSize += f.Size } } - if err := v.InitL0Sublevels(cmp, formatKey, flushSplitBytes); err != nil { + if err := v.InitL0Sublevels(flushSplitBytes); err != nil { panic(err) } - return &v + return v +} + +// TestingNewVersion returns a blank Version, used for tests. +func TestingNewVersion(comparer *base.Comparer) *Version { + return &Version{ + cmp: comparer, + } } // Version is a collection of file metadata for on-disk tables at various @@ -1159,6 +1168,8 @@ type Version struct { MarkedForCompaction int } + cmp *base.Comparer + // The list the version is linked into. list *VersionList @@ -1169,13 +1180,13 @@ type Version struct { // String implements fmt.Stringer, printing the FileMetadata for each level in // the Version. func (v *Version) String() string { - return v.string(base.DefaultFormatter, false) + return v.string(false) } // DebugString returns an alternative format to String() which includes sequence // number and kind information for the sstable boundaries. -func (v *Version) DebugString(format base.FormatKey) string { - return v.string(format, true) +func (v *Version) DebugString() string { + return v.string(true) } func describeSublevels(format base.FormatKey, verbose bool, sublevels []LevelSlice) string { @@ -1189,10 +1200,10 @@ func describeSublevels(format base.FormatKey, verbose bool, sublevels []LevelSli return buf.String() } -func (v *Version) string(format base.FormatKey, verbose bool) string { +func (v *Version) string(verbose bool) string { var buf bytes.Buffer if len(v.L0SublevelFiles) > 0 { - fmt.Fprintf(&buf, "%s", describeSublevels(format, verbose, v.L0SublevelFiles)) + fmt.Fprintf(&buf, "%s", describeSublevels(v.cmp.FormatKey, verbose, v.L0SublevelFiles)) } for level := 1; level < NumLevels; level++ { if v.Levels[level].Empty() { @@ -1201,16 +1212,14 @@ func (v *Version) string(format base.FormatKey, verbose bool) string { fmt.Fprintf(&buf, "%d:\n", level) iter := v.Levels[level].Iter() for f := iter.First(); f != nil; f = iter.Next() { - fmt.Fprintf(&buf, " %s\n", f.DebugString(format, verbose)) + fmt.Fprintf(&buf, " %s\n", f.DebugString(v.cmp.FormatKey, verbose)) } } return buf.String() } // ParseVersionDebug parses a Version from its DebugString output. -func ParseVersionDebug( - cmp Compare, formatKey base.FormatKey, flushSplitBytes int64, s string, -) (*Version, error) { +func ParseVersionDebug(comparer *base.Comparer, flushSplitBytes int64, s string) (*Version, error) { var level int var files [NumLevels][]*FileMetadata for _, l := range strings.Split(s, "\n") { @@ -1242,7 +1251,7 @@ func ParseVersionDebug( for i := 0; i < len(files[0])/2; i++ { files[0][i], files[0][len(files[0])-i-1] = files[0][len(files[0])-i-1], files[0][i] } - return NewVersion(cmp, formatKey, flushSplitBytes, files), nil + return NewVersion(comparer, flushSplitBytes, files), nil } // Refs returns the number of references to the version. @@ -1297,11 +1306,9 @@ func (v *Version) Next() *Version { } // InitL0Sublevels initializes the L0Sublevels -func (v *Version) InitL0Sublevels( - cmp Compare, formatKey base.FormatKey, flushSplitBytes int64, -) error { +func (v *Version) InitL0Sublevels(flushSplitBytes int64) error { var err error - v.L0Sublevels, err = NewL0Sublevels(&v.Levels[0], cmp, formatKey, flushSplitBytes) + v.L0Sublevels, err = NewL0Sublevels(&v.Levels[0], v.cmp.Compare, v.cmp.FormatKey, flushSplitBytes) if err == nil && v.L0Sublevels != nil { v.L0SublevelFiles = v.L0Sublevels.Levels } @@ -1313,7 +1320,7 @@ func (v *Version) InitL0Sublevels( // that include all keys that exist within levels [level, maxLevel] and within // [smallest,largest]. func (v *Version) CalculateInuseKeyRanges( - cmp base.Compare, level, maxLevel int, smallest, largest []byte, + level, maxLevel int, smallest, largest []byte, ) []UserKeyRange { // Use two slices, alternating which one is input and which one is output // as we descend the LSM. @@ -1331,7 +1338,7 @@ func (v *Version) CalculateInuseKeyRanges( // NB: We always treat `largest` as inclusive for simplicity, because // there's little consequence to calculating slightly broader in-use key // ranges. - overlaps := v.Overlaps(level, cmp, smallest, largest, false /* exclusiveEnd */) + overlaps := v.Overlaps(level, smallest, largest, false /* exclusiveEnd */) iter := overlaps.Iter() // We may already have in-use key ranges from higher levels. Iterate @@ -1351,11 +1358,12 @@ func (v *Version) CalculateInuseKeyRanges( if len(input) > 0 { currAccum, input = &input[0], input[1:] } + cmp := v.cmp.Compare // If we have an accumulated key range and its start is ≤ smallest, // we can seek to the accumulated range's end. Otherwise, we need to // start at the first overlapping file within the level. - if currAccum != nil && cmp(currAccum.Start, smallest) <= 0 { + if currAccum != nil && v.cmp.Compare(currAccum.Start, smallest) <= 0 { currFile = seekGT(&iter, cmp, currAccum.End) } else { currFile = iter.First() @@ -1425,11 +1433,10 @@ func seekGT(iter *LevelIterator, cmp base.Compare, key []byte) *FileMetadata { // the version at the given level. If level is non-zero then Contains binary // searches among the files. If level is zero, Contains scans the entire // level. -func (v *Version) Contains(level int, cmp Compare, m *FileMetadata) bool { +func (v *Version) Contains(level int, m *FileMetadata) bool { iter := v.Levels[level].Iter() if level > 0 { - overlaps := v.Overlaps(level, cmp, m.Smallest.UserKey, m.Largest.UserKey, - m.Largest.IsExclusiveSentinel()) + overlaps := v.Overlaps(level, m.Smallest.UserKey, m.Largest.UserKey, m.Largest.IsExclusiveSentinel()) iter = overlaps.Iter() } for f := iter.First(); f != nil; f = iter.Next() { @@ -1448,9 +1455,7 @@ func (v *Version) Contains(level int, cmp Compare, m *FileMetadata) bool { // repeated until [start, end] stabilizes. // The returned files are a subsequence of the input files, i.e., the ordering // is not changed. -func (v *Version) Overlaps( - level int, cmp Compare, start, end []byte, exclusiveEnd bool, -) LevelSlice { +func (v *Version) Overlaps(level int, start, end []byte, exclusiveEnd bool) LevelSlice { if level == 0 { // Indices that have been selected as overlapping. l0 := v.Levels[level] @@ -1465,7 +1470,7 @@ func (v *Version) Overlaps( if selected { continue } - if !meta.Overlaps(cmp, start, end, exclusiveEnd) { + if !meta.Overlaps(v.cmp.Compare, start, end, exclusiveEnd) { // meta is completely outside the specified range; skip it. continue } @@ -1480,11 +1485,11 @@ func (v *Version) Overlaps( // we have remaining to check in this loop. All already checked // and unselected files will need to be rechecked via the // restart below. - if cmp(smallest, start) < 0 { + if v.cmp.Compare(smallest, start) < 0 { start = smallest restart = true } - if v := cmp(largest, end); v > 0 { + if v := v.cmp.Compare(largest, end); v > 0 { end = largest exclusiveEnd = meta.Largest.IsExclusiveSentinel() restart = true @@ -1520,23 +1525,23 @@ func (v *Version) Overlaps( return slice } - return overlaps(v.Levels[level].Iter(), cmp, start, end, exclusiveEnd) + return overlaps(v.Levels[level].Iter(), v.cmp.Compare, start, end, exclusiveEnd) } // CheckOrdering checks that the files are consistent with respect to // increasing file numbers (for level 0 files) and increasing and non- // overlapping internal key ranges (for level non-0 files). -func (v *Version) CheckOrdering(cmp Compare, format base.FormatKey) error { +func (v *Version) CheckOrdering() error { for sublevel := len(v.L0SublevelFiles) - 1; sublevel >= 0; sublevel-- { sublevelIter := v.L0SublevelFiles[sublevel].Iter() - if err := CheckOrdering(cmp, format, L0Sublevel(sublevel), sublevelIter); err != nil { - return base.CorruptionErrorf("%s\n%s", err, v.DebugString(format)) + if err := CheckOrdering(v.cmp.Compare, v.cmp.FormatKey, L0Sublevel(sublevel), sublevelIter); err != nil { + return base.CorruptionErrorf("%s\n%s", err, v.DebugString()) } } for level, lm := range v.Levels { - if err := CheckOrdering(cmp, format, Level(level), lm.Iter()); err != nil { - return base.CorruptionErrorf("%s\n%s", err, v.DebugString(format)) + if err := CheckOrdering(v.cmp.Compare, v.cmp.FormatKey, Level(level), lm.Iter()); err != nil { + return base.CorruptionErrorf("%s\n%s", err, v.DebugString()) } } return nil diff --git a/internal/manifest/version_edit.go b/internal/manifest/version_edit.go index 87763512a9..6c60cf10ef 100644 --- a/internal/manifest/version_edit.go +++ b/internal/manifest/version_edit.go @@ -889,8 +889,7 @@ func (b *BulkVersionEdit) Accumulate(ve *VersionEdit) error { func AccumulateIncompleteAndApplySingleVE( ve *VersionEdit, curr *Version, - cmp Compare, - formatKey base.FormatKey, + comparer *base.Comparer, flushSplitBytes int64, readCompactionRate int64, backingStateMap map[base.DiskFileNum]*FileBacking, @@ -906,7 +905,7 @@ func AccumulateIncompleteAndApplySingleVE( return nil, nil, err } zombies = make(map[base.DiskFileNum]uint64) - v, err := b.Apply(curr, cmp, formatKey, flushSplitBytes, readCompactionRate, zombies) + v, err := b.Apply(curr, comparer, flushSplitBytes, readCompactionRate, zombies) if err != nil { return nil, nil, err } @@ -941,8 +940,7 @@ func AccumulateIncompleteAndApplySingleVE( // incoming Version. func (b *BulkVersionEdit) Apply( curr *Version, - cmp Compare, - formatKey base.FormatKey, + comparer *base.Comparer, flushSplitBytes int64, readCompactionRate int64, zombies map[base.DiskFileNum]uint64, @@ -958,7 +956,9 @@ func (b *BulkVersionEdit) Apply( } } - v := new(Version) + v := &Version{ + cmp: comparer, + } // Adjust the count of files marked for compaction. if curr != nil { @@ -971,12 +971,12 @@ func (b *BulkVersionEdit) Apply( for level := range v.Levels { if curr == nil || curr.Levels[level].tree.root == nil { - v.Levels[level] = makeLevelMetadata(cmp, level, nil /* files */) + v.Levels[level] = makeLevelMetadata(comparer.Compare, level, nil /* files */) } else { v.Levels[level] = curr.Levels[level].clone() } if curr == nil || curr.RangeKeyLevels[level].tree.root == nil { - v.RangeKeyLevels[level] = makeLevelMetadata(cmp, level, nil /* files */) + v.RangeKeyLevels[level] = makeLevelMetadata(comparer.Compare, level, nil /* files */) } else { v.RangeKeyLevels[level] = curr.RangeKeyLevels[level].clone() } @@ -986,7 +986,7 @@ func (b *BulkVersionEdit) Apply( if level == 0 { // Initialize L0Sublevels. if curr == nil || curr.L0Sublevels == nil { - if err := v.InitL0Sublevels(cmp, formatKey, flushSplitBytes); err != nil { + if err := v.InitL0Sublevels(flushSplitBytes); err != nil { return nil, errors.Wrap(err, "pebble: internal error") } } else { @@ -1092,10 +1092,10 @@ func (b *BulkVersionEdit) Apply( removeZombie(f.FileBacking) // Track the keys with the smallest and largest keys, so that we can // check consistency of the modified span. - if sm == nil || base.InternalCompare(cmp, sm.Smallest, f.Smallest) > 0 { + if sm == nil || base.InternalCompare(comparer.Compare, sm.Smallest, f.Smallest) > 0 { sm = f } - if la == nil || base.InternalCompare(cmp, la.Largest, f.Largest) < 0 { + if la == nil || base.InternalCompare(comparer.Compare, la.Largest, f.Largest) < 0 { la = f } } @@ -1110,18 +1110,18 @@ func (b *BulkVersionEdit) Apply( SortBySeqNum(addedFiles) v.L0Sublevels, err = curr.L0Sublevels.AddL0Files(addedFiles, flushSplitBytes, &v.Levels[0]) if errors.Is(err, errInvalidL0SublevelsOpt) { - err = v.InitL0Sublevels(cmp, formatKey, flushSplitBytes) + err = v.InitL0Sublevels(flushSplitBytes) } else if invariants.Enabled && err == nil { - copyOfSublevels, err := NewL0Sublevels(&v.Levels[0], cmp, formatKey, flushSplitBytes) + copyOfSublevels, err := NewL0Sublevels(&v.Levels[0], comparer.Compare, comparer.FormatKey, flushSplitBytes) if err != nil { panic(fmt.Sprintf("error when regenerating sublevels: %s", err)) } - s1 := describeSublevels(base.DefaultFormatter, false /* verbose */, copyOfSublevels.Levels) - s2 := describeSublevels(base.DefaultFormatter, false /* verbose */, v.L0Sublevels.Levels) + s1 := describeSublevels(comparer.FormatKey, false /* verbose */, copyOfSublevels.Levels) + s2 := describeSublevels(comparer.FormatKey, false /* verbose */, v.L0Sublevels.Levels) if s1 != s2 { // Add verbosity. - s1 := describeSublevels(base.DefaultFormatter, true /* verbose */, copyOfSublevels.Levels) - s2 := describeSublevels(base.DefaultFormatter, true /* verbose */, v.L0Sublevels.Levels) + s1 := describeSublevels(comparer.FormatKey, true /* verbose */, copyOfSublevels.Levels) + s2 := describeSublevels(comparer.FormatKey, true /* verbose */, v.L0Sublevels.Levels) panic(fmt.Sprintf("incremental L0 sublevel generation produced different output than regeneration: %s != %s", s1, s2)) } } @@ -1129,10 +1129,10 @@ func (b *BulkVersionEdit) Apply( return nil, errors.Wrap(err, "pebble: internal error") } v.L0SublevelFiles = v.L0Sublevels.Levels - } else if err := v.InitL0Sublevels(cmp, formatKey, flushSplitBytes); err != nil { + } else if err := v.InitL0Sublevels(flushSplitBytes); err != nil { return nil, errors.Wrap(err, "pebble: internal error") } - if err := CheckOrdering(cmp, formatKey, Level(0), v.Levels[level].Iter()); err != nil { + if err := CheckOrdering(comparer.Compare, comparer.FormatKey, Level(0), v.Levels[level].Iter()); err != nil { return nil, errors.Wrap(err, "pebble: internal error") } continue @@ -1140,7 +1140,7 @@ func (b *BulkVersionEdit) Apply( // Check consistency of the level in the vicinity of our edits. if sm != nil && la != nil { - overlap := overlaps(v.Levels[level].Iter(), cmp, sm.Smallest.UserKey, + overlap := overlaps(v.Levels[level].Iter(), comparer.Compare, sm.Smallest.UserKey, la.Largest.UserKey, la.Largest.IsExclusiveSentinel()) // overlap contains all of the added files. We want to ensure that // the added files are consistent with neighboring existing files @@ -1153,7 +1153,7 @@ func (b *BulkVersionEdit) Apply( end.Prev() } }) - if err := CheckOrdering(cmp, formatKey, Level(level), check.Iter()); err != nil { + if err := CheckOrdering(comparer.Compare, comparer.FormatKey, Level(level), check.Iter()); err != nil { return nil, errors.Wrap(err, "pebble: internal error") } } diff --git a/internal/manifest/version_edit_test.go b/internal/manifest/version_edit_test.go index 8035d60b3d..e0a83e0ae6 100644 --- a/internal/manifest/version_edit_test.go +++ b/internal/manifest/version_edit_test.go @@ -486,7 +486,7 @@ func TestVersionEditApply(t *testing.T) { } if isVersion { if v == nil { - v = new(Version) + v = &Version{cmp: base.DefaultComparer} for l := 0; l < NumLevels; l++ { v.Levels[l] = makeLevelMetadata(base.DefaultComparer.Compare, l, nil /* files */) } @@ -512,8 +512,9 @@ func TestVersionEditApply(t *testing.T) { } } + const flushSplitBytes = 10 * 1024 * 1024 if v != nil { - if err := v.InitL0Sublevels(base.DefaultComparer.Compare, base.DefaultFormatter, 10<<20); err != nil { + if err := v.InitL0Sublevels(flushSplitBytes); err != nil { return err.Error() } } @@ -526,7 +527,7 @@ func TestVersionEditApply(t *testing.T) { } } zombies := make(map[base.DiskFileNum]uint64) - newv, err := bve.Apply(v, base.DefaultComparer.Compare, base.DefaultFormatter, 10<<20, 32000, zombies) + newv, err := bve.Apply(v, base.DefaultComparer, flushSplitBytes, 32000, zombies) if err != nil { return err.Error() } diff --git a/internal/manifest/version_test.go b/internal/manifest/version_test.go index eb743adad8..440b735dc8 100644 --- a/internal/manifest/version_test.go +++ b/internal/manifest/version_test.go @@ -90,13 +90,11 @@ func TestIkeyRange(t *testing.T) { func TestOverlaps(t *testing.T) { var v *Version - cmp := testkeys.Comparer.Compare - fmtKey := testkeys.Comparer.FormatKey datadriven.RunTest(t, "testdata/overlaps", func(t *testing.T, d *datadriven.TestData) string { switch d.Cmd { case "define": var err error - v, err = ParseVersionDebug(cmp, fmtKey, 64>>10 /* flush split bytes */, d.Input) + v, err = ParseVersionDebug(testkeys.Comparer, 64*1024 /* flush split bytes */, d.Input) if err != nil { return err.Error() } @@ -109,7 +107,7 @@ func TestOverlaps(t *testing.T) { d.ScanArgs(t, "start", &start) d.ScanArgs(t, "end", &end) d.ScanArgs(t, "exclusive-end", &exclusiveEnd) - overlaps := v.Overlaps(level, testkeys.Comparer.Compare, []byte(start), []byte(end), exclusiveEnd) + overlaps := v.Overlaps(level, []byte(start), []byte(end), exclusiveEnd) var buf bytes.Buffer fmt.Fprintf(&buf, "%d files:\n", overlaps.Len()) overlaps.Each(func(f *FileMetadata) { @@ -217,6 +215,7 @@ func TestContains(t *testing.T) { 0: levelMetadata(0, m00, m01, m02, m03, m04, m05, m06, m07), 1: levelMetadata(1, m10, m11, m12, m13, m14), }, + cmp: testkeys.Comparer, } testCases := []struct { @@ -264,7 +263,7 @@ func TestContains(t *testing.T) { } for _, tc := range testCases { - got := v.Contains(tc.level, cmp, tc.file) + got := v.Contains(tc.level, tc.file) if got != tc.want { t.Errorf("level=%d, file=%s\ngot %t\nwant %t", tc.level, tc.file, got, tc.want) } @@ -284,13 +283,11 @@ func TestVersionUnref(t *testing.T) { } func TestCheckOrdering(t *testing.T) { - cmp := base.DefaultComparer.Compare - fmtKey := base.DefaultComparer.FormatKey datadriven.RunTest(t, "testdata/version_check_ordering", func(t *testing.T, d *datadriven.TestData) string { switch d.Cmd { case "check-ordering": - v, err := ParseVersionDebug(cmp, fmtKey, 10<<20, d.Input) + v, err := ParseVersionDebug(base.DefaultComparer, 10*1024*1024, d.Input) if err != nil { return err.Error() } @@ -300,7 +297,7 @@ func TestCheckOrdering(t *testing.T) { m.SmallestSeqNum = m.Smallest.SeqNum() m.LargestSeqNum = m.Largest.SeqNum() }) - if err = v.CheckOrdering(cmp, base.DefaultFormatter); err != nil { + if err = v.CheckOrdering(); err != nil { return err.Error() } return "OK" diff --git a/level_checker_test.go b/level_checker_test.go index c063ccc6ad..a27b8cdd04 100644 --- a/level_checker_test.go +++ b/level_checker_test.go @@ -252,8 +252,7 @@ func TestCheckLevelsCornerCases(t *testing.T) { files[i+1] = levels[i] } version := manifest.NewVersion( - base.DefaultComparer.Compare, - base.DefaultFormatter, + base.DefaultComparer, 0, files) readState := &readState{current: version} diff --git a/open_test.go b/open_test.go index 683bc5508c..8b9f73b6b6 100644 --- a/open_test.go +++ b/open_test.go @@ -1245,8 +1245,6 @@ func TestCheckConsistency(t *testing.T) { require.NoError(t, err) defer provider.Close() - cmp := base.DefaultComparer.Compare - fmtKey := base.DefaultComparer.FormatKey parseMeta := func(s string) (*manifest.FileMetadata, error) { if len(s) == 0 { return nil, nil @@ -1308,7 +1306,7 @@ func TestCheckConsistency(t *testing.T) { } } - v := manifest.NewVersion(cmp, fmtKey, 0, filesByLevel) + v := manifest.NewVersion(base.DefaultComparer, 0, filesByLevel) err := checkConsistency(v, dir, provider) if err != nil { if redactErr { diff --git a/replay/replay.go b/replay/replay.go index 86d149115f..bffe431b4e 100644 --- a/replay/replay.go +++ b/replay/replay.go @@ -714,8 +714,7 @@ func (r *Runner) prepareWorkloadSteps(ctx context.Context) error { currentVersion := func() (*manifest.Version, error) { var err error v, err = bve.Apply(v, - r.Opts.Comparer.Compare, - r.Opts.Comparer.FormatKey, + r.Opts.Comparer, r.Opts.FlushSplitBytes, r.Opts.Experimental.ReadCompactionRate, nil /* zombies */) diff --git a/table_stats.go b/table_stats.go index 63b5e77f28..c378a05c88 100644 --- a/table_stats.go +++ b/table_stats.go @@ -149,7 +149,7 @@ func (d *DB) collectTableStats() bool { v := d.mu.versions.currentVersion() keepHints := hints[:0] for _, h := range hints { - if v.Contains(h.tombstoneLevel, d.cmp, h.tombstoneFile) { + if v.Contains(h.tombstoneLevel, h.tombstoneFile) { keepHints = append(keepHints, h) } } @@ -185,7 +185,7 @@ func (d *DB) loadNewFileStats( // The file isn't guaranteed to still be live in the readState's // version. It may have been deleted or moved. Skip it if it's not in // the expected level. - if !rs.current.Contains(nf.Level, d.cmp, nf.Meta) { + if !rs.current.Contains(nf.Level, nf.Meta) { continue } @@ -500,7 +500,7 @@ func (d *DB) estimateSizesBeneath( } for l := level + 1; l < numLevels; l++ { - overlaps := v.Overlaps(l, d.cmp, meta.Smallest.UserKey, + overlaps := v.Overlaps(l, meta.Smallest.UserKey, meta.Largest.UserKey, meta.Largest.IsExclusiveSentinel()) iter := overlaps.Iter() for file = iter.First(); file != nil; file = iter.Next() { @@ -553,7 +553,7 @@ func (d *DB) estimateReclaimedSizeBeneath( // additional I/O to read the file's index blocks. hintSeqNum = math.MaxUint64 for l := level + 1; l < numLevels; l++ { - overlaps := v.Overlaps(l, d.cmp, start, end, true /* exclusiveEnd */) + overlaps := v.Overlaps(l, start, end, true /* exclusiveEnd */) iter := overlaps.Iter() for file := iter.First(); file != nil; file = iter.Next() { startCmp := d.cmp(start, file.Smallest.UserKey) diff --git a/table_stats_test.go b/table_stats_test.go index 27db47ac11..34949c34be 100644 --- a/table_stats_test.go +++ b/table_stats_test.go @@ -191,7 +191,7 @@ func TestTableStats(t *testing.T) { func TestTableRangeDeletionIter(t *testing.T) { var m *fileMetadata - cmp := base.DefaultComparer.Compare + cmp := base.DefaultComparer fs := vfs.NewMem() datadriven.RunTest(t, "testdata/table_stats_deletion_iter", func(t *testing.T, td *datadriven.TestData) string { switch cmd := td.Cmd; cmd { @@ -233,15 +233,15 @@ func TestTableRangeDeletionIter(t *testing.T) { return err.Error() } if meta.HasPointKeys { - m.ExtendPointKeyBounds(cmp, meta.SmallestPoint, meta.LargestPoint) + m.ExtendPointKeyBounds(cmp.Compare, meta.SmallestPoint, meta.LargestPoint) } if meta.HasRangeDelKeys { - m.ExtendPointKeyBounds(cmp, meta.SmallestRangeDel, meta.LargestRangeDel) + m.ExtendPointKeyBounds(cmp.Compare, meta.SmallestRangeDel, meta.LargestRangeDel) } if meta.HasRangeKeys { - m.ExtendRangeKeyBounds(cmp, meta.SmallestRangeKey, meta.LargestRangeKey) + m.ExtendRangeKeyBounds(cmp.Compare, meta.SmallestRangeKey, meta.LargestRangeKey) } - return m.DebugString(base.DefaultFormatter, false /* verbose */) + return m.DebugString(cmp.FormatKey, false /* verbose */) case "spans": f, err := fs.Open("tmp.sst") if err != nil { @@ -257,7 +257,7 @@ func TestTableRangeDeletionIter(t *testing.T) { return err.Error() } defer r.Close() - iter, err := newCombinedDeletionKeyspanIter(base.DefaultComparer, r, m) + iter, err := newCombinedDeletionKeyspanIter(cmp, r, m) if err != nil { return err.Error() } diff --git a/tool/db.go b/tool/db.go index 79b3a767d2..843c4f5dea 100644 --- a/tool/db.go +++ b/tool/db.go @@ -529,7 +529,7 @@ func (d *dbT) runProperties(cmd *cobra.Command, args []string) { } } v, err := bve.Apply( - nil /* version */, cmp.Compare, d.fmtKey.fn, d.opts.FlushSplitBytes, + nil /* version */, cmp, d.opts.FlushSplitBytes, d.opts.Experimental.ReadCompactionRate, nil, /* zombies */ ) if err != nil { diff --git a/tool/lsm.go b/tool/lsm.go index 013a80c0a2..f1e8b1679c 100644 --- a/tool/lsm.go +++ b/tool/lsm.go @@ -232,7 +232,9 @@ func (l *lsmT) readManifest(path string) []*manifest.VersionEdit { } l.fmtKey.setForComparer(ve.ComparerName, l.comparers) } else if l.cmp == nil { - l.cmp = base.DefaultComparer + l.cmp = &base.Comparer{} + *l.cmp = *base.DefaultComparer + l.cmp.FormatKey = l.fmtKey.fn } } return edits @@ -320,7 +322,7 @@ func (l *lsmT) buildEdits(edits []*manifest.VersionEdit) error { } } - v := manifest.NewVersion(l.cmp.Compare, l.fmtKey.fn, 0, currentFiles) + v := manifest.NewVersion(l.cmp, 0, currentFiles) edit.Sublevels = make(map[base.FileNum]int) for sublevel, files := range v.L0SublevelFiles { iter := files.Iter() diff --git a/tool/manifest.go b/tool/manifest.go index 192f929f10..61a42bf746 100644 --- a/tool/manifest.go +++ b/tool/manifest.go @@ -242,7 +242,7 @@ func (m *manifestT) runDump(cmd *cobra.Command, args []string) { if comparer != nil { v, err := bve.Apply( - nil /* version */, comparer.Compare, m.fmtKey.fn, 0, + nil /* version */, comparer, 0, m.opts.Experimental.ReadCompactionRate, nil, /* zombies */ ) @@ -552,7 +552,7 @@ func (m *manifestT) runCheck(cmd *cobra.Command, args []string) { } // TODO(sbhola): add option to Apply that reports all errors instead of // one error. - newv, err := bve.Apply(v, cmp.Compare, m.fmtKey.fn, 0, m.opts.Experimental.ReadCompactionRate, nil /* zombies */) + newv, err := bve.Apply(v, cmp, 0, m.opts.Experimental.ReadCompactionRate, nil /* zombies */) if err != nil { fmt.Fprintf(stdout, "%s: offset: %d err: %s\n", arg, offset, err) diff --git a/version_set.go b/version_set.go index 3932f24596..4c89f8e155 100644 --- a/version_set.go +++ b/version_set.go @@ -58,11 +58,10 @@ type versionSet struct { // Immutable fields. dirname string // Set to DB.mu. - mu *sync.Mutex - opts *Options - fs vfs.FS - cmp Compare - cmpName string + mu *sync.Mutex + opts *Options + fs vfs.FS + cmp *base.Comparer // Dynamic base level allows the dynamic base level computation to be // disabled. Used by tests which want to create specific LSM structures. dynamicBaseLevel bool @@ -135,8 +134,7 @@ func (vs *versionSet) init( vs.writerCond.L = mu vs.opts = opts vs.fs = opts.FS - vs.cmp = opts.Comparer.Compare - vs.cmpName = opts.Comparer.Name + vs.cmp = opts.Comparer vs.dynamicBaseLevel = true vs.versions.Init(mu) vs.obsoleteFn = vs.addObsoleteLocked @@ -241,10 +239,10 @@ func (vs *versionSet) load( return err } if ve.ComparerName != "" { - if ve.ComparerName != vs.cmpName { + if ve.ComparerName != vs.cmp.Name { return errors.Errorf("pebble: manifest file %q for DB %q: "+ "comparer name from file %q != comparer name from Options %q", - errors.Safe(manifestFilename), dirname, errors.Safe(ve.ComparerName), errors.Safe(vs.cmpName)) + errors.Safe(manifestFilename), dirname, errors.Safe(ve.ComparerName), errors.Safe(vs.cmp.Name)) } } if err := bve.Accumulate(&ve); err != nil { @@ -301,10 +299,8 @@ func (vs *versionSet) load( vs.removeFileBacking(fileNum) } - newVersion, err := bve.Apply( - nil, vs.cmp, opts.Comparer.FormatKey, opts.FlushSplitBytes, - opts.Experimental.ReadCompactionRate, nil, /* zombies */ - ) + newVersion, err := bve.Apply(nil, opts.Comparer, opts.FlushSplitBytes, + opts.Experimental.ReadCompactionRate, nil /* zombies */) if err != nil { return err } @@ -512,7 +508,7 @@ func (vs *versionSet) logAndApply( return errors.AssertionFailedf("MANIFEST cannot contain virtual sstable records due to format major version") } newVersion, zombies, err = manifest.AccumulateIncompleteAndApplySingleVE( - ve, currentVersion, vs.cmp, vs.opts.Comparer.FormatKey, + ve, currentVersion, vs.cmp, vs.opts.FlushSplitBytes, vs.opts.Experimental.ReadCompactionRate, vs.backingState.fileBackingMap, vs.addFileBacking, vs.removeFileBacking, ) @@ -715,7 +711,7 @@ func (vs *versionSet) createManifest( manifest = record.NewWriter(manifestFile) snapshot := versionEdit{ - ComparerName: vs.cmpName, + ComparerName: vs.cmp.Name, } dedup := make(map[base.DiskFileNum]struct{}) for level, levelMetadata := range vs.currentVersion().Levels {