From b2f3dd5dba77717524c5316b228880d7605ab64d Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Tue, 21 Mar 2023 16:35:22 +0800 Subject: [PATCH] Perform unmap when failing to mlock or both meta pages corrupted Signed-off-by: Benjamin Wang --- db.go | 16 +++++++++++++--- tests/failpoint/db_failpoint_test.go | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/db.go b/db.go index d89cd8c..b21fa3b 100644 --- a/db.go +++ b/db.go @@ -388,7 +388,7 @@ func (db *DB) hasSyncedFreelist() bool { // mmap opens the underlying memory-mapped file and initializes the meta references. // minsz is the minimum size that the new mmap can be. -func (db *DB) mmap(minsz int) error { +func (db *DB) mmap(minsz int) (err error) { db.mmaplock.Lock() defer db.mmaplock.Unlock() @@ -423,17 +423,27 @@ func (db *DB) mmap(minsz int) error { } // Unmap existing data before continuing. - if err := db.munmap(); err != nil { + if err = db.munmap(); err != nil { return err } // Memory-map the data file as a byte slice. // gofail: var mapError string // return errors.New(mapError) - if err := mmap(db, size); err != nil { + if err = mmap(db, size); err != nil { return err } + // Perform unmmap on any error to reset all data fields: + // dataref, data, datasz, meta0 and meta1. + defer func() { + if err != nil { + if unmapErr := db.munmap(); unmapErr != nil { + err = fmt.Errorf("%w; unmap failed: %v", err, unmapErr) + } + } + }() + if db.Mlock { // Don't allow swapping of data file if err := db.mlock(fileSize); err != nil { diff --git a/tests/failpoint/db_failpoint_test.go b/tests/failpoint/db_failpoint_test.go index 5df3dc0..ef7d7ca 100644 --- a/tests/failpoint/db_failpoint_test.go +++ b/tests/failpoint/db_failpoint_test.go @@ -2,7 +2,6 @@ package failpoint import ( "fmt" - "go.etcd.io/bbolt/internal/btesting" "path/filepath" "testing" "time" @@ -10,6 +9,7 @@ import ( "github.com/stretchr/testify/require" bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt/internal/btesting" gofail "go.etcd.io/gofail/runtime" )