From 92535e654b1ff244719107953bea0ba5c812b411 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Sun, 18 Jul 2021 23:41:40 +0000 Subject: [PATCH] [FIX] race condition from #216 (#227) [ADDED] new tests for TTL expiration race condition, see #216 [REMOVED] removes cleanup / automatic expiration from get() function to resolve #216 Reviewed-on: https://git.mills.io/prologic/bitcask/pulls/227 Co-authored-by: Tai Groot Co-committed-by: Tai Groot --- bitcask.go | 3 +-- bitcask_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/bitcask.go b/bitcask.go index e92cb49..be82a45 100644 --- a/bitcask.go +++ b/bitcask.go @@ -386,8 +386,7 @@ func (b *Bitcask) get(key []byte) (internal.Entry, error) { if !found { return internal.Entry{}, ErrKeyNotFound } - if expired := b.isExpired(key); expired { - _ = b.delete(key) // we don't care if it doesnt succeed + if b.isExpired(key) { return internal.Entry{}, ErrKeyExpired } diff --git a/bitcask_test.go b/bitcask_test.go index 16245dd..5b81bbb 100644 --- a/bitcask_test.go +++ b/bitcask_test.go @@ -1750,6 +1750,43 @@ func TestLockingAfterMerge(t *testing.T) { assert.Error(err) } +func TestGetExpiredInsideFold(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() + // Add a node to the tree that won't expire + db.Put([]byte("static"), []byte("static")) + // Add a node that expires almost immediately to the tree + db.PutWithTTL([]byte("shortLived"), []byte("shortLived"), 1*time.Millisecond) + db.Put([]byte("skipped"), []byte("skipped")) + db.Put([]byte("static2"), []byte("static2")) + time.Sleep(2 * time.Millisecond) + var arr []string + _ = db.Fold(func(key []byte) error { + val, err := db.Get(key) + switch string(key) { + case "skipped": + fallthrough + case "static2": + fallthrough + case "static": + assert.NoError(err) + assert.Equal(string(val), string(key)) + case "shortLived": + assert.Error(err) + } + arr = append(arr, string(val)) + return nil + }) + assert.Contains(arr, "skipped") + +} + type benchmarkTestCase struct { name string size int