mirror of
https://github.com/gogrlx/bitcask.git
synced 2026-04-17 10:35:16 -07:00
Auto recovery (#153)
* implement autorepair Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix misspell Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * Update internal/data/recover.go Co-authored-by: James Mills <prologic@shortcircuit.net.au> * Update internal/utils.go Co-authored-by: James Mills <prologic@shortcircuit.net.au> * Update internal/data/recover.go Co-authored-by: James Mills <prologic@shortcircuit.net.au> * skip failing test on windows Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: James Mills <prologic@shortcircuit.net.au>
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prologic/bitcask/internal"
|
||||
"github.com/prologic/bitcask/internal/config"
|
||||
@@ -334,6 +336,85 @@ func TestConfigErrors(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAutoRecovery(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.SkipNow()
|
||||
}
|
||||
withAutoRecovery := []bool{false, true}
|
||||
|
||||
for _, autoRecovery := range withAutoRecovery {
|
||||
t.Run(fmt.Sprintf("%v", autoRecovery), func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
testdir, err := ioutil.TempDir("", "bitcask")
|
||||
require.NoError(err)
|
||||
db, err := Open(testdir)
|
||||
require.NoError(err)
|
||||
|
||||
// Insert 10 key-value pairs and verify all is ok.
|
||||
makeKeyVal := func(i int) ([]byte, []byte) {
|
||||
return []byte(fmt.Sprintf("foo%d", i)), []byte(fmt.Sprintf("bar%d", i))
|
||||
}
|
||||
n := 10
|
||||
for i := 0; i < n; i++ {
|
||||
key, val := makeKeyVal(i)
|
||||
err = db.Put(key, val)
|
||||
require.NoError(err)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
key, val := makeKeyVal(i)
|
||||
rval, err := db.Get(key)
|
||||
require.NoError(err)
|
||||
require.Equal(val, rval)
|
||||
}
|
||||
err = db.Close()
|
||||
require.NoError(err)
|
||||
|
||||
// Corrupt the last inserted key
|
||||
f, err := os.OpenFile(path.Join(testdir, "000000000.data"), os.O_RDWR, 0755)
|
||||
require.NoError(err)
|
||||
fi, err := f.Stat()
|
||||
require.NoError(err)
|
||||
err = f.Truncate(fi.Size() - 1)
|
||||
require.NoError(err)
|
||||
err = f.Close()
|
||||
require.NoError(err)
|
||||
|
||||
db, err = Open(testdir, WithAutoRecovery(autoRecovery))
|
||||
require.NoError(err)
|
||||
defer db.Close()
|
||||
// Check that all values but the last are still intact.
|
||||
for i := 0; i < 9; i++ {
|
||||
key, val := makeKeyVal(i)
|
||||
rval, err := db.Get(key)
|
||||
require.NoError(err)
|
||||
require.Equal(val, rval)
|
||||
}
|
||||
// Check the index has no more keys than non-corrupted ones.
|
||||
// i.e: all but the last one.
|
||||
numKeys := 0
|
||||
for range db.Keys() {
|
||||
numKeys++
|
||||
}
|
||||
if !autoRecovery {
|
||||
// We are opening without autorepair, and thus are
|
||||
// in a corrupted state. The index isn't coherent with
|
||||
// the datafile.
|
||||
require.Equal(n, numKeys)
|
||||
return
|
||||
}
|
||||
|
||||
require.Equal(n-1, numKeys, "The index should have n-1 keys")
|
||||
|
||||
// Double-check explicitly the corrupted one isn't here.
|
||||
// This check is redundant considering the last two checks,
|
||||
// but doesn't hurt.
|
||||
corrKey, _ := makeKeyVal(9)
|
||||
_, err = db.Get(corrKey)
|
||||
require.Equal(ErrKeyNotFound, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReIndex(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user