Skip to content

Commit c52d9f8

Browse files
committed
add benchmark for expired-only value GC rewrite
1 parent 541b2d1 commit c52d9f8

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

value_gc_rewrite_bench_test.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package badger
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
const (
15+
benchmarkRewriteExpiredKeyCount = 8192
16+
benchmarkRewriteLiveKeyCount = 4096
17+
benchmarkRewriteValueSize = 2 << 10
18+
benchmarkRewriteValueLogFileSize = 8 << 20
19+
benchmarkRewriteValueThreshold = 128
20+
benchmarkRewriteEntryExpiry uint64 = 1
21+
)
22+
23+
func benchmarkValueGCRewriteOptions(dir string) Options {
24+
opt := getTestOptions(dir)
25+
opt.ValueLogFileSize = benchmarkRewriteValueLogFileSize
26+
opt.BaseTableSize = 1 << 20
27+
opt.BaseLevelSize = 4 << 20
28+
opt.ValueThreshold = benchmarkRewriteValueThreshold
29+
opt.NumCompactors = 0
30+
opt.MetricsEnabled = false
31+
return opt
32+
}
33+
34+
func benchmarkWriteEntries(b *testing.B, db *DB, prefix string, count int, value []byte, expiresAt uint64) {
35+
b.Helper()
36+
37+
for i := 0; i < count; {
38+
txn := db.NewTransaction(true)
39+
for ; i < count; i++ {
40+
entry := NewEntry([]byte(fmt.Sprintf("%s-%08d", prefix, i)), value)
41+
entry.ExpiresAt = expiresAt
42+
43+
err := txn.SetEntry(entry)
44+
if err == ErrTxnTooBig {
45+
require.NoError(b, txn.Commit())
46+
txn = nil
47+
break
48+
}
49+
require.NoError(b, err)
50+
}
51+
if txn != nil {
52+
require.NoError(b, txn.Commit())
53+
}
54+
}
55+
}
56+
57+
func benchmarkPrepareRewriteFixture(b *testing.B, dir string) {
58+
b.Helper()
59+
60+
db, err := Open(benchmarkValueGCRewriteOptions(dir))
61+
require.NoError(b, err)
62+
63+
expiredValue := bytes.Repeat([]byte("e"), benchmarkRewriteValueSize)
64+
liveValue := bytes.Repeat([]byte("l"), benchmarkRewriteValueSize)
65+
66+
// Fill the earliest vlog files with expired entries before appending live entries.
67+
benchmarkWriteEntries(b, db, "expired", benchmarkRewriteExpiredKeyCount, expiredValue, benchmarkRewriteEntryExpiry)
68+
benchmarkWriteEntries(b, db, "live", benchmarkRewriteLiveKeyCount, liveValue, 0)
69+
70+
require.NoError(b, db.Close())
71+
}
72+
73+
func copyDir(src, dst string) error {
74+
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
75+
if err != nil {
76+
return err
77+
}
78+
relPath, err := filepath.Rel(src, path)
79+
if err != nil {
80+
return err
81+
}
82+
targetPath := filepath.Join(dst, relPath)
83+
if info.IsDir() {
84+
return os.MkdirAll(targetPath, info.Mode())
85+
}
86+
if !info.Mode().IsRegular() {
87+
return fmt.Errorf("unsupported file mode for %s", path)
88+
}
89+
90+
srcFile, err := os.Open(path)
91+
if err != nil {
92+
return err
93+
}
94+
95+
dstFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode())
96+
if err != nil {
97+
_ = srcFile.Close()
98+
return err
99+
}
100+
if _, err := io.Copy(dstFile, srcFile); err != nil {
101+
_ = srcFile.Close()
102+
_ = dstFile.Close()
103+
return err
104+
}
105+
if err := srcFile.Close(); err != nil {
106+
_ = dstFile.Close()
107+
return err
108+
}
109+
return dstFile.Close()
110+
})
111+
}
112+
113+
func BenchmarkValueGCRewriteExpiredOnlyFile(b *testing.B) {
114+
rootDir := b.TempDir()
115+
fixtureDir := filepath.Join(rootDir, "fixture")
116+
benchmarkPrepareRewriteFixture(b, fixtureDir)
117+
118+
b.ReportAllocs()
119+
b.ResetTimer()
120+
121+
for i := 0; i < b.N; i++ {
122+
b.StopTimer()
123+
124+
runDir := filepath.Join(rootDir, fmt.Sprintf("run-%03d", i))
125+
require.NoError(b, copyDir(fixtureDir, runDir))
126+
127+
db, err := Open(benchmarkValueGCRewriteOptions(runDir))
128+
require.NoError(b, err)
129+
130+
fids := db.vlog.sortedFids()
131+
require.Greater(b, len(fids), 1)
132+
133+
db.vlog.filesLock.RLock()
134+
lf := db.vlog.filesMap[fids[0]]
135+
db.vlog.filesLock.RUnlock()
136+
137+
b.StartTimer()
138+
err = db.vlog.rewrite(lf)
139+
b.StopTimer()
140+
require.NoError(b, err)
141+
142+
require.NoError(b, db.Close())
143+
removeDir(runDir)
144+
}
145+
}

0 commit comments

Comments
 (0)