diff options
author | Ben Johnson <benbjohnson@yahoo.com> | 2015-05-21 09:02:35 -0600 |
---|---|---|
committer | Ben Johnson <benbjohnson@yahoo.com> | 2015-05-21 09:02:35 -0600 |
commit | c69cb102ce8f7609b57f75d0ccb10862167001e7 (patch) | |
tree | 48f4fe99a2c0c68768fcb329842b4b1e95f84347 | |
parent | Merge pull request #376 from ryanuber/readme-consul (diff) | |
parent | Wait for pending tx on close. (diff) | |
download | dedo-c69cb102ce8f7609b57f75d0ccb10862167001e7.tar.gz dedo-c69cb102ce8f7609b57f75d0ccb10862167001e7.tar.xz |
Merge pull request #377 from benbjohnson/close-race
Wait for pending transactions on close
-rw-r--r-- | db.go | 7 | ||||
-rw-r--r-- | db_test.go | 45 |
2 files changed, 51 insertions, 1 deletions
@@ -351,8 +351,15 @@ func (db *DB) init() error { // Close releases all database resources. // All transactions must be closed before closing the database. func (db *DB) Close() error { + db.rwlock.Lock() + defer db.rwlock.Unlock() + db.metalock.Lock() defer db.metalock.Unlock() + + db.mmaplock.RLock() + defer db.mmaplock.RUnlock() + return db.close() } @@ -324,6 +324,49 @@ func TestDB_BeginRW_Closed(t *testing.T) { assert(t, tx == nil, "") } +func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) } +func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) } + +// Ensure that a database cannot close while transactions are open. +func testDB_Close_PendingTx(t *testing.T, writable bool) { + db := NewTestDB() + defer db.Close() + + // Start transaction. + tx, err := db.Begin(true) + if err != nil { + t.Fatal(err) + } + + // Open update in separate goroutine. + done := make(chan struct{}) + go func() { + db.Close() + close(done) + }() + + // Ensure database hasn't closed. + time.Sleep(100 * time.Millisecond) + select { + case <-done: + t.Fatal("database closed too early") + default: + } + + // Commit transaction. + if err := tx.Commit(); err != nil { + t.Fatal(err) + } + + // Ensure database closed now. + time.Sleep(100 * time.Millisecond) + select { + case <-done: + default: + t.Fatal("database did not close") + } +} + // Ensure a database can provide a transactional block. func TestDB_Update(t *testing.T) { db := NewTestDB() @@ -748,7 +791,7 @@ func (db *TestDB) PrintStats() { // MustCheck runs a consistency check on the database and panics if any errors are found. func (db *TestDB) MustCheck() { - db.View(func(tx *bolt.Tx) error { + db.Update(func(tx *bolt.Tx) error { // Collect all the errors. var errors []error for err := range tx.Check() { |