blockmap_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "encoding/binary"
  9. "testing"
  10. "github.com/syncthing/syncthing/lib/protocol"
  11. )
  12. var f1, f2, f3 protocol.FileInfo
  13. var folders = []string{"folder1", "folder2"}
  14. func init() {
  15. blocks := genBlocks(30)
  16. f1 = protocol.FileInfo{
  17. Name: "f1",
  18. Blocks: blocks[:10],
  19. }
  20. f2 = protocol.FileInfo{
  21. Name: "f2",
  22. Blocks: blocks[10:20],
  23. }
  24. f3 = protocol.FileInfo{
  25. Name: "f3",
  26. Blocks: blocks[20:],
  27. }
  28. }
  29. func setup(t testing.TB) (*Lowlevel, *BlockFinder) {
  30. t.Helper()
  31. db := newLowlevelMemory(t)
  32. return db, NewBlockFinder(db)
  33. }
  34. func dbEmpty(db *Lowlevel) bool {
  35. iter, err := db.NewPrefixIterator([]byte{KeyTypeBlock})
  36. if err != nil {
  37. panic(err)
  38. }
  39. defer iter.Release()
  40. return !iter.Next()
  41. }
  42. func addToBlockMap(db *Lowlevel, folder []byte, fs []protocol.FileInfo) error {
  43. t, err := db.newReadWriteTransaction()
  44. if err != nil {
  45. return err
  46. }
  47. defer t.close()
  48. var keyBuf []byte
  49. blockBuf := make([]byte, 4)
  50. for _, f := range fs {
  51. if !f.IsDirectory() && !f.IsDeleted() && !f.IsInvalid() {
  52. name := []byte(f.Name)
  53. for i, block := range f.Blocks {
  54. binary.BigEndian.PutUint32(blockBuf, uint32(i))
  55. keyBuf, err = t.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
  56. if err != nil {
  57. return err
  58. }
  59. if err := t.Put(keyBuf, blockBuf); err != nil {
  60. return err
  61. }
  62. }
  63. }
  64. }
  65. return t.Commit()
  66. }
  67. func discardFromBlockMap(db *Lowlevel, folder []byte, fs []protocol.FileInfo) error {
  68. t, err := db.newReadWriteTransaction()
  69. if err != nil {
  70. return err
  71. }
  72. defer t.close()
  73. var keyBuf []byte
  74. for _, ef := range fs {
  75. if !ef.IsDirectory() && !ef.IsDeleted() && !ef.IsInvalid() {
  76. name := []byte(ef.Name)
  77. for _, block := range ef.Blocks {
  78. keyBuf, err = t.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
  79. if err != nil {
  80. return err
  81. }
  82. if err := t.Delete(keyBuf); err != nil {
  83. return err
  84. }
  85. }
  86. }
  87. }
  88. return t.Commit()
  89. }
  90. func TestBlockMapAddUpdateWipe(t *testing.T) {
  91. db, f := setup(t)
  92. defer db.Close()
  93. if !dbEmpty(db) {
  94. t.Fatal("db not empty")
  95. }
  96. folder := []byte("folder1")
  97. f3.Type = protocol.FileInfoTypeDirectory
  98. if err := addToBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3}); err != nil {
  99. t.Fatal(err)
  100. }
  101. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  102. if folder != "folder1" || file != "f1" || index != 0 {
  103. t.Fatal("Mismatch")
  104. }
  105. return true
  106. })
  107. f.Iterate(folders, f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
  108. if folder != "folder1" || file != "f2" || index != 0 {
  109. t.Fatal("Mismatch")
  110. }
  111. return true
  112. })
  113. f.Iterate(folders, f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
  114. t.Fatal("Unexpected block")
  115. return true
  116. })
  117. if err := discardFromBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3}); err != nil {
  118. t.Fatal(err)
  119. }
  120. f1.Deleted = true
  121. f2.LocalFlags = protocol.FlagLocalMustRescan // one of the invalid markers
  122. if err := addToBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3}); err != nil {
  123. t.Fatal(err)
  124. }
  125. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  126. t.Fatal("Unexpected block")
  127. return false
  128. })
  129. f.Iterate(folders, f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
  130. t.Fatal("Unexpected block")
  131. return false
  132. })
  133. f.Iterate(folders, f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
  134. if folder != "folder1" || file != "f3" || index != 0 {
  135. t.Fatal("Mismatch")
  136. }
  137. return true
  138. })
  139. if err := db.dropFolder(folder); err != nil {
  140. t.Fatal(err)
  141. }
  142. if !dbEmpty(db) {
  143. t.Fatal("db not empty")
  144. }
  145. // Should not add
  146. if err := addToBlockMap(db, folder, []protocol.FileInfo{f1, f2}); err != nil {
  147. t.Fatal(err)
  148. }
  149. if !dbEmpty(db) {
  150. t.Fatal("db not empty")
  151. }
  152. f1.Deleted = false
  153. f1.LocalFlags = 0
  154. f2.Deleted = false
  155. f2.LocalFlags = 0
  156. f3.Deleted = false
  157. f3.LocalFlags = 0
  158. }
  159. func TestBlockFinderLookup(t *testing.T) {
  160. db, f := setup(t)
  161. defer db.Close()
  162. folder1 := []byte("folder1")
  163. folder2 := []byte("folder2")
  164. if err := addToBlockMap(db, folder1, []protocol.FileInfo{f1}); err != nil {
  165. t.Fatal(err)
  166. }
  167. if err := addToBlockMap(db, folder2, []protocol.FileInfo{f1}); err != nil {
  168. t.Fatal(err)
  169. }
  170. counter := 0
  171. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  172. counter++
  173. switch counter {
  174. case 1:
  175. if folder != "folder1" || file != "f1" || index != 0 {
  176. t.Fatal("Mismatch")
  177. }
  178. case 2:
  179. if folder != "folder2" || file != "f1" || index != 0 {
  180. t.Fatal("Mismatch")
  181. }
  182. default:
  183. t.Fatal("Unexpected block")
  184. }
  185. return false
  186. })
  187. if counter != 2 {
  188. t.Fatal("Incorrect count", counter)
  189. }
  190. if err := discardFromBlockMap(db, folder1, []protocol.FileInfo{f1}); err != nil {
  191. t.Fatal(err)
  192. }
  193. f1.Deleted = true
  194. if err := addToBlockMap(db, folder1, []protocol.FileInfo{f1}); err != nil {
  195. t.Fatal(err)
  196. }
  197. counter = 0
  198. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  199. counter++
  200. switch counter {
  201. case 1:
  202. if folder != "folder2" || file != "f1" || index != 0 {
  203. t.Fatal("Mismatch")
  204. }
  205. default:
  206. t.Fatal("Unexpected block")
  207. }
  208. return false
  209. })
  210. if counter != 1 {
  211. t.Fatal("Incorrect count")
  212. }
  213. f1.Deleted = false
  214. }