|
|
package kvdb
import ( "fmt" "io/ioutil" "os" "sync" "testing"
"github.com/hermeznetwork/hermez-node/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" )
func addTestKV(t *testing.T, db *KVDB, k, v []byte) { tx, err := db.db.NewTx() require.NoError(t, err)
err = tx.Put(k, v) require.NoError(t, err)
err = tx.Commit() require.NoError(t, err) }
func printCheckpoints(t *testing.T, path string) { files, err := ioutil.ReadDir(path) require.NoError(t, err)
fmt.Println(path) for _, f := range files { fmt.Println(" " + f.Name()) } }
func TestCheckpoints(t *testing.T) { dir, err := ioutil.TempDir("", "sdb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dir))
db, err := NewKVDB(Config{Path: dir, Keep: 128}) require.NoError(t, err)
// add test key-values
for i := 0; i < 10; i++ { addTestKV(t, db, []byte{byte(i), byte(i)}, []byte{byte(i * 2), byte(i * 2)}) }
// do checkpoints and check that currentBatch is correct
err = db.MakeCheckpoint() require.NoError(t, err) cb, err := db.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(1), cb)
for i := 1; i < 10; i++ { err = db.MakeCheckpoint() require.NoError(t, err)
cb, err = db.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(i+1), cb) }
// printCheckpoints(t, db.path)
// reset checkpoint
err = db.Reset(3) require.NoError(t, err)
// check that reset can be repeated (as there exist the 'current' and
// 'BatchNum3', from where the 'current' is a copy)
err = db.Reset(3) require.NoError(t, err)
printCheckpoints(t, db.cfg.Path)
// check that currentBatch is as expected after Reset
cb, err = db.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(3), cb)
// advance one checkpoint and check that currentBatch is fine
err = db.MakeCheckpoint() require.NoError(t, err) cb, err = db.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(4), cb)
err = db.DeleteCheckpoint(common.BatchNum(1)) require.NoError(t, err) err = db.DeleteCheckpoint(common.BatchNum(2)) require.NoError(t, err) err = db.DeleteCheckpoint(common.BatchNum(1)) // does not exist, should return err
assert.NotNil(t, err) err = db.DeleteCheckpoint(common.BatchNum(2)) // does not exist, should return err
assert.NotNil(t, err)
// Create a new KVDB which will get Reset from the initial KVDB
dirLocal, err := ioutil.TempDir("", "ldb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dirLocal)) ldb, err := NewKVDB(Config{Path: dirLocal, Keep: 128}) require.NoError(t, err)
// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
err = ldb.ResetFromSynchronizer(4, db) require.NoError(t, err) // check that currentBatch is 4 after the Reset
cb, err = ldb.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(4), cb) // advance one checkpoint in ldb
err = ldb.MakeCheckpoint() require.NoError(t, err) cb, err = ldb.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(5), cb)
// Create a 3rd KVDB which will get Reset from the initial KVDB
dirLocal2, err := ioutil.TempDir("", "ldb2") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dirLocal2)) ldb2, err := NewKVDB(Config{Path: dirLocal2, Keep: 128}) require.NoError(t, err)
// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
err = ldb2.ResetFromSynchronizer(4, db) require.NoError(t, err) // check that currentBatch is 4 after the Reset
cb, err = ldb2.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(4), cb) // advance one checkpoint in ldb2
err = ldb2.MakeCheckpoint() require.NoError(t, err) cb, err = ldb2.GetCurrentBatch() require.NoError(t, err) assert.Equal(t, common.BatchNum(5), cb)
debug := false if debug { printCheckpoints(t, db.cfg.Path) printCheckpoints(t, ldb.cfg.Path) printCheckpoints(t, ldb2.cfg.Path) } }
func TestListCheckpoints(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dir))
db, err := NewKVDB(Config{Path: dir, Keep: 128}) require.NoError(t, err)
numCheckpoints := 16 // do checkpoints
for i := 0; i < numCheckpoints; i++ { err = db.MakeCheckpoint() require.NoError(t, err) } list, err := db.ListCheckpoints() require.NoError(t, err) assert.Equal(t, numCheckpoints, len(list)) assert.Equal(t, 1, list[0]) assert.Equal(t, numCheckpoints, list[len(list)-1])
numReset := 10 err = db.Reset(common.BatchNum(numReset)) require.NoError(t, err) list, err = db.ListCheckpoints() require.NoError(t, err) assert.Equal(t, numReset, len(list)) assert.Equal(t, 1, list[0]) assert.Equal(t, numReset, list[len(list)-1]) }
func TestDeleteOldCheckpoints(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dir))
keep := 16 db, err := NewKVDB(Config{Path: dir, Keep: keep}) require.NoError(t, err)
numCheckpoints := 32 // do checkpoints and check that we never have more than `keep`
// checkpoints
for i := 0; i < numCheckpoints; i++ { err = db.MakeCheckpoint() require.NoError(t, err) err = db.DeleteOldCheckpoints() require.NoError(t, err) checkpoints, err := db.ListCheckpoints() require.NoError(t, err) assert.LessOrEqual(t, len(checkpoints), keep) } }
func TestConcurrentDeleteOldCheckpoints(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dir))
keep := 16 db, err := NewKVDB(Config{Path: dir, Keep: keep}) require.NoError(t, err)
numCheckpoints := 32
var wg sync.WaitGroup wg.Add(numCheckpoints)
// do checkpoints and check that we never have more than `keep`
// checkpoints.
// 1 async DeleteOldCheckpoint after 1 MakeCheckpoint
for i := 0; i < numCheckpoints; i++ { err = db.MakeCheckpoint() require.NoError(t, err) go func() { err = db.DeleteOldCheckpoints() require.NoError(t, err) wg.Done() }() } wg.Wait() checkpoints, err := db.ListCheckpoints() require.NoError(t, err) assert.LessOrEqual(t, len(checkpoints), keep)
wg.Add(numCheckpoints)
// do checkpoints and check that we never have more than `keep`
// checkpoints
// 32 concurrent DeleteOldCheckpoint after 32 MakeCheckpoint
for i := 0; i < numCheckpoints; i++ { err = db.MakeCheckpoint() require.NoError(t, err) } for i := 0; i < numCheckpoints; i++ { go func() { err = db.DeleteOldCheckpoints() require.NoError(t, err) wg.Done() }() } wg.Wait() checkpoints, err = db.ListCheckpoints() require.NoError(t, err) assert.LessOrEqual(t, len(checkpoints), keep) }
func TestGetCurrentIdx(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.NoError(t, err) defer require.NoError(t, os.RemoveAll(dir))
keep := 16 db, err := NewKVDB(Config{Path: dir, Keep: keep}) require.NoError(t, err)
idx, err := db.GetCurrentIdx() require.NoError(t, err) assert.Equal(t, common.Idx(255), idx)
db.Close()
db, err = NewKVDB(Config{Path: dir, Keep: keep}) require.NoError(t, err)
idx, err = db.GetCurrentIdx() require.NoError(t, err) assert.Equal(t, common.Idx(255), idx)
err = db.MakeCheckpoint() require.NoError(t, err)
idx, err = db.GetCurrentIdx() require.NoError(t, err) assert.Equal(t, common.Idx(255), idx)
db.Close()
db, err = NewKVDB(Config{Path: dir, Keep: keep}) require.NoError(t, err)
idx, err = db.GetCurrentIdx() require.NoError(t, err) assert.Equal(t, common.Idx(255), idx) }
|