Some checks failed
Go Tests / Run Tests (1.24.2) (push) Has been cancelled
Adds a complete LSM-based storage engine with these features: - Single-writer based architecture for the storage engine - WAL for durability, and hey it's configurable - MemTable with skip list implementation for fast read/writes - SSTable with block-based structure for on-disk level-based storage - Background compaction with tiered strategy - ACID transactions - Good documentation (I hope)
133 lines
3.0 KiB
Go
133 lines
3.0 KiB
Go
package memtable
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func BenchmarkSkipListInsert(b *testing.B) {
|
|
sl := NewSkipList()
|
|
|
|
// Create random keys ahead of time
|
|
keys := make([][]byte, b.N)
|
|
values := make([][]byte, b.N)
|
|
for i := 0; i < b.N; i++ {
|
|
keys[i] = []byte(fmt.Sprintf("key-%d", i))
|
|
values[i] = []byte(fmt.Sprintf("value-%d", i))
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
e := newEntry(keys[i], values[i], TypeValue, uint64(i))
|
|
sl.Insert(e)
|
|
}
|
|
}
|
|
|
|
func BenchmarkSkipListFind(b *testing.B) {
|
|
sl := NewSkipList()
|
|
|
|
// Insert entries first
|
|
const numEntries = 100000
|
|
keys := make([][]byte, numEntries)
|
|
for i := 0; i < numEntries; i++ {
|
|
key := []byte(fmt.Sprintf("key-%d", i))
|
|
value := []byte(fmt.Sprintf("value-%d", i))
|
|
keys[i] = key
|
|
sl.Insert(newEntry(key, value, TypeValue, uint64(i)))
|
|
}
|
|
|
|
// Create random keys for lookup
|
|
lookupKeys := make([][]byte, b.N)
|
|
r := rand.New(rand.NewSource(42)) // Use fixed seed for reproducibility
|
|
for i := 0; i < b.N; i++ {
|
|
idx := r.Intn(numEntries)
|
|
lookupKeys[i] = keys[idx]
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
sl.Find(lookupKeys[i])
|
|
}
|
|
}
|
|
|
|
func BenchmarkMemTablePut(b *testing.B) {
|
|
mt := NewMemTable()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := []byte("key-" + strconv.Itoa(i))
|
|
value := []byte("value-" + strconv.Itoa(i))
|
|
mt.Put(key, value, uint64(i))
|
|
}
|
|
}
|
|
|
|
func BenchmarkMemTableGet(b *testing.B) {
|
|
mt := NewMemTable()
|
|
|
|
// Insert entries first
|
|
const numEntries = 100000
|
|
keys := make([][]byte, numEntries)
|
|
for i := 0; i < numEntries; i++ {
|
|
key := []byte(fmt.Sprintf("key-%d", i))
|
|
value := []byte(fmt.Sprintf("value-%d", i))
|
|
keys[i] = key
|
|
mt.Put(key, value, uint64(i))
|
|
}
|
|
|
|
// Create random keys for lookup
|
|
lookupKeys := make([][]byte, b.N)
|
|
r := rand.New(rand.NewSource(42)) // Use fixed seed for reproducibility
|
|
for i := 0; i < b.N; i++ {
|
|
idx := r.Intn(numEntries)
|
|
lookupKeys[i] = keys[idx]
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
mt.Get(lookupKeys[i])
|
|
}
|
|
}
|
|
|
|
func BenchmarkMemPoolGet(b *testing.B) {
|
|
cfg := createTestConfig()
|
|
cfg.MemTableSize = 1024 * 1024 * 32 // 32MB for benchmark
|
|
pool := NewMemTablePool(cfg)
|
|
|
|
// Create multiple memtables with entries
|
|
const entriesPerTable = 50000
|
|
const numTables = 3
|
|
keys := make([][]byte, entriesPerTable*numTables)
|
|
|
|
// Fill tables
|
|
for t := 0; t < numTables; t++ {
|
|
// Fill a table
|
|
for i := 0; i < entriesPerTable; i++ {
|
|
idx := t*entriesPerTable + i
|
|
key := []byte(fmt.Sprintf("key-%d", idx))
|
|
value := []byte(fmt.Sprintf("value-%d", idx))
|
|
keys[idx] = key
|
|
pool.Put(key, value, uint64(idx))
|
|
}
|
|
|
|
// Switch to a new memtable (except for last one)
|
|
if t < numTables-1 {
|
|
pool.SwitchToNewMemTable()
|
|
}
|
|
}
|
|
|
|
// Create random keys for lookup
|
|
lookupKeys := make([][]byte, b.N)
|
|
r := rand.New(rand.NewSource(42)) // Use fixed seed for reproducibility
|
|
for i := 0; i < b.N; i++ {
|
|
idx := r.Intn(entriesPerTable * numTables)
|
|
lookupKeys[i] = keys[idx]
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
pool.Get(lookupKeys[i])
|
|
}
|
|
}
|