Skip to content
Open
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
3 changes: 2 additions & 1 deletion badger/cmd/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ func init() {
func doBackup(cmd *cobra.Command, args []string) error {
opt := badger.DefaultOptions(sstDir).
WithValueDir(vlogDir).
WithNumVersionsToKeep(math.MaxInt32)
WithNumVersionsToKeep(math.MaxInt32).
WithMaxLevels(vMaxLevels)

if bo.numVersions > 0 {
opt.NumVersionsToKeep = bo.numVersions
Expand Down
10 changes: 6 additions & 4 deletions badger/cmd/bank.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ func runDisect(cmd *cobra.Command, args []string) error {
WithValueDir(vlogDir).
WithReadOnly(true).
WithEncryptionKey([]byte(encryptionKey)).
WithIndexCacheSize(1 << 30))
WithIndexCacheSize(1 << 30).
WithMaxLevels(vMaxLevels))
if err != nil {
return err
}
Expand Down Expand Up @@ -351,7 +352,8 @@ func runTest(cmd *cobra.Command, args []string) error {
// Do not GC any versions, because we need them for the disect.
WithNumVersionsToKeep(int(math.MaxInt32)).
WithBlockCacheSize(1 << 30).
WithIndexCacheSize(1 << 30)
WithIndexCacheSize(1 << 30).
WithMaxLevels(vMaxLevels)

if verbose {
opts = opts.WithLoggingLevel(badger.DEBUG)
Expand All @@ -376,7 +378,7 @@ func runTest(cmd *cobra.Command, args []string) error {
dir, err := os.MkdirTemp("", "bank_subscribe")
y.Check(err)

subscribeDB, err = badger.Open(badger.DefaultOptions(dir).WithSyncWrites(false))
subscribeDB, err = badger.Open(badger.DefaultOptions(dir).WithSyncWrites(false).WithMaxLevels(vMaxLevels))
if err != nil {
return err
}
Expand All @@ -387,7 +389,7 @@ func runTest(cmd *cobra.Command, args []string) error {
dir, err := os.MkdirTemp("", "bank_stream")
y.Check(err)

tmpDb, err = badger.Open(badger.DefaultOptions(dir).WithSyncWrites(false))
tmpDb, err = badger.Open(badger.DefaultOptions(dir).WithSyncWrites(false).WithMaxLevels(vMaxLevels))
if err != nil {
return err
}
Expand Down
66 changes: 66 additions & 0 deletions badger/cmd/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

package cmd

import (
"os"
"testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/require"

"github.com/dgraph-io/badger/v4"
)

// TestMaxLevelsFlag tests the --max-levels CLI flag
func TestMaxLevelsFlag(t *testing.T) {
tests := []struct {
name string
maxLevels int
shouldError bool
}{
{"max-levels-0", 0, true},
{"max-levels-negative", -1, true},
{"max-levels-10", 10, false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir, err := os.MkdirTemp("", "badger-max-levels-test")
require.NoError(t, err)
defer func() {
if err := os.RemoveAll(dir); err != nil {
t.Fatalf("Failed to clean up temp directory: %v", err)
}
}()

// Set the vMaxLevels variable to test value
oldMaxLevels := vMaxLevels
vMaxLevels = tt.maxLevels
defer func() { vMaxLevels = oldMaxLevels }()

sstDir = dir
vlogDir = dir

// Test validation - create a mock cobra command to avoid nil pointer dereference
cmd := &cobra.Command{Use: "test"}
err = validateRootCmdArgs(cmd, []string{})

if tt.shouldError {
require.Error(t, err, "Expected validation to fail for max-levels=%d", tt.maxLevels)
require.Contains(t, err.Error(), "--max-levels should be at least 1")
} else {
require.NoError(t, err, "Expected validation to pass for max-levels=%d", tt.maxLevels)

// Test that DB can be opened with the max-levels setting
opts := badger.DefaultOptions(dir).WithMaxLevels(vMaxLevels)
db, err := badger.Open(opts)
require.NoError(t, err)
require.NoError(t, db.Close())
}
})
}
}
3 changes: 2 additions & 1 deletion badger/cmd/flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ func flatten(cmd *cobra.Command, args []string) error {
WithBlockCacheSize(100 << 20).
WithIndexCacheSize(200 << 20).
WithCompression(options.CompressionType(fo.compressionType)).
WithEncryptionKey(encKey)
WithEncryptionKey(encKey).
WithMaxLevels(vMaxLevels)
fmt.Printf("Opening badger with options = %+v\n", opt)
db, err := badger.Open(opt)
if err != nil {
Expand Down
8 changes: 7 additions & 1 deletion badger/cmd/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type flagOptions struct {
checksumVerificationMode string
discard bool
externalMagicVersion uint16

memTableSize int64
}

var (
Expand Down Expand Up @@ -73,6 +75,8 @@ func init() {
"Parse and print DISCARD file from value logs.")
infoCmd.Flags().Uint16Var(&opt.externalMagicVersion, "external-magic", 0,
"External magic number")
infoCmd.Flags().Int64Var(&opt.memTableSize, "memtable-size", 128<<20,
"Size of memtable in bytes.")
}

var infoCmd = &cobra.Command{
Expand All @@ -96,7 +100,9 @@ func handleInfo(cmd *cobra.Command, args []string) error {
WithIndexCacheSize(200 << 20).
WithEncryptionKey([]byte(opt.encryptionKey)).
WithChecksumVerificationMode(cvMode).
WithExternalMagic(opt.externalMagicVersion)
WithExternalMagic(opt.externalMagicVersion).
WithMemTableSize(opt.memTableSize).
WithMaxLevels(vMaxLevels)

if opt.discard {
ds, err := badger.InitDiscardStats(bopt)
Expand Down
3 changes: 2 additions & 1 deletion badger/cmd/pick_table_bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ func init() {
func pickTableBench(cmd *cobra.Command, args []string) error {
opt := badger.DefaultOptions(sstDir).
WithValueDir(vlogDir).
WithReadOnly(pickOpts.readOnly)
WithReadOnly(pickOpts.readOnly).
WithMaxLevels(vMaxLevels)
fmt.Printf("Opening badger with options = %+v\n", opt)
db, err := badger.OpenManaged(opt)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion badger/cmd/read_bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ func readBench(cmd *cobra.Command, args []string) error {
WithValueDir(vlogDir).
WithReadOnly(ro.readOnly).
WithBlockCacheSize(ro.blockCacheSize << 20).
WithIndexCacheSize(ro.indexCacheSize << 20)
WithIndexCacheSize(ro.indexCacheSize << 20).
WithMaxLevels(vMaxLevels)
fmt.Printf("Opening badger with options = %+v\n", opt)
db, err := badger.OpenManaged(opt)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion badger/cmd/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func doRestore(cmd *cobra.Command, args []string) error {
// Open DB
db, err := badger.Open(badger.DefaultOptions(sstDir).
WithValueDir(vlogDir).
WithNumVersionsToKeep(math.MaxInt32))
WithNumVersionsToKeep(math.MaxInt32).
WithMaxLevels(vMaxLevels))
if err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions badger/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

var sstDir, vlogDir string

var vMaxLevels int

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "badger",
Expand All @@ -38,6 +40,9 @@ func init() {

RootCmd.PersistentFlags().StringVar(&vlogDir, "vlog-dir", "",
"Directory where the value log files are located, if different from --dir")

RootCmd.PersistentFlags().IntVar(&vMaxLevels, "max-levels", 7,
"Maximum number of levels in the LSM tree")
}

func validateRootCmdArgs(cmd *cobra.Command, args []string) error {
Expand All @@ -50,5 +55,9 @@ func validateRootCmdArgs(cmd *cobra.Command, args []string) error {
if vlogDir == "" {
vlogDir = sstDir
}

if vMaxLevels < 1 {
return errors.New("--max-levels should be at least 1")
}
return nil
}
3 changes: 2 additions & 1 deletion badger/cmd/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ func stream(cmd *cobra.Command, args []string) error {
WithNumVersionsToKeep(so.numVersions).
WithBlockCacheSize(100 << 20).
WithIndexCacheSize(200 << 20).
WithEncryptionKey(encKey)
WithEncryptionKey(encKey).
WithMaxLevels(vMaxLevels)

// Options for output DB.
if so.compressionType > 2 {
Expand Down
3 changes: 2 additions & 1 deletion badger/cmd/write_bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ func writeBench(cmd *cobra.Command, args []string) error {
WithValueLogMaxEntries(wo.vlogMaxEntries).
WithEncryptionKey([]byte(wo.encryptionKey)).
WithDetectConflicts(wo.detectConflicts).
WithLoggingLevel(badger.INFO)
WithLoggingLevel(badger.INFO).
WithMaxLevels(vMaxLevels)
if wo.zstdComp {
opt = opt.WithCompression(options.ZSTD)
}
Expand Down
2 changes: 1 addition & 1 deletion levels.go
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ func (s *levelsController) runCompactDef(id, l int, cd compactDef) (err error) {
expensive = " [E]"
}
s.kv.opt.Infof("[%d]%s LOG Compact %d->%d (%d, %d -> %d tables with %d splits)."+
" [%s] -> [%s], took %v\n, deleted %d bytes",
" [%s] -> [%s], took %v, deleted %d bytes\n",
id, expensive, thisLevel.level, nextLevel.level, len(cd.top), len(cd.bot),
len(newTables), len(cd.splits), strings.Join(from, " "), strings.Join(to, " "),
dur.Round(time.Millisecond), sizeOldTables-sizeNewTables)
Expand Down