blockmap_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. "github.com/syndtr/goleveldb/leveldb/util"
  12. )
  13. func genBlocks(n int) []protocol.BlockInfo {
  14. b := make([]protocol.BlockInfo, n)
  15. for i := range b {
  16. h := make([]byte, 32)
  17. for j := range h {
  18. h[j] = byte(i + j)
  19. }
  20. b[i].Size = int32(i)
  21. b[i].Hash = h
  22. }
  23. return b
  24. }
  25. var f1, f2, f3 protocol.FileInfo
  26. var folders = []string{"folder1", "folder2"}
  27. func init() {
  28. blocks := genBlocks(30)
  29. f1 = protocol.FileInfo{
  30. Name: "f1",
  31. Blocks: blocks[:10],
  32. }
  33. f2 = protocol.FileInfo{
  34. Name: "f2",
  35. Blocks: blocks[10:20],
  36. }
  37. f3 = protocol.FileInfo{
  38. Name: "f3",
  39. Blocks: blocks[20:],
  40. }
  41. }
  42. func setup() (*instance, *BlockFinder) {
  43. // Setup
  44. db := OpenMemory()
  45. return newInstance(db), NewBlockFinder(db)
  46. }
  47. func dbEmpty(db *instance) bool {
  48. iter := db.NewIterator(util.BytesPrefix([]byte{KeyTypeBlock}), nil)
  49. defer iter.Release()
  50. return !iter.Next()
  51. }
  52. func addToBlockMap(db *instance, folder []byte, fs []protocol.FileInfo) {
  53. t := db.newReadWriteTransaction()
  54. defer t.close()
  55. var keyBuf []byte
  56. blockBuf := make([]byte, 4)
  57. for _, f := range fs {
  58. if !f.IsDirectory() && !f.IsDeleted() && !f.IsInvalid() {
  59. name := []byte(f.Name)
  60. for i, block := range f.Blocks {
  61. binary.BigEndian.PutUint32(blockBuf, uint32(i))
  62. keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
  63. t.Put(keyBuf, blockBuf)
  64. }
  65. }
  66. }
  67. }
  68. func discardFromBlockMap(db *instance, folder []byte, fs []protocol.FileInfo) {
  69. t := db.newReadWriteTransaction()
  70. defer t.close()
  71. var keyBuf []byte
  72. for _, ef := range fs {
  73. if !ef.IsDirectory() && !ef.IsDeleted() && !ef.IsInvalid() {
  74. name := []byte(ef.Name)
  75. for _, block := range ef.Blocks {
  76. keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
  77. t.Delete(keyBuf)
  78. }
  79. }
  80. }
  81. }
  82. func TestBlockMapAddUpdateWipe(t *testing.T) {
  83. db, f := setup()
  84. if !dbEmpty(db) {
  85. t.Fatal("db not empty")
  86. }
  87. folder := []byte("folder1")
  88. f3.Type = protocol.FileInfoTypeDirectory
  89. addToBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3})
  90. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  91. if folder != "folder1" || file != "f1" || index != 0 {
  92. t.Fatal("Mismatch")
  93. }
  94. return true
  95. })
  96. f.Iterate(folders, f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
  97. if folder != "folder1" || file != "f2" || index != 0 {
  98. t.Fatal("Mismatch")
  99. }
  100. return true
  101. })
  102. f.Iterate(folders, f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
  103. t.Fatal("Unexpected block")
  104. return true
  105. })
  106. discardFromBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3})
  107. f1.Deleted = true
  108. f2.LocalFlags = protocol.FlagLocalMustRescan // one of the invalid markers
  109. addToBlockMap(db, folder, []protocol.FileInfo{f1, f2, f3})
  110. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  111. t.Fatal("Unexpected block")
  112. return false
  113. })
  114. f.Iterate(folders, f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
  115. t.Fatal("Unexpected block")
  116. return false
  117. })
  118. f.Iterate(folders, f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
  119. if folder != "folder1" || file != "f3" || index != 0 {
  120. t.Fatal("Mismatch")
  121. }
  122. return true
  123. })
  124. db.dropFolder(folder)
  125. if !dbEmpty(db) {
  126. t.Fatal("db not empty")
  127. }
  128. // Should not add
  129. addToBlockMap(db, folder, []protocol.FileInfo{f1, f2})
  130. if !dbEmpty(db) {
  131. t.Fatal("db not empty")
  132. }
  133. f1.Deleted = false
  134. f1.LocalFlags = 0
  135. f2.Deleted = false
  136. f2.LocalFlags = 0
  137. f3.Deleted = false
  138. f3.LocalFlags = 0
  139. }
  140. func TestBlockFinderLookup(t *testing.T) {
  141. db, f := setup()
  142. folder1 := []byte("folder1")
  143. folder2 := []byte("folder2")
  144. addToBlockMap(db, folder1, []protocol.FileInfo{f1})
  145. addToBlockMap(db, folder2, []protocol.FileInfo{f1})
  146. counter := 0
  147. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  148. counter++
  149. switch counter {
  150. case 1:
  151. if folder != "folder1" || file != "f1" || index != 0 {
  152. t.Fatal("Mismatch")
  153. }
  154. case 2:
  155. if folder != "folder2" || file != "f1" || index != 0 {
  156. t.Fatal("Mismatch")
  157. }
  158. default:
  159. t.Fatal("Unexpected block")
  160. }
  161. return false
  162. })
  163. if counter != 2 {
  164. t.Fatal("Incorrect count", counter)
  165. }
  166. discardFromBlockMap(db, folder1, []protocol.FileInfo{f1})
  167. f1.Deleted = true
  168. addToBlockMap(db, folder1, []protocol.FileInfo{f1})
  169. counter = 0
  170. f.Iterate(folders, f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
  171. counter++
  172. switch counter {
  173. case 1:
  174. if folder != "folder2" || file != "f1" || index != 0 {
  175. t.Fatal("Mismatch")
  176. }
  177. default:
  178. t.Fatal("Unexpected block")
  179. }
  180. return false
  181. })
  182. if counter != 1 {
  183. t.Fatal("Incorrect count")
  184. }
  185. f1.Deleted = false
  186. }