diff --git a/bitcask.go b/bitcask.go index af2a472..4312001 100644 --- a/bitcask.go +++ b/bitcask.go @@ -22,6 +22,10 @@ import ( "github.com/prologic/bitcask/internal/metadata" ) +const ( + lockfile = "lock" +) + var ( // ErrKeyNotFound is the error returned when a key is not found ErrKeyNotFound = errors.New("error: key not found") @@ -96,13 +100,15 @@ func (b *Bitcask) Stats() (stats Stats, err error) { // database. func (b *Bitcask) Close() error { b.mu.RLock() - defer b.mu.RUnlock() + defer func() { + b.mu.RUnlock() + b.Flock.Unlock() + }() return b.close() } func (b *Bitcask) close() error { - defer b.Flock.Unlock() if err := b.saveIndex(); err != nil { return err } @@ -490,7 +496,7 @@ func (b *Bitcask) Merge() error { return err } for _, file := range files { - if file.IsDir() { + if file.IsDir() || file.Name() == lockfile { continue } ids, err := internal.ParseIds([]string{file.Name()}) @@ -563,7 +569,7 @@ func Open(path string, options ...Option) (*Bitcask, error) { } bitcask := &Bitcask{ - Flock: flock.New(filepath.Join(path, "lock")), + Flock: flock.New(filepath.Join(path, lockfile)), config: cfg, options: options, path: path, @@ -604,7 +610,7 @@ func (b *Bitcask) Backup(path string) error { return err } } - return internal.Copy(b.path, path, []string{"lock"}) + return internal.Copy(b.path, path, []string{lockfile}) } // saveIndex saves index currently in RAM to disk diff --git a/bitcask_test.go b/bitcask_test.go index 6678e5f..45e35be 100644 --- a/bitcask_test.go +++ b/bitcask_test.go @@ -1627,6 +1627,27 @@ func TestLocking(t *testing.T) { assert.Error(err) } +func TestLockingAfterMerge(t *testing.T) { + assert := assert.New(t) + + testdir, err := ioutil.TempDir("", "bitcask") + assert.NoError(err) + + db, err := Open(testdir) + assert.NoError(err) + defer db.Close() + + _, err = Open(testdir) + assert.Error(err) + + err = db.Merge() + assert.NoError(err) + + // This should still error. + _, err = Open(testdir) + assert.Error(err) +} + type benchmarkTestCase struct { name string size int