Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

storage: add benchmark for scanning MVCC garbage #85716

Merged
merged 1 commit into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions pkg/storage/bench_pebble_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,32 @@ func BenchmarkMVCCScan_Pebble(b *testing.B) {
}
}

func BenchmarkMVCCScanGarbage_Pebble(b *testing.B) {
skip.UnderShort(b)
ctx := context.Background()
for _, numRows := range []int{1, 10, 100, 1000, 10000, 50000} {
b.Run(fmt.Sprintf("rows=%d", numRows), func(b *testing.B) {
for _, numVersions := range []int{1, 2, 10, 100, 1000} {
b.Run(fmt.Sprintf("versions=%d", numVersions), func(b *testing.B) {
for _, numRangeKeys := range []int{0, 1, 100} {
b.Run(fmt.Sprintf("numRangeKeys=%d", numRangeKeys), func(b *testing.B) {
runMVCCScan(ctx, b, setupMVCCPebble, benchScanOptions{
benchDataOptions: benchDataOptions{
numVersions: numVersions,
numRangeKeys: numRangeKeys,
garbage: true,
},
numRows: numRows,
reverse: false,
})
})
}
})
}
})
}
}

func BenchmarkMVCCScanSQLRows_Pebble(b *testing.B) {
skip.UnderShort(b)
ctx := context.Background()
Expand Down
72 changes: 51 additions & 21 deletions pkg/storage/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,11 @@ type benchDataOptions struct {
numColumnFamilies int
numRangeKeys int // MVCC range tombstones, 1=global

// If garbage is enabled, point keys will be tombstones rather than values.
// Furthermore, range keys (controlled by numRangeKeys) will be written above
// the point keys rather than below them.
garbage bool

// In transactional mode, data is written by writing and later resolving
// intents. In non-transactional mode, data is written directly, without
// leaving intents. Transactional mode notably stresses RocksDB deletion
Expand Down Expand Up @@ -683,6 +688,9 @@ func setupMVCCData(
if opts.transactional {
loc += "_txn"
}
if opts.garbage {
loc += "_garbage"
}

exists := true
if _, err := os.Stat(loc); oserror.IsNotExist(err) {
Expand All @@ -703,25 +711,31 @@ func setupMVCCData(
// Generate the same data every time.
rng := rand.New(rand.NewSource(1449168817))

// Write MVCC range keys.
batch := eng.NewBatch()
for i := 0; i < opts.numRangeKeys; i++ {
ts := hlc.Timestamp{Logical: int32(i + 1)}
start := rng.Intn(opts.numKeys)
end := start + rng.Intn(opts.numKeys-start) + 1
// As a special case, if we're only writing one range key, write it across
// the entire span.
if opts.numRangeKeys == 1 {
start = 0
end = opts.numKeys + 1
// Write MVCC range keys. If garbage is enabled, they will be written on top
// of the point keys, otherwise they will be written below them.
writeRangeKeys := func(b testing.TB, wallTime int) {
batch := eng.NewBatch()
defer batch.Close()
for i := 0; i < opts.numRangeKeys; i++ {
ts := hlc.Timestamp{WallTime: int64(wallTime), Logical: int32(i + 1)}
start := rng.Intn(opts.numKeys)
end := start + rng.Intn(opts.numKeys-start) + 1
// As a special case, if we're only writing one range key, write it across
// the entire span.
if opts.numRangeKeys == 1 {
start = 0
end = opts.numKeys + 1
}
startKey := roachpb.Key(encoding.EncodeUvarintAscending([]byte("key-"), uint64(start)))
endKey := roachpb.Key(encoding.EncodeUvarintAscending([]byte("key-"), uint64(end)))
require.NoError(b, MVCCDeleteRangeUsingTombstone(
ctx, batch, nil, startKey, endKey, ts, hlc.ClockTimestamp{}, nil, nil, 0, nil))
}
startKey := roachpb.Key(encoding.EncodeUvarintAscending([]byte("key-"), uint64(start)))
endKey := roachpb.Key(encoding.EncodeUvarintAscending([]byte("key-"), uint64(end)))
require.NoError(b, MVCCDeleteRangeUsingTombstone(
ctx, batch, nil, startKey, endKey, ts, hlc.ClockTimestamp{}, nil, nil, 0, nil))
require.NoError(b, batch.Commit(false /* sync */))
}
if !opts.garbage {
writeRangeKeys(b, 0 /* wallTime */)
}
require.NoError(b, batch.Commit(false /* sync */))
batch.Close()

// Generate point keys.
keySlice := make([]roachpb.Key, opts.numKeys)
Expand Down Expand Up @@ -756,8 +770,11 @@ func setupMVCCData(

writeKey := func(batch Batch, idx int) {
key := keySlice[idx]
value := roachpb.MakeValueFromBytes(randutil.RandBytes(rng, opts.valueBytes))
value.InitChecksum(key)
var value roachpb.Value
if !opts.garbage {
value = roachpb.MakeValueFromBytes(randutil.RandBytes(rng, opts.valueBytes))
value.InitChecksum(key)
}
counts[idx]++
ts := hlc.Timestamp{WallTime: int64(counts[idx] * 5)}
if txn != nil {
Expand All @@ -782,7 +799,7 @@ func setupMVCCData(
}
}

batch = eng.NewBatch()
batch := eng.NewBatch()
for i, idx := range order {
// Output the keys in ~20 batches. If we used a single batch to output all
// of the keys rocksdb would create a single sstable. We want multiple
Expand Down Expand Up @@ -824,6 +841,13 @@ func setupMVCCData(
b.Fatal(err)
}
batch.Close()

// If we're writing garbage, write MVCC range tombstones on top of the
// point keys.
if opts.garbage {
writeRangeKeys(b, 10*opts.numVersions)
}

if err := eng.Flush(); err != nil {
b.Fatal(err)
}
Expand Down Expand Up @@ -891,6 +915,9 @@ func runMVCCScan(ctx context.Context, b *testing.B, emk engineMaker, opts benchS
endKey = makeBenchRowKey(b, endKeyBuf[:0], int(endID), 0)
}
walltime := int64(5 * (rand.Int31n(int32(opts.numVersions)) + 1))
if opts.garbage {
walltime = hlc.MaxTimestamp.WallTime
}
ts := hlc.Timestamp{WallTime: walltime}
var wholeRowsOfSize int32
if opts.wholeRows {
Expand All @@ -909,9 +936,12 @@ func runMVCCScan(ctx context.Context, b *testing.B, emk engineMaker, opts benchS
if opts.wholeRows {
expectKVs -= opts.numRows % opts.numColumnFamilies
}
if len(res.KVs) != expectKVs {
if !opts.garbage && len(res.KVs) != expectKVs {
b.Fatalf("failed to scan: %d != %d", len(res.KVs), expectKVs)
}
if opts.garbage && len(res.KVs) != 0 {
b.Fatalf("failed to scan garbage: found %d keys", len(res.KVs))
}
}

b.StopTimer()
Expand Down