- package db
-
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io/ioutil"
- "sync"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- cmn "github.com/tendermint/tendermint/libs/common"
- )
-
- //----------------------------------------
- // Helper functions.
-
- func checkValue(t *testing.T, db DB, key []byte, valueWanted []byte) {
- valueGot := db.Get(key)
- assert.Equal(t, valueWanted, valueGot)
- }
-
- func checkValid(t *testing.T, itr Iterator, expected bool) {
- valid := itr.Valid()
- require.Equal(t, expected, valid)
- }
-
- func checkNext(t *testing.T, itr Iterator, expected bool) {
- itr.Next()
- valid := itr.Valid()
- require.Equal(t, expected, valid)
- }
-
- func checkNextPanics(t *testing.T, itr Iterator) {
- assert.Panics(t, func() { itr.Next() }, "checkNextPanics expected panic but didn't")
- }
-
- func checkDomain(t *testing.T, itr Iterator, start, end []byte) {
- ds, de := itr.Domain()
- assert.Equal(t, start, ds, "checkDomain domain start incorrect")
- assert.Equal(t, end, de, "checkDomain domain end incorrect")
- }
-
- func checkItem(t *testing.T, itr Iterator, key []byte, value []byte) {
- k, v := itr.Key(), itr.Value()
- assert.Exactly(t, key, k)
- assert.Exactly(t, value, v)
- }
-
- func checkInvalid(t *testing.T, itr Iterator) {
- checkValid(t, itr, false)
- checkKeyPanics(t, itr)
- checkValuePanics(t, itr)
- checkNextPanics(t, itr)
- }
-
- func checkKeyPanics(t *testing.T, itr Iterator) {
- assert.Panics(t, func() { itr.Key() }, "checkKeyPanics expected panic but didn't")
- }
-
- func checkValuePanics(t *testing.T, itr Iterator) {
- assert.Panics(t, func() { itr.Value() }, "checkValuePanics expected panic but didn't")
- }
-
- func newTempDB(t *testing.T, backend DBBackendType) (db DB, dbDir string) {
- dirname, err := ioutil.TempDir("", "db_common_test")
- require.Nil(t, err)
- return NewDB("testdb", backend, dirname), dirname
- }
-
- //----------------------------------------
- // mockDB
-
- // NOTE: not actually goroutine safe.
- // If you want something goroutine safe, maybe you just want a MemDB.
- type mockDB struct {
- mtx sync.Mutex
- calls map[string]int
- }
-
- func newMockDB() *mockDB {
- return &mockDB{
- calls: make(map[string]int),
- }
- }
-
- func (mdb *mockDB) Mutex() *sync.Mutex {
- return &(mdb.mtx)
- }
-
- func (mdb *mockDB) Get([]byte) []byte {
- mdb.calls["Get"]++
- return nil
- }
-
- func (mdb *mockDB) Has([]byte) bool {
- mdb.calls["Has"]++
- return false
- }
-
- func (mdb *mockDB) Set([]byte, []byte) {
- mdb.calls["Set"]++
- }
-
- func (mdb *mockDB) SetSync([]byte, []byte) {
- mdb.calls["SetSync"]++
- }
-
- func (mdb *mockDB) SetNoLock([]byte, []byte) {
- mdb.calls["SetNoLock"]++
- }
-
- func (mdb *mockDB) SetNoLockSync([]byte, []byte) {
- mdb.calls["SetNoLockSync"]++
- }
-
- func (mdb *mockDB) Delete([]byte) {
- mdb.calls["Delete"]++
- }
-
- func (mdb *mockDB) DeleteSync([]byte) {
- mdb.calls["DeleteSync"]++
- }
-
- func (mdb *mockDB) DeleteNoLock([]byte) {
- mdb.calls["DeleteNoLock"]++
- }
-
- func (mdb *mockDB) DeleteNoLockSync([]byte) {
- mdb.calls["DeleteNoLockSync"]++
- }
-
- func (mdb *mockDB) Iterator(start, end []byte) Iterator {
- mdb.calls["Iterator"]++
- return &mockIterator{}
- }
-
- func (mdb *mockDB) ReverseIterator(start, end []byte) Iterator {
- mdb.calls["ReverseIterator"]++
- return &mockIterator{}
- }
-
- func (mdb *mockDB) Close() {
- mdb.calls["Close"]++
- }
-
- func (mdb *mockDB) NewBatch() Batch {
- mdb.calls["NewBatch"]++
- return &memBatch{db: mdb}
- }
-
- func (mdb *mockDB) Print() {
- mdb.calls["Print"]++
- fmt.Printf("mockDB{%v}", mdb.Stats())
- }
-
- func (mdb *mockDB) Stats() map[string]string {
- mdb.calls["Stats"]++
-
- res := make(map[string]string)
- for key, count := range mdb.calls {
- res[key] = fmt.Sprintf("%d", count)
- }
- return res
- }
-
- //----------------------------------------
- // mockIterator
-
- type mockIterator struct{}
-
- func (mockIterator) Domain() (start []byte, end []byte) {
- return nil, nil
- }
-
- func (mockIterator) Valid() bool {
- return false
- }
-
- func (mockIterator) Next() {
- }
-
- func (mockIterator) Key() []byte {
- return nil
- }
-
- func (mockIterator) Value() []byte {
- return nil
- }
-
- func (mockIterator) Close() {
- }
-
- func benchmarkRandomReadsWrites(b *testing.B, db DB) {
- b.StopTimer()
-
- // create dummy data
- const numItems = int64(1000000)
- internal := map[int64]int64{}
- for i := 0; i < int(numItems); i++ {
- internal[int64(i)] = int64(0)
- }
-
- // fmt.Println("ok, starting")
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- // Write something
- {
- idx := int64(cmn.RandInt()) % numItems
- internal[idx]++
- val := internal[idx]
- idxBytes := int642Bytes(int64(idx))
- valBytes := int642Bytes(int64(val))
- //fmt.Printf("Set %X -> %X\n", idxBytes, valBytes)
- db.Set(idxBytes, valBytes)
- }
-
- // Read something
- {
- idx := int64(cmn.RandInt()) % numItems
- valExp := internal[idx]
- idxBytes := int642Bytes(int64(idx))
- valBytes := db.Get(idxBytes)
- //fmt.Printf("Get %X -> %X\n", idxBytes, valBytes)
- if valExp == 0 {
- if !bytes.Equal(valBytes, nil) {
- b.Errorf("Expected %v for %v, got %X", nil, idx, valBytes)
- break
- }
- } else {
- if len(valBytes) != 8 {
- b.Errorf("Expected length 8 for %v, got %X", idx, valBytes)
- break
- }
- valGot := bytes2Int64(valBytes)
- if valExp != valGot {
- b.Errorf("Expected %v for %v, got %v", valExp, idx, valGot)
- break
- }
- }
- }
-
- }
- }
-
- func int642Bytes(i int64) []byte {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint64(buf, uint64(i))
- return buf
- }
-
- func bytes2Int64(buf []byte) int64 {
- return int64(binary.BigEndian.Uint64(buf))
- }
|