db_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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. "bytes"
  9. "context"
  10. "testing"
  11. "github.com/syncthing/syncthing/lib/db/backend"
  12. "github.com/syncthing/syncthing/lib/fs"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. )
  15. func genBlocks(n int) []protocol.BlockInfo {
  16. b := make([]protocol.BlockInfo, n)
  17. for i := range b {
  18. h := make([]byte, 32)
  19. for j := range h {
  20. h[j] = byte(i + j)
  21. }
  22. b[i].Size = int32(i)
  23. b[i].Hash = h
  24. }
  25. return b
  26. }
  27. func TestIgnoredFiles(t *testing.T) {
  28. ldb, err := openJSONS("testdata/v0.14.48-ignoredfiles.db.jsons")
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. db := NewLowlevel(ldb)
  33. defer db.Close()
  34. if err := UpdateSchema(db); err != nil {
  35. t.Fatal(err)
  36. }
  37. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  38. // The contents of the database are like this:
  39. //
  40. // fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  41. // fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  42. // { // invalid (ignored) file
  43. // Name: "foo",
  44. // Type: protocol.FileInfoTypeFile,
  45. // Invalid: true,
  46. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1000}}},
  47. // },
  48. // { // regular file
  49. // Name: "bar",
  50. // Type: protocol.FileInfoTypeFile,
  51. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  52. // },
  53. // })
  54. // fs.Update(protocol.DeviceID{42}, []protocol.FileInfo{
  55. // { // invalid file
  56. // Name: "baz",
  57. // Type: protocol.FileInfoTypeFile,
  58. // Invalid: true,
  59. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1000}}},
  60. // },
  61. // { // regular file
  62. // Name: "quux",
  63. // Type: protocol.FileInfoTypeFile,
  64. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1002}}},
  65. // },
  66. // })
  67. // Local files should have the "ignored" bit in addition to just being
  68. // generally invalid if we want to look at the simulation of that bit.
  69. snap := fs.Snapshot()
  70. defer snap.Release()
  71. fi, ok := snap.Get(protocol.LocalDeviceID, "foo")
  72. if !ok {
  73. t.Fatal("foo should exist")
  74. }
  75. if !fi.IsInvalid() {
  76. t.Error("foo should be invalid")
  77. }
  78. if !fi.IsIgnored() {
  79. t.Error("foo should be ignored")
  80. }
  81. fi, ok = snap.Get(protocol.LocalDeviceID, "bar")
  82. if !ok {
  83. t.Fatal("bar should exist")
  84. }
  85. if fi.IsInvalid() {
  86. t.Error("bar should not be invalid")
  87. }
  88. if fi.IsIgnored() {
  89. t.Error("bar should not be ignored")
  90. }
  91. // Remote files have the invalid bit as usual, and the IsInvalid() method
  92. // should pick this up too.
  93. fi, ok = snap.Get(protocol.DeviceID{42}, "baz")
  94. if !ok {
  95. t.Fatal("baz should exist")
  96. }
  97. if !fi.IsInvalid() {
  98. t.Error("baz should be invalid")
  99. }
  100. if !fi.IsInvalid() {
  101. t.Error("baz should be invalid")
  102. }
  103. fi, ok = snap.Get(protocol.DeviceID{42}, "quux")
  104. if !ok {
  105. t.Fatal("quux should exist")
  106. }
  107. if fi.IsInvalid() {
  108. t.Error("quux should not be invalid")
  109. }
  110. if fi.IsInvalid() {
  111. t.Error("quux should not be invalid")
  112. }
  113. }
  114. const myID = 1
  115. var (
  116. remoteDevice0, remoteDevice1 protocol.DeviceID
  117. update0to3Folder = "UpdateSchema0to3"
  118. invalid = "invalid"
  119. slashPrefixed = "/notgood"
  120. haveUpdate0to3 map[protocol.DeviceID]fileList
  121. )
  122. func init() {
  123. remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  124. remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
  125. haveUpdate0to3 = map[protocol.DeviceID]fileList{
  126. protocol.LocalDeviceID: {
  127. protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  128. protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  129. },
  130. remoteDevice0: {
  131. protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
  132. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), RawInvalid: true},
  133. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
  134. },
  135. remoteDevice1: {
  136. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(7)},
  137. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(5), RawInvalid: true},
  138. protocol.FileInfo{Name: invalid, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1004}}}, Blocks: genBlocks(5), RawInvalid: true},
  139. },
  140. }
  141. }
  142. func TestUpdate0to3(t *testing.T) {
  143. ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. db := NewLowlevel(ldb)
  148. defer db.Close()
  149. updater := schemaUpdater{db}
  150. folder := []byte(update0to3Folder)
  151. if err := updater.updateSchema0to1(0); err != nil {
  152. t.Fatal(err)
  153. }
  154. trans, err := db.newReadOnlyTransaction()
  155. if err != nil {
  156. t.Fatal(err)
  157. }
  158. defer trans.Release()
  159. if _, ok, err := trans.getFile(folder, protocol.LocalDeviceID[:], []byte(slashPrefixed)); err != nil {
  160. t.Fatal(err)
  161. } else if ok {
  162. t.Error("File prefixed by '/' was not removed during transition to schema 1")
  163. }
  164. var key []byte
  165. key, err = db.keyer.GenerateGlobalVersionKey(nil, folder, []byte(invalid))
  166. if err != nil {
  167. t.Fatal(err)
  168. }
  169. if _, err := db.Get(key); err != nil {
  170. t.Error("Invalid file wasn't added to global list")
  171. }
  172. if err := updater.updateSchema1to2(1); err != nil {
  173. t.Fatal(err)
  174. }
  175. found := false
  176. trans, err = db.newReadOnlyTransaction()
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. defer trans.Release()
  181. _ = trans.withHaveSequence(folder, 0, func(fi protocol.FileIntf) bool {
  182. f := fi.(protocol.FileInfo)
  183. l.Infoln(f)
  184. if found {
  185. t.Error("Unexpected additional file via sequence", f.FileName())
  186. return true
  187. }
  188. if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, 0, true, true, 0) {
  189. found = true
  190. } else {
  191. t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
  192. }
  193. return true
  194. })
  195. if !found {
  196. t.Error("Local file wasn't added to sequence bucket", err)
  197. }
  198. if err := updater.updateSchema2to3(2); err != nil {
  199. t.Fatal(err)
  200. }
  201. need := map[string]protocol.FileInfo{
  202. haveUpdate0to3[remoteDevice0][0].Name: haveUpdate0to3[remoteDevice0][0],
  203. haveUpdate0to3[remoteDevice1][0].Name: haveUpdate0to3[remoteDevice1][0],
  204. haveUpdate0to3[remoteDevice0][2].Name: haveUpdate0to3[remoteDevice0][2],
  205. }
  206. trans, err = db.newReadOnlyTransaction()
  207. if err != nil {
  208. t.Fatal(err)
  209. }
  210. defer trans.Release()
  211. key, err = trans.keyer.GenerateNeedFileKey(nil, folder, nil)
  212. if err != nil {
  213. t.Fatal(err)
  214. }
  215. dbi, err := trans.NewPrefixIterator(key)
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. defer dbi.Release()
  220. for dbi.Next() {
  221. name := trans.keyer.NameFromGlobalVersionKey(dbi.Key())
  222. key, err = trans.keyer.GenerateGlobalVersionKey(key, folder, name)
  223. bs, err := trans.Get(key)
  224. if err != nil {
  225. t.Fatal(err)
  226. }
  227. var vl VersionListDeprecated
  228. if err := vl.Unmarshal(bs); err != nil {
  229. t.Fatal(err)
  230. }
  231. key, err = trans.keyer.GenerateDeviceFileKey(key, folder, vl.Versions[0].Device, name)
  232. fi, ok, err := trans.getFileTrunc(key, false)
  233. if err != nil {
  234. t.Fatal(err)
  235. }
  236. if !ok {
  237. device := "<invalid>"
  238. if dev, err := protocol.DeviceIDFromBytes(vl.Versions[0].Device); err != nil {
  239. device = dev.String()
  240. }
  241. t.Fatal("surprise missing global file", string(name), device)
  242. }
  243. e, ok := need[fi.FileName()]
  244. if !ok {
  245. t.Error("Got unexpected needed file:", fi.FileName())
  246. }
  247. f := fi.(protocol.FileInfo)
  248. delete(need, f.Name)
  249. if !f.IsEquivalentOptional(e, 0, true, true, 0) {
  250. t.Errorf("Wrong needed file, got %v, expected %v", f, e)
  251. }
  252. }
  253. if dbi.Error() != nil {
  254. t.Fatal(err)
  255. }
  256. for n := range need {
  257. t.Errorf(`Missing needed file "%v"`, n)
  258. }
  259. }
  260. // TestRepairSequence checks that a few hand-crafted messed-up sequence entries get fixed.
  261. func TestRepairSequence(t *testing.T) {
  262. db := NewLowlevel(backend.OpenMemory())
  263. defer db.Close()
  264. folderStr := "test"
  265. folder := []byte(folderStr)
  266. id := protocol.LocalDeviceID
  267. short := protocol.LocalDeviceID.Short()
  268. files := []protocol.FileInfo{
  269. {Name: "fine", Blocks: genBlocks(1)},
  270. {Name: "duplicate", Blocks: genBlocks(2)},
  271. {Name: "missing", Blocks: genBlocks(3)},
  272. {Name: "overwriting", Blocks: genBlocks(4)},
  273. {Name: "inconsistent", Blocks: genBlocks(5)},
  274. }
  275. for i, f := range files {
  276. files[i].Version = f.Version.Update(short)
  277. }
  278. trans, err := db.newReadWriteTransaction()
  279. if err != nil {
  280. t.Fatal(err)
  281. }
  282. defer trans.close()
  283. addFile := func(f protocol.FileInfo, seq int64) {
  284. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  285. if err != nil {
  286. t.Fatal(err)
  287. }
  288. if err := trans.putFile(dk, f, false); err != nil {
  289. t.Fatal(err)
  290. }
  291. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  292. if err != nil {
  293. t.Fatal(err)
  294. }
  295. if err := trans.Put(sk, dk); err != nil {
  296. t.Fatal(err)
  297. }
  298. }
  299. // Plain normal entry
  300. var seq int64 = 1
  301. files[0].Sequence = 1
  302. addFile(files[0], seq)
  303. // Second entry once updated with original sequence still in place
  304. f := files[1]
  305. f.Sequence = int64(len(files) + 1)
  306. addFile(f, f.Sequence)
  307. // Original sequence entry
  308. seq++
  309. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  310. if err != nil {
  311. t.Fatal(err)
  312. }
  313. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. if err := trans.Put(sk, dk); err != nil {
  318. t.Fatal(err)
  319. }
  320. // File later overwritten thus missing sequence entry
  321. seq++
  322. files[2].Sequence = seq
  323. addFile(files[2], seq)
  324. // File overwriting previous sequence entry (no seq bump)
  325. seq++
  326. files[3].Sequence = seq
  327. addFile(files[3], seq)
  328. // Inconistent file
  329. seq++
  330. files[4].Sequence = 101
  331. addFile(files[4], seq)
  332. // And a sequence entry pointing at nothing because why not
  333. sk, err = trans.keyer.GenerateSequenceKey(nil, folder, 100001)
  334. if err != nil {
  335. t.Fatal(err)
  336. }
  337. dk, err = trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte("nonexisting"))
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. if err := trans.Put(sk, dk); err != nil {
  342. t.Fatal(err)
  343. }
  344. if err := trans.Commit(); err != nil {
  345. t.Fatal(err)
  346. }
  347. // Loading the metadata for the first time means a "re"calculation happens,
  348. // along which the sequences get repaired too.
  349. db.gcMut.RLock()
  350. _ = db.loadMetadataTracker(folderStr)
  351. db.gcMut.RUnlock()
  352. if err != nil {
  353. t.Fatal(err)
  354. }
  355. // Check the db
  356. ro, err := db.newReadOnlyTransaction()
  357. if err != nil {
  358. t.Fatal(err)
  359. }
  360. defer ro.close()
  361. it, err := ro.NewPrefixIterator([]byte{KeyTypeDevice})
  362. if err != nil {
  363. t.Fatal(err)
  364. }
  365. defer it.Release()
  366. for it.Next() {
  367. fi, err := ro.unmarshalTrunc(it.Value(), true)
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. if sk, err = ro.keyer.GenerateSequenceKey(sk, folder, fi.SequenceNo()); err != nil {
  372. t.Fatal(err)
  373. }
  374. dk, err := ro.Get(sk)
  375. if backend.IsNotFound(err) {
  376. t.Error("Missing sequence entry for", fi.FileName())
  377. } else if err != nil {
  378. t.Fatal(err)
  379. }
  380. if !bytes.Equal(it.Key(), dk) {
  381. t.Errorf("Wrong key for %v, expected %s, got %s", f.FileName(), it.Key(), dk)
  382. }
  383. }
  384. if err := it.Error(); err != nil {
  385. t.Fatal(err)
  386. }
  387. it.Release()
  388. it, err = ro.NewPrefixIterator([]byte{KeyTypeSequence})
  389. if err != nil {
  390. t.Fatal(err)
  391. }
  392. defer it.Release()
  393. for it.Next() {
  394. intf, ok, err := ro.getFileTrunc(it.Value(), false)
  395. if err != nil {
  396. t.Fatal(err)
  397. }
  398. fi := intf.(protocol.FileInfo)
  399. seq := ro.keyer.SequenceFromSequenceKey(it.Key())
  400. if !ok {
  401. t.Errorf("Sequence entry %v points at nothing", seq)
  402. } else if fi.SequenceNo() != seq {
  403. t.Errorf("Inconsistent sequence entry for %v: %v != %v", fi.FileName(), fi.SequenceNo(), seq)
  404. }
  405. if len(fi.Blocks) == 0 {
  406. t.Error("Missing blocks in", fi.FileName())
  407. }
  408. }
  409. if err := it.Error(); err != nil {
  410. t.Fatal(err)
  411. }
  412. it.Release()
  413. }
  414. func TestDowngrade(t *testing.T) {
  415. db := NewLowlevel(backend.OpenMemory())
  416. defer db.Close()
  417. // sets the min version etc
  418. if err := UpdateSchema(db); err != nil {
  419. t.Fatal(err)
  420. }
  421. // Bump the database version to something newer than we actually support
  422. miscDB := NewMiscDataNamespace(db)
  423. if err := miscDB.PutInt64("dbVersion", dbVersion+1); err != nil {
  424. t.Fatal(err)
  425. }
  426. l.Infoln(dbVersion)
  427. // Pretend we just opened the DB and attempt to update it again
  428. err := UpdateSchema(db)
  429. if err, ok := err.(*databaseDowngradeError); !ok {
  430. t.Fatal("Expected error due to database downgrade, got", err)
  431. } else if err.minSyncthingVersion != dbMinSyncthingVersion {
  432. t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
  433. }
  434. }
  435. func TestCheckGlobals(t *testing.T) {
  436. db := NewLowlevel(backend.OpenMemory())
  437. defer db.Close()
  438. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeFake, ""), db)
  439. // Add any file
  440. name := "foo"
  441. fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  442. {
  443. Name: name,
  444. Type: protocol.FileInfoTypeFile,
  445. Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  446. },
  447. })
  448. // Remove just the file entry
  449. if err := db.dropPrefix([]byte{KeyTypeDevice}); err != nil {
  450. t.Fatal(err)
  451. }
  452. // Clean up global entry of the now missing file
  453. if err := db.checkGlobals([]byte(fs.folder)); err != nil {
  454. t.Fatal(err)
  455. }
  456. // Check that the global entry is gone
  457. gk, err := db.keyer.GenerateGlobalVersionKey(nil, []byte(fs.folder), []byte(name))
  458. if err != nil {
  459. t.Fatal(err)
  460. }
  461. _, err = db.Get(gk)
  462. if !backend.IsNotFound(err) {
  463. t.Error("Expected key missing error, got", err)
  464. }
  465. }
  466. func TestUpdateTo10(t *testing.T) {
  467. ldb, err := openJSONS("./testdata/v1.4.0-updateTo10.json")
  468. if err != nil {
  469. t.Fatal(err)
  470. }
  471. db := NewLowlevel(ldb)
  472. defer db.Close()
  473. UpdateSchema(db)
  474. folder := "test"
  475. meta := db.getMetaAndCheck(folder)
  476. empty := Counts{}
  477. c := meta.Counts(protocol.LocalDeviceID, needFlag)
  478. if c.Files != 1 {
  479. t.Error("Expected 1 needed file locally, got", c.Files)
  480. }
  481. c.Files = 0
  482. if c.Deleted != 1 {
  483. t.Error("Expected 1 needed deletion locally, got", c.Deleted)
  484. }
  485. c.Deleted = 0
  486. if !c.Equal(empty) {
  487. t.Error("Expected all counts to be zero, got", c)
  488. }
  489. c = meta.Counts(remoteDevice0, needFlag)
  490. if !c.Equal(empty) {
  491. t.Error("Expected all counts to be zero, got", c)
  492. }
  493. trans, err := db.newReadOnlyTransaction()
  494. if err != nil {
  495. t.Fatal(err)
  496. }
  497. defer trans.Release()
  498. // a
  499. vl, err := trans.getGlobalVersions(nil, []byte(folder), []byte("a"))
  500. if err != nil {
  501. t.Fatal(err)
  502. }
  503. for _, v := range vl.RawVersions {
  504. if !v.Deleted {
  505. t.Error("Unexpected undeleted global version for a")
  506. }
  507. }
  508. // b
  509. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("b"))
  510. if err != nil {
  511. t.Fatal(err)
  512. }
  513. if !vl.RawVersions[0].Deleted {
  514. t.Error("vl.Versions[0] not deleted for b")
  515. }
  516. if vl.RawVersions[1].Deleted {
  517. t.Error("vl.Versions[1] deleted for b")
  518. }
  519. // c
  520. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("c"))
  521. if err != nil {
  522. t.Fatal(err)
  523. }
  524. if vl.RawVersions[0].Deleted {
  525. t.Error("vl.Versions[0] deleted for c")
  526. }
  527. if !vl.RawVersions[1].Deleted {
  528. t.Error("vl.Versions[1] not deleted for c")
  529. }
  530. }
  531. func TestDropDuplicates(t *testing.T) {
  532. names := []string{
  533. "foo",
  534. "bar",
  535. "dcxvoijnds",
  536. "3d/dsfase/4/ss2",
  537. }
  538. tcs := []struct{ in, out []int }{
  539. {[]int{0}, []int{0}},
  540. {[]int{0, 1}, []int{0, 1}},
  541. {[]int{0, 1, 0, 1}, []int{0, 1}},
  542. {[]int{0, 1, 1, 1, 1}, []int{0, 1}},
  543. {[]int{0, 0, 0, 1}, []int{0, 1}},
  544. {[]int{0, 1, 2, 3}, []int{0, 1, 2, 3}},
  545. {[]int{3, 2, 1, 0, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  546. {[]int{0, 1, 1, 3, 0, 1, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  547. }
  548. for tci, tc := range tcs {
  549. inp := make([]protocol.FileInfo, len(tc.in))
  550. expSeq := make(map[string]int)
  551. for i, j := range tc.in {
  552. inp[i] = protocol.FileInfo{Name: names[j], Sequence: int64(i)}
  553. expSeq[names[j]] = i
  554. }
  555. outp := normalizeFilenamesAndDropDuplicates(inp)
  556. if len(outp) != len(tc.out) {
  557. t.Errorf("tc %v: Expected %v entries, got %v", tci, len(tc.out), len(outp))
  558. continue
  559. }
  560. for i, f := range outp {
  561. if exp := names[tc.out[i]]; exp != f.Name {
  562. t.Errorf("tc %v: Got file %v at pos %v, expected %v", tci, f.Name, i, exp)
  563. }
  564. if exp := int64(expSeq[outp[i].Name]); exp != f.Sequence {
  565. t.Errorf("tc %v: Got sequence %v at pos %v, expected %v", tci, f.Sequence, i, exp)
  566. }
  567. }
  568. }
  569. }
  570. func TestGCIndirect(t *testing.T) {
  571. // Verify that the gcIndirect run actually removes block lists.
  572. db := NewLowlevel(backend.OpenMemory())
  573. defer db.Close()
  574. meta := newMetadataTracker(db.keyer)
  575. // Add three files with different block lists
  576. files := []protocol.FileInfo{
  577. {Name: "a", Blocks: genBlocks(100)},
  578. {Name: "b", Blocks: genBlocks(200)},
  579. {Name: "c", Blocks: genBlocks(300)},
  580. }
  581. db.updateLocalFiles([]byte("folder"), files, meta)
  582. // Run a GC pass
  583. db.gcIndirect(context.Background())
  584. // Verify that we have three different block lists
  585. n, err := numBlockLists(db)
  586. if err != nil {
  587. t.Fatal(err)
  588. }
  589. if n != len(files) {
  590. t.Fatal("expected each file to have a block list")
  591. }
  592. // Change the block lists for each file
  593. for i := range files {
  594. files[i].Version = files[i].Version.Update(42)
  595. files[i].Blocks = genBlocks(len(files[i].Blocks) + 1)
  596. }
  597. db.updateLocalFiles([]byte("folder"), files, meta)
  598. // Verify that we now have *six* different block lists
  599. n, err = numBlockLists(db)
  600. if err != nil {
  601. t.Fatal(err)
  602. }
  603. if n != 2*len(files) {
  604. t.Fatal("expected both old and new block lists to exist")
  605. }
  606. // Run a GC pass
  607. db.gcIndirect(context.Background())
  608. // Verify that we now have just the three we need, again
  609. n, err = numBlockLists(db)
  610. if err != nil {
  611. t.Fatal(err)
  612. }
  613. if n != len(files) {
  614. t.Fatal("expected GC to collect all but the needed ones")
  615. }
  616. // Double check the correctness by loading the block lists and comparing with what we stored
  617. tr, err := db.newReadOnlyTransaction()
  618. if err != nil {
  619. t.Fatal()
  620. }
  621. defer tr.Release()
  622. for _, f := range files {
  623. fi, ok, err := tr.getFile([]byte("folder"), protocol.LocalDeviceID[:], []byte(f.Name))
  624. if err != nil {
  625. t.Fatal(err)
  626. }
  627. if !ok {
  628. t.Fatal("mysteriously missing")
  629. }
  630. if len(fi.Blocks) != len(f.Blocks) {
  631. t.Fatal("block list mismatch")
  632. }
  633. for i := range fi.Blocks {
  634. if !bytes.Equal(fi.Blocks[i].Hash, f.Blocks[i].Hash) {
  635. t.Fatal("hash mismatch")
  636. }
  637. }
  638. }
  639. }
  640. func numBlockLists(db *Lowlevel) (int, error) {
  641. it, err := db.Backend.NewPrefixIterator([]byte{KeyTypeBlockList})
  642. if err != nil {
  643. return 0, err
  644. }
  645. defer it.Release()
  646. n := 0
  647. for it.Next() {
  648. n++
  649. }
  650. if err := it.Error(); err != nil {
  651. return 0, err
  652. }
  653. return n, nil
  654. }