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.

292 lines
7.4 KiB

  1. package kvdb
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "sync"
  7. "testing"
  8. "github.com/hermeznetwork/hermez-node/common"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func addTestKV(t *testing.T, db *KVDB, k, v []byte) {
  13. tx, err := db.db.NewTx()
  14. require.NoError(t, err)
  15. err = tx.Put(k, v)
  16. require.NoError(t, err)
  17. err = tx.Commit()
  18. require.NoError(t, err)
  19. }
  20. func printCheckpoints(t *testing.T, path string) {
  21. files, err := ioutil.ReadDir(path)
  22. require.NoError(t, err)
  23. fmt.Println(path)
  24. for _, f := range files {
  25. fmt.Println(" " + f.Name())
  26. }
  27. }
  28. func TestCheckpoints(t *testing.T) {
  29. dir, err := ioutil.TempDir("", "sdb")
  30. require.NoError(t, err)
  31. defer require.NoError(t, os.RemoveAll(dir))
  32. db, err := NewKVDB(Config{Path: dir, Keep: 128})
  33. require.NoError(t, err)
  34. // add test key-values
  35. for i := 0; i < 10; i++ {
  36. addTestKV(t, db, []byte{byte(i), byte(i)}, []byte{byte(i * 2), byte(i * 2)})
  37. }
  38. // do checkpoints and check that currentBatch is correct
  39. err = db.MakeCheckpoint()
  40. require.NoError(t, err)
  41. cb, err := db.GetCurrentBatch()
  42. require.NoError(t, err)
  43. assert.Equal(t, common.BatchNum(1), cb)
  44. for i := 1; i < 10; i++ {
  45. err = db.MakeCheckpoint()
  46. require.NoError(t, err)
  47. cb, err = db.GetCurrentBatch()
  48. require.NoError(t, err)
  49. assert.Equal(t, common.BatchNum(i+1), cb)
  50. }
  51. // printCheckpoints(t, db.path)
  52. // reset checkpoint
  53. err = db.Reset(3)
  54. require.NoError(t, err)
  55. // check that reset can be repeated (as there exist the 'current' and
  56. // 'BatchNum3', from where the 'current' is a copy)
  57. err = db.Reset(3)
  58. require.NoError(t, err)
  59. printCheckpoints(t, db.cfg.Path)
  60. // check that currentBatch is as expected after Reset
  61. cb, err = db.GetCurrentBatch()
  62. require.NoError(t, err)
  63. assert.Equal(t, common.BatchNum(3), cb)
  64. // advance one checkpoint and check that currentBatch is fine
  65. err = db.MakeCheckpoint()
  66. require.NoError(t, err)
  67. cb, err = db.GetCurrentBatch()
  68. require.NoError(t, err)
  69. assert.Equal(t, common.BatchNum(4), cb)
  70. err = db.DeleteCheckpoint(common.BatchNum(1))
  71. require.NoError(t, err)
  72. err = db.DeleteCheckpoint(common.BatchNum(2))
  73. require.NoError(t, err)
  74. err = db.DeleteCheckpoint(common.BatchNum(1)) // does not exist, should return err
  75. assert.NotNil(t, err)
  76. err = db.DeleteCheckpoint(common.BatchNum(2)) // does not exist, should return err
  77. assert.NotNil(t, err)
  78. // Create a new KVDB which will get Reset from the initial KVDB
  79. dirLocal, err := ioutil.TempDir("", "ldb")
  80. require.NoError(t, err)
  81. defer require.NoError(t, os.RemoveAll(dirLocal))
  82. ldb, err := NewKVDB(Config{Path: dirLocal, Keep: 128})
  83. require.NoError(t, err)
  84. // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
  85. err = ldb.ResetFromSynchronizer(4, db)
  86. require.NoError(t, err)
  87. // check that currentBatch is 4 after the Reset
  88. cb, err = ldb.GetCurrentBatch()
  89. require.NoError(t, err)
  90. assert.Equal(t, common.BatchNum(4), cb)
  91. // advance one checkpoint in ldb
  92. err = ldb.MakeCheckpoint()
  93. require.NoError(t, err)
  94. cb, err = ldb.GetCurrentBatch()
  95. require.NoError(t, err)
  96. assert.Equal(t, common.BatchNum(5), cb)
  97. // Create a 3rd KVDB which will get Reset from the initial KVDB
  98. dirLocal2, err := ioutil.TempDir("", "ldb2")
  99. require.NoError(t, err)
  100. defer require.NoError(t, os.RemoveAll(dirLocal2))
  101. ldb2, err := NewKVDB(Config{Path: dirLocal2, Keep: 128})
  102. require.NoError(t, err)
  103. // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
  104. err = ldb2.ResetFromSynchronizer(4, db)
  105. require.NoError(t, err)
  106. // check that currentBatch is 4 after the Reset
  107. cb, err = ldb2.GetCurrentBatch()
  108. require.NoError(t, err)
  109. assert.Equal(t, common.BatchNum(4), cb)
  110. // advance one checkpoint in ldb2
  111. err = ldb2.MakeCheckpoint()
  112. require.NoError(t, err)
  113. cb, err = ldb2.GetCurrentBatch()
  114. require.NoError(t, err)
  115. assert.Equal(t, common.BatchNum(5), cb)
  116. debug := false
  117. if debug {
  118. printCheckpoints(t, db.cfg.Path)
  119. printCheckpoints(t, ldb.cfg.Path)
  120. printCheckpoints(t, ldb2.cfg.Path)
  121. }
  122. }
  123. func TestListCheckpoints(t *testing.T) {
  124. dir, err := ioutil.TempDir("", "tmpdb")
  125. require.NoError(t, err)
  126. defer require.NoError(t, os.RemoveAll(dir))
  127. db, err := NewKVDB(Config{Path: dir, Keep: 128})
  128. require.NoError(t, err)
  129. numCheckpoints := 16
  130. // do checkpoints
  131. for i := 0; i < numCheckpoints; i++ {
  132. err = db.MakeCheckpoint()
  133. require.NoError(t, err)
  134. }
  135. list, err := db.ListCheckpoints()
  136. require.NoError(t, err)
  137. assert.Equal(t, numCheckpoints, len(list))
  138. assert.Equal(t, 1, list[0])
  139. assert.Equal(t, numCheckpoints, list[len(list)-1])
  140. numReset := 10
  141. err = db.Reset(common.BatchNum(numReset))
  142. require.NoError(t, err)
  143. list, err = db.ListCheckpoints()
  144. require.NoError(t, err)
  145. assert.Equal(t, numReset, len(list))
  146. assert.Equal(t, 1, list[0])
  147. assert.Equal(t, numReset, list[len(list)-1])
  148. }
  149. func TestDeleteOldCheckpoints(t *testing.T) {
  150. dir, err := ioutil.TempDir("", "tmpdb")
  151. require.NoError(t, err)
  152. defer require.NoError(t, os.RemoveAll(dir))
  153. keep := 16
  154. db, err := NewKVDB(Config{Path: dir, Keep: keep})
  155. require.NoError(t, err)
  156. numCheckpoints := 32
  157. // do checkpoints and check that we never have more than `keep`
  158. // checkpoints
  159. for i := 0; i < numCheckpoints; i++ {
  160. err = db.MakeCheckpoint()
  161. require.NoError(t, err)
  162. err = db.DeleteOldCheckpoints()
  163. require.NoError(t, err)
  164. checkpoints, err := db.ListCheckpoints()
  165. require.NoError(t, err)
  166. assert.LessOrEqual(t, len(checkpoints), keep)
  167. }
  168. }
  169. func TestConcurrentDeleteOldCheckpoints(t *testing.T) {
  170. dir, err := ioutil.TempDir("", "tmpdb")
  171. require.NoError(t, err)
  172. defer require.NoError(t, os.RemoveAll(dir))
  173. keep := 16
  174. db, err := NewKVDB(Config{Path: dir, Keep: keep})
  175. require.NoError(t, err)
  176. numCheckpoints := 32
  177. var wg sync.WaitGroup
  178. wg.Add(numCheckpoints)
  179. // do checkpoints and check that we never have more than `keep`
  180. // checkpoints.
  181. // 1 async DeleteOldCheckpoint after 1 MakeCheckpoint
  182. for i := 0; i < numCheckpoints; i++ {
  183. err = db.MakeCheckpoint()
  184. require.NoError(t, err)
  185. go func() {
  186. err = db.DeleteOldCheckpoints()
  187. require.NoError(t, err)
  188. wg.Done()
  189. }()
  190. }
  191. wg.Wait()
  192. checkpoints, err := db.ListCheckpoints()
  193. require.NoError(t, err)
  194. assert.LessOrEqual(t, len(checkpoints), keep)
  195. wg.Add(numCheckpoints)
  196. // do checkpoints and check that we never have more than `keep`
  197. // checkpoints
  198. // 32 concurrent DeleteOldCheckpoint after 32 MakeCheckpoint
  199. for i := 0; i < numCheckpoints; i++ {
  200. err = db.MakeCheckpoint()
  201. require.NoError(t, err)
  202. }
  203. for i := 0; i < numCheckpoints; i++ {
  204. go func() {
  205. err = db.DeleteOldCheckpoints()
  206. require.NoError(t, err)
  207. wg.Done()
  208. }()
  209. }
  210. wg.Wait()
  211. checkpoints, err = db.ListCheckpoints()
  212. require.NoError(t, err)
  213. assert.LessOrEqual(t, len(checkpoints), keep)
  214. }
  215. func TestGetCurrentIdx(t *testing.T) {
  216. dir, err := ioutil.TempDir("", "tmpdb")
  217. require.NoError(t, err)
  218. defer require.NoError(t, os.RemoveAll(dir))
  219. keep := 16
  220. db, err := NewKVDB(Config{Path: dir, Keep: keep})
  221. require.NoError(t, err)
  222. idx, err := db.GetCurrentIdx()
  223. require.NoError(t, err)
  224. assert.Equal(t, common.Idx(255), idx)
  225. db.Close()
  226. db, err = NewKVDB(Config{Path: dir, Keep: keep})
  227. require.NoError(t, err)
  228. idx, err = db.GetCurrentIdx()
  229. require.NoError(t, err)
  230. assert.Equal(t, common.Idx(255), idx)
  231. err = db.MakeCheckpoint()
  232. require.NoError(t, err)
  233. idx, err = db.GetCurrentIdx()
  234. require.NoError(t, err)
  235. assert.Equal(t, common.Idx(255), idx)
  236. db.Close()
  237. db, err = NewKVDB(Config{Path: dir, Keep: keep})
  238. require.NoError(t, err)
  239. idx, err = db.GetCurrentIdx()
  240. require.NoError(t, err)
  241. assert.Equal(t, common.Idx(255), idx)
  242. }