You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
5.3 KiB

  1. package db
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "io/ioutil"
  7. "sync"
  8. "testing"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. cmn "github.com/tendermint/tendermint/libs/common"
  12. )
  13. //----------------------------------------
  14. // Helper functions.
  15. func checkValue(t *testing.T, db DB, key []byte, valueWanted []byte) {
  16. valueGot := db.Get(key)
  17. assert.Equal(t, valueWanted, valueGot)
  18. }
  19. func checkValid(t *testing.T, itr Iterator, expected bool) {
  20. valid := itr.Valid()
  21. require.Equal(t, expected, valid)
  22. }
  23. func checkNext(t *testing.T, itr Iterator, expected bool) {
  24. itr.Next()
  25. valid := itr.Valid()
  26. require.Equal(t, expected, valid)
  27. }
  28. func checkNextPanics(t *testing.T, itr Iterator) {
  29. assert.Panics(t, func() { itr.Next() }, "checkNextPanics expected panic but didn't")
  30. }
  31. func checkDomain(t *testing.T, itr Iterator, start, end []byte) {
  32. ds, de := itr.Domain()
  33. assert.Equal(t, start, ds, "checkDomain domain start incorrect")
  34. assert.Equal(t, end, de, "checkDomain domain end incorrect")
  35. }
  36. func checkItem(t *testing.T, itr Iterator, key []byte, value []byte) {
  37. k, v := itr.Key(), itr.Value()
  38. assert.Exactly(t, key, k)
  39. assert.Exactly(t, value, v)
  40. }
  41. func checkInvalid(t *testing.T, itr Iterator) {
  42. checkValid(t, itr, false)
  43. checkKeyPanics(t, itr)
  44. checkValuePanics(t, itr)
  45. checkNextPanics(t, itr)
  46. }
  47. func checkKeyPanics(t *testing.T, itr Iterator) {
  48. assert.Panics(t, func() { itr.Key() }, "checkKeyPanics expected panic but didn't")
  49. }
  50. func checkValuePanics(t *testing.T, itr Iterator) {
  51. assert.Panics(t, func() { itr.Value() }, "checkValuePanics expected panic but didn't")
  52. }
  53. func newTempDB(t *testing.T, backend DBBackendType) (db DB, dbDir string) {
  54. dirname, err := ioutil.TempDir("", "db_common_test")
  55. require.Nil(t, err)
  56. return NewDB("testdb", backend, dirname), dirname
  57. }
  58. //----------------------------------------
  59. // mockDB
  60. // NOTE: not actually goroutine safe.
  61. // If you want something goroutine safe, maybe you just want a MemDB.
  62. type mockDB struct {
  63. mtx sync.Mutex
  64. calls map[string]int
  65. }
  66. func newMockDB() *mockDB {
  67. return &mockDB{
  68. calls: make(map[string]int),
  69. }
  70. }
  71. func (mdb *mockDB) Mutex() *sync.Mutex {
  72. return &(mdb.mtx)
  73. }
  74. func (mdb *mockDB) Get([]byte) []byte {
  75. mdb.calls["Get"]++
  76. return nil
  77. }
  78. func (mdb *mockDB) Has([]byte) bool {
  79. mdb.calls["Has"]++
  80. return false
  81. }
  82. func (mdb *mockDB) Set([]byte, []byte) {
  83. mdb.calls["Set"]++
  84. }
  85. func (mdb *mockDB) SetSync([]byte, []byte) {
  86. mdb.calls["SetSync"]++
  87. }
  88. func (mdb *mockDB) SetNoLock([]byte, []byte) {
  89. mdb.calls["SetNoLock"]++
  90. }
  91. func (mdb *mockDB) SetNoLockSync([]byte, []byte) {
  92. mdb.calls["SetNoLockSync"]++
  93. }
  94. func (mdb *mockDB) Delete([]byte) {
  95. mdb.calls["Delete"]++
  96. }
  97. func (mdb *mockDB) DeleteSync([]byte) {
  98. mdb.calls["DeleteSync"]++
  99. }
  100. func (mdb *mockDB) DeleteNoLock([]byte) {
  101. mdb.calls["DeleteNoLock"]++
  102. }
  103. func (mdb *mockDB) DeleteNoLockSync([]byte) {
  104. mdb.calls["DeleteNoLockSync"]++
  105. }
  106. func (mdb *mockDB) Iterator(start, end []byte) Iterator {
  107. mdb.calls["Iterator"]++
  108. return &mockIterator{}
  109. }
  110. func (mdb *mockDB) ReverseIterator(start, end []byte) Iterator {
  111. mdb.calls["ReverseIterator"]++
  112. return &mockIterator{}
  113. }
  114. func (mdb *mockDB) Close() {
  115. mdb.calls["Close"]++
  116. }
  117. func (mdb *mockDB) NewBatch() Batch {
  118. mdb.calls["NewBatch"]++
  119. return &memBatch{db: mdb}
  120. }
  121. func (mdb *mockDB) Print() {
  122. mdb.calls["Print"]++
  123. fmt.Printf("mockDB{%v}", mdb.Stats())
  124. }
  125. func (mdb *mockDB) Stats() map[string]string {
  126. mdb.calls["Stats"]++
  127. res := make(map[string]string)
  128. for key, count := range mdb.calls {
  129. res[key] = fmt.Sprintf("%d", count)
  130. }
  131. return res
  132. }
  133. //----------------------------------------
  134. // mockIterator
  135. type mockIterator struct{}
  136. func (mockIterator) Domain() (start []byte, end []byte) {
  137. return nil, nil
  138. }
  139. func (mockIterator) Valid() bool {
  140. return false
  141. }
  142. func (mockIterator) Next() {
  143. }
  144. func (mockIterator) Key() []byte {
  145. return nil
  146. }
  147. func (mockIterator) Value() []byte {
  148. return nil
  149. }
  150. func (mockIterator) Close() {
  151. }
  152. func benchmarkRandomReadsWrites(b *testing.B, db DB) {
  153. b.StopTimer()
  154. // create dummy data
  155. const numItems = int64(1000000)
  156. internal := map[int64]int64{}
  157. for i := 0; i < int(numItems); i++ {
  158. internal[int64(i)] = int64(0)
  159. }
  160. // fmt.Println("ok, starting")
  161. b.StartTimer()
  162. for i := 0; i < b.N; i++ {
  163. // Write something
  164. {
  165. idx := int64(cmn.RandInt()) % numItems
  166. internal[idx]++
  167. val := internal[idx]
  168. idxBytes := int642Bytes(int64(idx))
  169. valBytes := int642Bytes(int64(val))
  170. //fmt.Printf("Set %X -> %X\n", idxBytes, valBytes)
  171. db.Set(idxBytes, valBytes)
  172. }
  173. // Read something
  174. {
  175. idx := int64(cmn.RandInt()) % numItems
  176. valExp := internal[idx]
  177. idxBytes := int642Bytes(int64(idx))
  178. valBytes := db.Get(idxBytes)
  179. //fmt.Printf("Get %X -> %X\n", idxBytes, valBytes)
  180. if valExp == 0 {
  181. if !bytes.Equal(valBytes, nil) {
  182. b.Errorf("Expected %v for %v, got %X", nil, idx, valBytes)
  183. break
  184. }
  185. } else {
  186. if len(valBytes) != 8 {
  187. b.Errorf("Expected length 8 for %v, got %X", idx, valBytes)
  188. break
  189. }
  190. valGot := bytes2Int64(valBytes)
  191. if valExp != valGot {
  192. b.Errorf("Expected %v for %v, got %v", valExp, idx, valGot)
  193. break
  194. }
  195. }
  196. }
  197. }
  198. }
  199. func int642Bytes(i int64) []byte {
  200. buf := make([]byte, 8)
  201. binary.BigEndian.PutUint64(buf, uint64(i))
  202. return buf
  203. }
  204. func bytes2Int64(buf []byte) int64 {
  205. return int64(binary.BigEndian.Uint64(buf))
  206. }