mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-09 13:28:20 +01:00
* filer leveldb2: read cache and buffer sizes from filer.toml The leveldb2 store hardcoded its block cache (32MiB) and write buffer (16MiB) and offered no way to tune the table block size or compaction table size. Optional block_cache_size_mb, write_buffer_size_mb, block_size_kb and compaction_table_size_mb keys under [leveldb2] now override them; zero or negative values keep the previous defaults. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * filer leveldb2: document tuning options in scaffold filer.toml Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * filer leveldb2: saturate size options instead of overflowing int The option fields take int, so a MiB config value past math.MaxInt/MiB (e.g. 2048 on 32-bit) wrapped negative and goleveldb would panic sizing the memtable. Clamp the product instead of the input. * filer leveldb2: reject size options too large for int bytes Clamping a MiB setting at math.MaxInt silently hands goleveldb a different size than configured; fail Initialize on values that cannot fit instead. * filer leveldb3: same tunable cache, buffer, block and table sizes Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * filer leveldb2/3: exercise oversized-option rejection on 64-bit too The tests skipped whenever int was 64-bit, but write_buffer_size_mb values above MaxInt/1MiB still overflow there, so the rejection path had no coverage on the primary platform. Use MaxInt/1MiB + 1 so the rejection triggers on every platform. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
175 lines
4.4 KiB
Go
175 lines
4.4 KiB
Go
package leveldb
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/filer"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
)
|
|
|
|
func TestCreateAndFind(t *testing.T) {
|
|
testFiler := filer.NewFiler(pb.ServerDiscovery{}, nil, "", "", "", "", "", 255, nil)
|
|
dir := t.TempDir()
|
|
store := &LevelDB2Store{}
|
|
store.initialize(dir, 2)
|
|
testFiler.SetStore(store)
|
|
|
|
fullpath := util.FullPath("/home/chris/this/is/one/file1.jpg")
|
|
|
|
ctx := context.Background()
|
|
|
|
entry1 := &filer.Entry{
|
|
FullPath: fullpath,
|
|
Attr: filer.Attr{
|
|
Mode: 0440,
|
|
Uid: 1234,
|
|
Gid: 5678,
|
|
},
|
|
}
|
|
|
|
if err := testFiler.CreateEntry(ctx, entry1, nil, false, false, nil, false, testFiler.MaxFilenameLength); err != nil {
|
|
t.Errorf("create entry %v: %v", entry1.FullPath, err)
|
|
return
|
|
}
|
|
|
|
entry, err := testFiler.FindEntry(ctx, fullpath)
|
|
|
|
if err != nil {
|
|
t.Errorf("find entry: %v", err)
|
|
return
|
|
}
|
|
|
|
if entry.FullPath != entry1.FullPath {
|
|
t.Errorf("find wrong entry: %v", entry.FullPath)
|
|
return
|
|
}
|
|
|
|
// checking one upper directory
|
|
entries, _, _ := testFiler.ListDirectoryEntries(ctx, util.FullPath("/home/chris/this/is/one"), "", false, 100, "", "", "")
|
|
if len(entries) != 1 {
|
|
t.Errorf("list entries count: %v", len(entries))
|
|
return
|
|
}
|
|
|
|
// checking one upper directory
|
|
entries, _, _ = testFiler.ListDirectoryEntries(ctx, util.FullPath("/"), "", false, 100, "", "", "")
|
|
if len(entries) != 1 {
|
|
t.Errorf("list entries count: %v", len(entries))
|
|
return
|
|
}
|
|
|
|
}
|
|
|
|
type fakeConfiguration map[string]interface{}
|
|
|
|
func (c fakeConfiguration) GetString(key string) string {
|
|
value, _ := c[key].(string)
|
|
return value
|
|
}
|
|
|
|
func (c fakeConfiguration) GetBool(key string) bool {
|
|
value, _ := c[key].(bool)
|
|
return value
|
|
}
|
|
|
|
func (c fakeConfiguration) GetInt(key string) int {
|
|
value, _ := c[key].(int)
|
|
return value
|
|
}
|
|
|
|
func (c fakeConfiguration) GetStringSlice(key string) []string {
|
|
value, _ := c[key].([]string)
|
|
return value
|
|
}
|
|
|
|
func (c fakeConfiguration) SetDefault(key string, value interface{}) {
|
|
if _, found := c[key]; !found {
|
|
c[key] = value
|
|
}
|
|
}
|
|
|
|
func TestInitializeOptions(t *testing.T) {
|
|
store := &LevelDB2Store{}
|
|
if err := store.Initialize(fakeConfiguration{
|
|
"leveldb2.dir": t.TempDir(),
|
|
"leveldb2.block_cache_size_mb": 64,
|
|
"leveldb2.write_buffer_size_mb": 32,
|
|
"leveldb2.block_size_kb": 16,
|
|
"leveldb2.compaction_table_size_mb": 8,
|
|
}, "leveldb2."); err != nil {
|
|
t.Fatalf("initialize: %v", err)
|
|
}
|
|
defer store.Shutdown()
|
|
|
|
opts := store.buildOptions()
|
|
if opts.BlockCacheCapacity != 64*1024*1024 {
|
|
t.Errorf("block cache %d, want 64MiB", opts.BlockCacheCapacity)
|
|
}
|
|
if opts.WriteBuffer != 32*1024*1024 {
|
|
t.Errorf("write buffer %d, want 32MiB", opts.WriteBuffer)
|
|
}
|
|
if opts.BlockSize != 16*1024 {
|
|
t.Errorf("block size %d, want 16KiB", opts.BlockSize)
|
|
}
|
|
if opts.CompactionTableSize != 8*1024*1024 {
|
|
t.Errorf("compaction table size %d, want 8MiB", opts.CompactionTableSize)
|
|
}
|
|
}
|
|
|
|
func TestInitializeDefaultOptions(t *testing.T) {
|
|
store := &LevelDB2Store{}
|
|
if err := store.Initialize(fakeConfiguration{
|
|
"leveldb2.dir": t.TempDir(),
|
|
"leveldb2.block_cache_size_mb": -1,
|
|
"leveldb2.write_buffer_size_mb": 0,
|
|
}, "leveldb2."); err != nil {
|
|
t.Fatalf("initialize: %v", err)
|
|
}
|
|
defer store.Shutdown()
|
|
|
|
opts := store.buildOptions()
|
|
if opts.BlockCacheCapacity != 32*1024*1024 {
|
|
t.Errorf("block cache %d, want the 32MiB default", opts.BlockCacheCapacity)
|
|
}
|
|
if opts.WriteBuffer != 16*1024*1024 {
|
|
t.Errorf("write buffer %d, want the 16MiB default", opts.WriteBuffer)
|
|
}
|
|
}
|
|
|
|
func TestInitializeRejectsOversizedOption(t *testing.T) {
|
|
store := &LevelDB2Store{}
|
|
err := store.Initialize(fakeConfiguration{
|
|
"leveldb2.dir": t.TempDir(),
|
|
"leveldb2.write_buffer_size_mb": math.MaxInt/(1<<20) + 1,
|
|
}, "leveldb2.")
|
|
if err == nil || !strings.Contains(err.Error(), "write_buffer_size_mb") {
|
|
t.Fatalf("expected overflow rejection, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEmptyRoot(t *testing.T) {
|
|
testFiler := filer.NewFiler(pb.ServerDiscovery{}, nil, "", "", "", "", "", 255, nil)
|
|
dir := t.TempDir()
|
|
store := &LevelDB2Store{}
|
|
store.initialize(dir, 2)
|
|
testFiler.SetStore(store)
|
|
|
|
ctx := context.Background()
|
|
|
|
// checking one upper directory
|
|
entries, _, err := testFiler.ListDirectoryEntries(ctx, util.FullPath("/"), "", false, 100, "", "", "")
|
|
if err != nil {
|
|
t.Errorf("list entries: %v", err)
|
|
return
|
|
}
|
|
if len(entries) != 0 {
|
|
t.Errorf("list entries count: %v", len(entries))
|
|
return
|
|
}
|
|
|
|
}
|