boltdd: return error on use-after-Close
Return the same error as boltdb instead of panic'ing.
This commit is contained in:
parent
6f3712ed48
commit
4d92603340
|
@ -69,6 +69,10 @@ func (db *DB) bucket(btx *bolt.Tx, name []byte) *Bucket {
|
|||
db.rootBucketsLock.Lock()
|
||||
defer db.rootBucketsLock.Unlock()
|
||||
|
||||
if db.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, ok := db.rootBuckets[string(name)]
|
||||
if !ok {
|
||||
b = newBucketMeta()
|
||||
|
@ -87,6 +91,12 @@ func (db *DB) createBucket(btx *bolt.Tx, name []byte) (*Bucket, error) {
|
|||
db.rootBucketsLock.Lock()
|
||||
defer db.rootBucketsLock.Unlock()
|
||||
|
||||
// While creating a bucket on a closed db would error, we must recheck
|
||||
// after acquiring the lock to avoid races.
|
||||
if db.isClosed() {
|
||||
return nil, bolt.ErrDatabaseNotOpen
|
||||
}
|
||||
|
||||
// Always create a new Bucket since CreateBucket above fails if the
|
||||
// bucket already exists.
|
||||
b := newBucketMeta()
|
||||
|
@ -104,6 +114,12 @@ func (db *DB) createBucketIfNotExists(btx *bolt.Tx, name []byte) (*Bucket, error
|
|||
db.rootBucketsLock.Lock()
|
||||
defer db.rootBucketsLock.Unlock()
|
||||
|
||||
// While creating a bucket on a closed db would error, we must recheck
|
||||
// after acquiring the lock to avoid races.
|
||||
if db.isClosed() {
|
||||
return nil, bolt.ErrDatabaseNotOpen
|
||||
}
|
||||
|
||||
b, ok := db.rootBuckets[string(name)]
|
||||
if !ok {
|
||||
b = newBucketMeta()
|
||||
|
@ -127,10 +143,18 @@ func (db *DB) View(fn func(*Tx) error) error {
|
|||
})
|
||||
}
|
||||
|
||||
// isClosed returns true if the database is closed and must be called while
|
||||
// db.rootBucketsLock is acquired.
|
||||
func (db *DB) isClosed() bool {
|
||||
return db.rootBuckets == nil
|
||||
}
|
||||
|
||||
// Close closes the underlying bolt.DB and clears all bucket hashes. DB is
|
||||
// unusable after closing.
|
||||
func (db *DB) Close() error {
|
||||
db.rootBucketsLock.Lock()
|
||||
db.rootBuckets = nil
|
||||
db.rootBucketsLock.Unlock()
|
||||
return db.bdb.Close()
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/hashicorp/nomad/nomad/mock"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -54,6 +55,25 @@ func TestDB_Open(t *testing.T) {
|
|||
require.Equal(0, db.BoltDB().Stats().TxStats.Write)
|
||||
}
|
||||
|
||||
func TestDB_Close(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, cleanup := setupBoltDB(t)
|
||||
defer cleanup()
|
||||
|
||||
db.Close()
|
||||
|
||||
require.Equal(t, db.Update(func(tx *Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists([]byte("foo"))
|
||||
return err
|
||||
}), bolt.ErrDatabaseNotOpen)
|
||||
|
||||
require.Equal(t, db.Update(func(tx *Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("foo"))
|
||||
return err
|
||||
}), bolt.ErrDatabaseNotOpen)
|
||||
}
|
||||
|
||||
func TestBucket_Create(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
|
Loading…
Reference in New Issue