Skip to content
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
28 changes: 24 additions & 4 deletions core/kv/pebblekv/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ type OpenOptions struct {
// an OS-level crash / power loss can lose the un-synced tail. Set Sync for a
// store of record. Ignored when DisableWAL is set (there is no WAL to sync).
Sync bool
// MemTableSize is the steady-state MemTable size in bytes. Zero selects the
// conservative built-in default (4 MiB). A larger memtable defers flushes, so
// more redundant writes coalesce/elide before hitting disk — cutting L0
// churn and compaction during a bulk build, at the cost of higher transient
// build-time memory (peak ≈ MemTableStopWritesThreshold × MemTableSize).
MemTableSize uint64
// MemTableStopWritesThreshold is the hard limit on queued memtables: writes
// stop once the queued memtable sizes exceed this × MemTableSize. Zero selects
// the built-in default (2). Values below 2 are raised to 2 (Pebble stalls
// writes whenever a memtable flushes at threshold 1).
MemTableStopWritesThreshold int
}

// Open opens a Pebble database at the default WAL mode — WAL on, commits not
Expand All @@ -88,6 +99,17 @@ func OpenWithOptions(path string, o OpenOptions) (kv.Store, error) {
return nil, fmt.Errorf("failed to get absolute path: %v", err)
}

// Memtable sizing: zero selects the conservative built-in defaults; a caller
// that knows its workload (e.g. a bulk index build) can enlarge it.
memTableSize := o.MemTableSize
if memTableSize == 0 {
memTableSize = 4 * 1024 * 1024
}
memTableStop := o.MemTableStopWritesThreshold
if memTableStop < 2 {
memTableStop = 2
}

// Configure Pebble options
opts := &pebble.Options{
Cache: pebble.NewCache(o.CacheSize),
Expand All @@ -102,10 +124,8 @@ func OpenWithOptions(path string, o OpenOptions) (kv.Store, error) {
// Allow more files to be open
MaxOpenFiles: 8192,

// Set write buffer size to 8MB
MemTableSize: 4 * 1024 * 1024,
// Set max memtable count to 2
MemTableStopWritesThreshold: 2,
MemTableSize: memTableSize,
MemTableStopWritesThreshold: memTableStop,

// The count of L0 files necessary to trigger an L0 compaction.
L0CompactionFileThreshold: 1024,
Expand Down
27 changes: 27 additions & 0 deletions core/kv/pebblekv/pebble_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,33 @@ func TestOpenWithOptions_WALModes(t *testing.T) {
}
}

// TestOpenWithOptions_MemTable covers the memtable sizing knobs: an explicit
// larger memtable + threshold opens and round-trips, the zero value falls back
// to the built-in default, and a sub-2 threshold is clamped to 2 (Pebble
// requires >= 2). All go through the kv.Store surface.
func TestOpenWithOptions_MemTable(t *testing.T) {
cases := []struct {
name string
opts OpenOptions
}{
{"explicit_16MiB_stop4", OpenOptions{CacheSize: 1 << 20, MemTableSize: 16 << 20, MemTableStopWritesThreshold: 4}},
{"zero_defaults", OpenOptions{CacheSize: 1 << 20}},
{"stop_below_2_clamped", OpenOptions{CacheSize: 1 << 20, MemTableSize: 8 << 20, MemTableStopWritesThreshold: 1}},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
db, err := OpenWithOptions(t.TempDir()+"/db", c.opts)
assert.NoError(t, err)
defer db.Close()

assert.NoError(t, db.Put([]byte("k"), []byte("v")))
got, err := db.Get([]byte("k"))
assert.NoError(t, err)
assert.Equal(t, []byte("v"), got)
})
}
}

func TestOpen_And_BasicOps(t *testing.T) {
tmpDir := t.TempDir()
db, err := Open(tmpDir+"/testdb", 4*1024*1024)
Expand Down
Loading