Skip to content

Commit 3958d45

Browse files
committed
db: add excise_bound tests
Add tests for `determineLeft/RightTableBounds` during excise.
1 parent 8701e52 commit 3958d45

File tree

4 files changed

+345
-4
lines changed

4 files changed

+345
-4
lines changed

data_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,13 +608,18 @@ func runBuildRemoteCmd(td *datadriven.TestData, d *DB, storage remote.Storage) e
608608
}
609609

610610
type dataDrivenCmdOptions struct {
611-
blobValues *blobtest.Values
611+
blobValues *blobtest.Values
612+
defaultWriterOpts sstable.WriterOptions
612613
}
613614

614615
func withBlobValues(bv *blobtest.Values) func(*dataDrivenCmdOptions) {
615616
return func(o *dataDrivenCmdOptions) { o.blobValues = bv }
616617
}
617618

619+
func withDefaultWriterOpts(defaultWriterOpts sstable.WriterOptions) func(*dataDrivenCmdOptions) {
620+
return func(o *dataDrivenCmdOptions) { o.defaultWriterOpts = defaultWriterOpts }
621+
}
622+
618623
func combineDataDrivenOpts(opts ...func(*dataDrivenCmdOptions)) dataDrivenCmdOptions {
619624
combined := dataDrivenCmdOptions{}
620625
for _, opt := range opts {
@@ -623,6 +628,7 @@ func combineDataDrivenOpts(opts ...func(*dataDrivenCmdOptions)) dataDrivenCmdOpt
623628
return combined
624629
}
625630

631+
// TODO(radu): remove this in favor of runBuildSSTCmd.
626632
func runBuildCmd(
627633
td *datadriven.TestData, d *DB, fs vfs.FS, opts ...func(*dataDrivenCmdOptions),
628634
) error {
@@ -718,6 +724,38 @@ func runBuildCmd(
718724
return w.Close()
719725
}
720726

727+
func runBuildSSTCmd(
728+
input string,
729+
writerArgs []datadriven.CmdArg,
730+
path string,
731+
fs vfs.FS,
732+
opts ...func(*dataDrivenCmdOptions),
733+
) (sstable.WriterMetadata, error) {
734+
ddOpts := combineDataDrivenOpts(opts...)
735+
736+
writerOpts := ddOpts.defaultWriterOpts
737+
if err := sstable.ParseWriterOptions(&writerOpts, writerArgs...); err != nil {
738+
return sstable.WriterMetadata{}, err
739+
}
740+
741+
f, err := fs.Create(path, vfs.WriteCategoryUnspecified)
742+
if err != nil {
743+
return sstable.WriterMetadata{}, err
744+
}
745+
w := sstable.NewWriter(objstorageprovider.NewFileWritable(f), writerOpts)
746+
if err := sstable.ParseTestSST(w.Raw(), input, nil /* bv */); err != nil {
747+
return sstable.WriterMetadata{}, err
748+
}
749+
if err := w.Close(); err != nil {
750+
return sstable.WriterMetadata{}, err
751+
}
752+
metadata, err := w.Metadata()
753+
if err != nil {
754+
return sstable.WriterMetadata{}, err
755+
}
756+
return *metadata, nil
757+
}
758+
721759
func runCompactCmd(td *datadriven.TestData, d *DB) error {
722760
if len(td.CmdArgs) > 4 {
723761
return errors.Errorf("%s expects at most four arguments", td.Cmd)

excise_test.go

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package pebble
77
import (
88
"context"
99
"fmt"
10+
"math/rand/v2"
1011
"strconv"
1112
"strings"
1213
"sync"
@@ -306,6 +307,7 @@ func TestExcise(t *testing.T) {
306307
fileNums[base.FileNum(fNum)] = struct{}{}
307308
}
308309
d.mu.Lock()
310+
defer d.mu.Unlock()
309311
currVersion := d.mu.versions.currentVersion()
310312
var ptr *manifest.FileBacking
311313
for _, level := range currVersion.Levels {
@@ -322,7 +324,6 @@ func TestExcise(t *testing.T) {
322324
}
323325
}
324326
}
325-
d.mu.Unlock()
326327
return "file backings are the same"
327328
case "compact":
328329
if len(td.CmdArgs) != 2 {
@@ -431,7 +432,6 @@ func TestConcurrentExcise(t *testing.T) {
431432
FormatMajorVersion: FormatVirtualSSTables,
432433
Logger: testLogger{t},
433434
}
434-
// lel.
435435
lel := MakeLoggingEventListener(testLogger{t})
436436
tel := TeeEventListener(lel, el)
437437
opts1.EventListener = &tel
@@ -763,3 +763,108 @@ func TestConcurrentExcise(t *testing.T) {
763763
}
764764
})
765765
}
766+
767+
func TestExciseBounds(t *testing.T) {
768+
const sstPath = "foo.sst"
769+
var fs vfs.FS
770+
var m *manifest.TableMetadata
771+
cmp := base.DefaultComparer.Compare
772+
773+
datadriven.RunTest(t, "testdata/excise_bounds", func(t *testing.T, td *datadriven.TestData) string {
774+
checkErr := func(err error) {
775+
if err != nil {
776+
t.Helper()
777+
td.Fatalf(t, "%v", err)
778+
}
779+
}
780+
var buf strings.Builder
781+
printBounds := func(title string, m *tableMetadata) {
782+
fmt.Fprintf(&buf, "%s:\n", title)
783+
fmt.Fprintf(&buf, " overall: %v - %v\n", m.Smallest, m.Largest)
784+
if m.HasPointKeys {
785+
fmt.Fprintf(&buf, " point: %v - %v\n", m.SmallestPointKey, m.LargestPointKey)
786+
}
787+
if m.HasRangeKeys {
788+
fmt.Fprintf(&buf, " range: %v - %v\n", m.SmallestRangeKey, m.LargestRangeKey)
789+
}
790+
}
791+
switch td.Cmd {
792+
case "build-sst":
793+
fs = vfs.NewMem()
794+
var writerOpts sstable.WriterOptions
795+
writerOpts.TableFormat = sstable.TableFormat(rand.IntN(int(sstable.TableFormatMax)) + 1)
796+
// We need at least v2 for tests with range keys.
797+
writerOpts.TableFormat = max(writerOpts.TableFormat, sstable.TableFormatPebblev2)
798+
sstMeta, err := runBuildSSTCmd(td.Input, td.CmdArgs, sstPath, fs, withDefaultWriterOpts(writerOpts))
799+
checkErr(err)
800+
801+
m = &manifest.TableMetadata{}
802+
if sstMeta.HasPointKeys {
803+
m.ExtendPointKeyBounds(cmp, sstMeta.SmallestPoint, sstMeta.LargestPoint)
804+
}
805+
if sstMeta.HasRangeDelKeys {
806+
m.ExtendPointKeyBounds(cmp, sstMeta.SmallestRangeDel, sstMeta.LargestRangeDel)
807+
}
808+
if sstMeta.HasRangeKeys {
809+
m.ExtendRangeKeyBounds(cmp, sstMeta.SmallestRangeKey, sstMeta.LargestRangeKey)
810+
}
811+
printBounds("Bounds", m)
812+
813+
case "excise":
814+
f, err := fs.Open(sstPath)
815+
checkErr(err)
816+
readable, err := sstable.NewSimpleReadable(f)
817+
checkErr(err)
818+
ctx := context.Background()
819+
r, err := sstable.NewReader(ctx, readable, sstable.ReaderOptions{})
820+
checkErr(err)
821+
pointIter, err := r.NewPointIter(ctx, sstable.IterOptions{})
822+
checkErr(err)
823+
rangeDelIter, err := r.NewRawRangeDelIter(ctx, sstable.NoFragmentTransforms, block.ReadEnv{})
824+
checkErr(err)
825+
rangeKeyIter, err := r.NewRawRangeKeyIter(ctx, sstable.NoFragmentTransforms, block.ReadEnv{})
826+
checkErr(err)
827+
iters := iterSet{
828+
point: pointIter,
829+
rangeDeletion: rangeDelIter,
830+
rangeKey: rangeKeyIter,
831+
}
832+
833+
exciseSpan := base.ParseUserKeyBounds(td.Input)
834+
if cmp(m.Smallest.UserKey, exciseSpan.Start) < 0 {
835+
var t manifest.TableMetadata
836+
checkErr(determineLeftTableBounds(cmp, m, &t, exciseSpan.Start, iters))
837+
printBounds("Left table bounds", &t)
838+
}
839+
840+
if !exciseSpan.End.IsUpperBoundForInternalKey(cmp, m.Largest) {
841+
var t manifest.TableMetadata
842+
err := func() (err error) {
843+
// determineRightTableBounds can return assertion errors which we want
844+
// to see in the tests but which panic in invariant builds.
845+
defer func() {
846+
if p := recover(); p != nil {
847+
if e, ok := p.(error); ok {
848+
err = e
849+
} else {
850+
panic(p)
851+
}
852+
}
853+
}()
854+
return determineRightTableBounds(cmp, m, &t, exciseSpan.End, iters)
855+
}()
856+
if err != nil {
857+
fmt.Fprintf(&buf, "determineRightTableBounds error: %v", err)
858+
} else {
859+
printBounds("Right table bounds", &t)
860+
}
861+
}
862+
checkErr(iters.CloseAll())
863+
864+
default:
865+
td.Fatalf(t, "unknown command %q", td.Cmd)
866+
}
867+
868+
return buf.String()
869+
})
870+
}

ingest_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,6 @@ func testIngestSharedImpl(
684684
FormatMajorVersion: FormatVirtualSSTables,
685685
Logger: testLogger{t},
686686
}
687-
// lel.
688687
lel := MakeLoggingEventListener(testLogger{t})
689688
opts1.EventListener = &lel
690689
opts1.Experimental.RemoteStorage = remote.MakeSimpleFactory(map[remote.Locator]remote.Storage{

0 commit comments

Comments
 (0)