From d30a4fbf0c17660f9ce960c71f5af044db205583 Mon Sep 17 00:00:00 2001 From: Bogdan Kanivets Date: Thu, 17 Feb 2022 15:33:05 -0800 Subject: [PATCH] mvcc/backend: restore original bolt db options after defrag Problem: Defrag was implemented before custom bolt options were added. Currently defrag doesn't restore backend options. For example BackendFreelistType will be unset after defrag. Solution: save bolt db options and use them in defrag. --- mvcc/backend/backend.go | 24 ++++++++++++++++-------- mvcc/backend/backend_test.go | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/mvcc/backend/backend.go b/mvcc/backend/backend.go index 4f12b9a6b34..f63dfff1398 100644 --- a/mvcc/backend/backend.go +++ b/mvcc/backend/backend.go @@ -95,8 +95,9 @@ type backend struct { // openReadTxN is the number of currently open read transactions in the backend openReadTxN int64 - mu sync.RWMutex - db *bolt.DB + mu sync.RWMutex + bopts *bolt.Options + db *bolt.DB batchInterval time.Duration batchLimit int @@ -167,7 +168,8 @@ func newBackend(bcfg BackendConfig) *backend { // In future, may want to make buffering optional for low-concurrency systems // or dynamically swap between buffered/non-buffered depending on workload. b := &backend{ - db: db, + bopts: bopts, + db: db, batchInterval: bcfg.BatchInterval, batchLimit: bcfg.BatchLimit, @@ -447,7 +449,7 @@ func (b *backend) defrag() error { } } - b.db, err = bolt.Open(dbp, 0600, boltOpenOptions) + b.db, err = bolt.Open(dbp, 0600, b.bopts) if err != nil { if b.lg != nil { b.lg.Fatal("failed to open database", zap.String("path", dbp), zap.Error(err)) @@ -568,18 +570,24 @@ func (b *backend) OpenReadTxN() int64 { return atomic.LoadInt64(&b.openReadTxN) } -// NewTmpBackend creates a backend implementation for testing. -func NewTmpBackend(batchInterval time.Duration, batchLimit int) (*backend, string) { +// NewTmpBackendFromCfg creates a backend implementation for testing with custom BackendConfig. +func NewTmpBackendFromCfg(bcfg BackendConfig) (*backend, string) { dir, err := ioutil.TempDir(os.TempDir(), "etcd_backend_test") if err != nil { panic(err) } tmpPath := filepath.Join(dir, "database") - bcfg := DefaultBackendConfig() - bcfg.Path, bcfg.BatchInterval, bcfg.BatchLimit = tmpPath, batchInterval, batchLimit + bcfg.Path = tmpPath return newBackend(bcfg), tmpPath } +// NewTmpBackend creates a backend implementation for testing. +func NewTmpBackend(batchInterval time.Duration, batchLimit int) (*backend, string) { + bcfg := DefaultBackendConfig() + bcfg.BatchInterval, bcfg.BatchLimit = batchInterval, batchLimit + return NewTmpBackendFromCfg(bcfg) +} + func NewDefaultTmpBackend() (*backend, string) { return NewTmpBackend(defaultBatchInterval, defaultBatchLimit) } diff --git a/mvcc/backend/backend_test.go b/mvcc/backend/backend_test.go index cdcb508ddef..c3aac6607cf 100644 --- a/mvcc/backend/backend_test.go +++ b/mvcc/backend/backend_test.go @@ -120,7 +120,16 @@ func TestBackendBatchIntervalCommit(t *testing.T) { } func TestBackendDefrag(t *testing.T) { - b, tmpPath := NewDefaultTmpBackend() + bcfg := DefaultBackendConfig() + // Make sure we change BackendFreelistType + // The goal is to verify that we restore config option after defrag. + if bcfg.BackendFreelistType == bolt.FreelistMapType { + bcfg.BackendFreelistType = bolt.FreelistArrayType + } else { + bcfg.BackendFreelistType = bolt.FreelistMapType + } + + b, tmpPath := NewTmpBackendFromCfg(bcfg) defer cleanup(b, tmpPath) tx := b.BatchTx() @@ -167,6 +176,10 @@ func TestBackendDefrag(t *testing.T) { t.Errorf("new size = %v, want < %d", nsize, size) } + if b.db.FreelistType != bcfg.BackendFreelistType { + t.Errorf("db FreelistType = [%v], want [%v]", b.db.FreelistType, bcfg.BackendFreelistType) + } + // try put more keys after shrink. tx = b.BatchTx() tx.Lock()