db_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  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. "fmt"
  11. "testing"
  12. "github.com/syncthing/syncthing/lib/db/backend"
  13. "github.com/syncthing/syncthing/lib/fs"
  14. "github.com/syncthing/syncthing/lib/protocol"
  15. )
  16. func genBlocks(n int) []protocol.BlockInfo {
  17. b := make([]protocol.BlockInfo, n)
  18. for i := range b {
  19. h := make([]byte, 32)
  20. for j := range h {
  21. h[j] = byte(i + j)
  22. }
  23. b[i].Size = i
  24. b[i].Hash = h
  25. }
  26. return b
  27. }
  28. func TestIgnoredFiles(t *testing.T) {
  29. ldb, err := openJSONS("testdata/v0.14.48-ignoredfiles.db.jsons")
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. db := NewLowlevel(ldb)
  34. defer db.Close()
  35. if err := UpdateSchema(db); err != nil {
  36. t.Fatal(err)
  37. }
  38. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  39. // The contents of the database are like this:
  40. //
  41. // fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  42. // fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  43. // { // invalid (ignored) file
  44. // Name: "foo",
  45. // Type: protocol.FileInfoTypeFile,
  46. // Invalid: true,
  47. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1000}}},
  48. // },
  49. // { // regular file
  50. // Name: "bar",
  51. // Type: protocol.FileInfoTypeFile,
  52. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  53. // },
  54. // })
  55. // fs.Update(protocol.DeviceID{42}, []protocol.FileInfo{
  56. // { // invalid file
  57. // Name: "baz",
  58. // Type: protocol.FileInfoTypeFile,
  59. // Invalid: true,
  60. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1000}}},
  61. // },
  62. // { // regular file
  63. // Name: "quux",
  64. // Type: protocol.FileInfoTypeFile,
  65. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1002}}},
  66. // },
  67. // })
  68. // Local files should have the "ignored" bit in addition to just being
  69. // generally invalid if we want to look at the simulation of that bit.
  70. snap := fs.Snapshot()
  71. defer snap.Release()
  72. fi, ok := snap.Get(protocol.LocalDeviceID, "foo")
  73. if !ok {
  74. t.Fatal("foo should exist")
  75. }
  76. if !fi.IsInvalid() {
  77. t.Error("foo should be invalid")
  78. }
  79. if !fi.IsIgnored() {
  80. t.Error("foo should be ignored")
  81. }
  82. fi, ok = snap.Get(protocol.LocalDeviceID, "bar")
  83. if !ok {
  84. t.Fatal("bar should exist")
  85. }
  86. if fi.IsInvalid() {
  87. t.Error("bar should not be invalid")
  88. }
  89. if fi.IsIgnored() {
  90. t.Error("bar should not be ignored")
  91. }
  92. // Remote files have the invalid bit as usual, and the IsInvalid() method
  93. // should pick this up too.
  94. fi, ok = snap.Get(protocol.DeviceID{42}, "baz")
  95. if !ok {
  96. t.Fatal("baz should exist")
  97. }
  98. if !fi.IsInvalid() {
  99. t.Error("baz should be invalid")
  100. }
  101. if !fi.IsInvalid() {
  102. t.Error("baz should be invalid")
  103. }
  104. fi, ok = snap.Get(protocol.DeviceID{42}, "quux")
  105. if !ok {
  106. t.Fatal("quux should exist")
  107. }
  108. if fi.IsInvalid() {
  109. t.Error("quux should not be invalid")
  110. }
  111. if fi.IsInvalid() {
  112. t.Error("quux should not be invalid")
  113. }
  114. }
  115. const myID = 1
  116. var (
  117. remoteDevice0, remoteDevice1 protocol.DeviceID
  118. update0to3Folder = "UpdateSchema0to3"
  119. invalid = "invalid"
  120. slashPrefixed = "/notgood"
  121. haveUpdate0to3 map[protocol.DeviceID]fileList
  122. )
  123. func init() {
  124. remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  125. remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
  126. haveUpdate0to3 = map[protocol.DeviceID]fileList{
  127. protocol.LocalDeviceID: {
  128. protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  129. protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  130. },
  131. remoteDevice0: {
  132. protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
  133. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), RawInvalid: true},
  134. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
  135. },
  136. remoteDevice1: {
  137. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(7)},
  138. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(5), RawInvalid: true},
  139. protocol.FileInfo{Name: invalid, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1004}}}, Blocks: genBlocks(5), RawInvalid: true},
  140. },
  141. }
  142. }
  143. func TestUpdate0to3(t *testing.T) {
  144. ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
  145. if err != nil {
  146. t.Fatal(err)
  147. }
  148. db := NewLowlevel(ldb)
  149. defer db.Close()
  150. updater := schemaUpdater{db}
  151. folder := []byte(update0to3Folder)
  152. if err := updater.updateSchema0to1(0); err != nil {
  153. t.Fatal(err)
  154. }
  155. trans, err := db.newReadOnlyTransaction()
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. defer trans.Release()
  160. if _, ok, err := trans.getFile(folder, protocol.LocalDeviceID[:], []byte(slashPrefixed)); err != nil {
  161. t.Fatal(err)
  162. } else if ok {
  163. t.Error("File prefixed by '/' was not removed during transition to schema 1")
  164. }
  165. var key []byte
  166. key, err = db.keyer.GenerateGlobalVersionKey(nil, folder, []byte(invalid))
  167. if err != nil {
  168. t.Fatal(err)
  169. }
  170. if _, err := db.Get(key); err != nil {
  171. t.Error("Invalid file wasn't added to global list")
  172. }
  173. if err := updater.updateSchema1to2(1); err != nil {
  174. t.Fatal(err)
  175. }
  176. found := false
  177. trans, err = db.newReadOnlyTransaction()
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. defer trans.Release()
  182. _ = trans.withHaveSequence(folder, 0, func(fi protocol.FileIntf) bool {
  183. f := fi.(protocol.FileInfo)
  184. l.Infoln(f)
  185. if found {
  186. t.Error("Unexpected additional file via sequence", f.FileName())
  187. return true
  188. }
  189. if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, 0, true, true, 0) {
  190. found = true
  191. } else {
  192. t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
  193. }
  194. return true
  195. })
  196. if !found {
  197. t.Error("Local file wasn't added to sequence bucket", err)
  198. }
  199. if err := updater.updateSchema2to3(2); err != nil {
  200. t.Fatal(err)
  201. }
  202. need := map[string]protocol.FileInfo{
  203. haveUpdate0to3[remoteDevice0][0].Name: haveUpdate0to3[remoteDevice0][0],
  204. haveUpdate0to3[remoteDevice1][0].Name: haveUpdate0to3[remoteDevice1][0],
  205. haveUpdate0to3[remoteDevice0][2].Name: haveUpdate0to3[remoteDevice0][2],
  206. }
  207. trans, err = db.newReadOnlyTransaction()
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. defer trans.Release()
  212. key, err = trans.keyer.GenerateNeedFileKey(nil, folder, nil)
  213. if err != nil {
  214. t.Fatal(err)
  215. }
  216. dbi, err := trans.NewPrefixIterator(key)
  217. if err != nil {
  218. t.Fatal(err)
  219. }
  220. defer dbi.Release()
  221. for dbi.Next() {
  222. name := trans.keyer.NameFromGlobalVersionKey(dbi.Key())
  223. key, err = trans.keyer.GenerateGlobalVersionKey(key, folder, name)
  224. bs, err := trans.Get(key)
  225. if err != nil {
  226. t.Fatal(err)
  227. }
  228. var vl VersionListDeprecated
  229. if err := vl.Unmarshal(bs); err != nil {
  230. t.Fatal(err)
  231. }
  232. key, err = trans.keyer.GenerateDeviceFileKey(key, folder, vl.Versions[0].Device, name)
  233. fi, ok, err := trans.getFileTrunc(key, false)
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. if !ok {
  238. device := "<invalid>"
  239. if dev, err := protocol.DeviceIDFromBytes(vl.Versions[0].Device); err != nil {
  240. device = dev.String()
  241. }
  242. t.Fatal("surprise missing global file", string(name), device)
  243. }
  244. e, ok := need[fi.FileName()]
  245. if !ok {
  246. t.Error("Got unexpected needed file:", fi.FileName())
  247. }
  248. f := fi.(protocol.FileInfo)
  249. delete(need, f.Name)
  250. if !f.IsEquivalentOptional(e, 0, true, true, 0) {
  251. t.Errorf("Wrong needed file, got %v, expected %v", f, e)
  252. }
  253. }
  254. if dbi.Error() != nil {
  255. t.Fatal(err)
  256. }
  257. for n := range need {
  258. t.Errorf(`Missing needed file "%v"`, n)
  259. }
  260. }
  261. // TestRepairSequence checks that a few hand-crafted messed-up sequence entries get fixed.
  262. func TestRepairSequence(t *testing.T) {
  263. db := NewLowlevel(backend.OpenMemory())
  264. defer db.Close()
  265. folderStr := "test"
  266. folder := []byte(folderStr)
  267. id := protocol.LocalDeviceID
  268. short := protocol.LocalDeviceID.Short()
  269. files := []protocol.FileInfo{
  270. {Name: "fine", Blocks: genBlocks(1)},
  271. {Name: "duplicate", Blocks: genBlocks(2)},
  272. {Name: "missing", Blocks: genBlocks(3)},
  273. {Name: "overwriting", Blocks: genBlocks(4)},
  274. {Name: "inconsistent", Blocks: genBlocks(5)},
  275. {Name: "inconsistentNotIndirected", Blocks: genBlocks(2)},
  276. }
  277. for i, f := range files {
  278. files[i].Version = f.Version.Update(short)
  279. }
  280. trans, err := db.newReadWriteTransaction()
  281. if err != nil {
  282. t.Fatal(err)
  283. }
  284. defer trans.close()
  285. addFile := func(f protocol.FileInfo, seq int64) {
  286. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  287. if err != nil {
  288. t.Fatal(err)
  289. }
  290. if err := trans.putFile(dk, f); err != nil {
  291. t.Fatal(err)
  292. }
  293. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  294. if err != nil {
  295. t.Fatal(err)
  296. }
  297. if err := trans.Put(sk, dk); err != nil {
  298. t.Fatal(err)
  299. }
  300. }
  301. // Plain normal entry
  302. var seq int64 = 1
  303. files[0].Sequence = 1
  304. addFile(files[0], seq)
  305. // Second entry once updated with original sequence still in place
  306. f := files[1]
  307. f.Sequence = int64(len(files) + 1)
  308. addFile(f, f.Sequence)
  309. // Original sequence entry
  310. seq++
  311. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  312. if err != nil {
  313. t.Fatal(err)
  314. }
  315. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  316. if err != nil {
  317. t.Fatal(err)
  318. }
  319. if err := trans.Put(sk, dk); err != nil {
  320. t.Fatal(err)
  321. }
  322. // File later overwritten thus missing sequence entry
  323. seq++
  324. files[2].Sequence = seq
  325. addFile(files[2], seq)
  326. // File overwriting previous sequence entry (no seq bump)
  327. seq++
  328. files[3].Sequence = seq
  329. addFile(files[3], seq)
  330. // Inconistent files
  331. seq++
  332. files[4].Sequence = 101
  333. addFile(files[4], seq)
  334. seq++
  335. files[5].Sequence = 102
  336. addFile(files[5], seq)
  337. // And a sequence entry pointing at nothing because why not
  338. sk, err = trans.keyer.GenerateSequenceKey(nil, folder, 100001)
  339. if err != nil {
  340. t.Fatal(err)
  341. }
  342. dk, err = trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte("nonexisting"))
  343. if err != nil {
  344. t.Fatal(err)
  345. }
  346. if err := trans.Put(sk, dk); err != nil {
  347. t.Fatal(err)
  348. }
  349. if err := trans.Commit(); err != nil {
  350. t.Fatal(err)
  351. }
  352. // Loading the metadata for the first time means a "re"calculation happens,
  353. // along which the sequences get repaired too.
  354. db.gcMut.RLock()
  355. _ = db.loadMetadataTracker(folderStr)
  356. db.gcMut.RUnlock()
  357. if err != nil {
  358. t.Fatal(err)
  359. }
  360. // Check the db
  361. ro, err := db.newReadOnlyTransaction()
  362. if err != nil {
  363. t.Fatal(err)
  364. }
  365. defer ro.close()
  366. it, err := ro.NewPrefixIterator([]byte{KeyTypeDevice})
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. defer it.Release()
  371. for it.Next() {
  372. fi, err := ro.unmarshalTrunc(it.Value(), true)
  373. if err != nil {
  374. t.Fatal(err)
  375. }
  376. if sk, err = ro.keyer.GenerateSequenceKey(sk, folder, fi.SequenceNo()); err != nil {
  377. t.Fatal(err)
  378. }
  379. dk, err := ro.Get(sk)
  380. if backend.IsNotFound(err) {
  381. t.Error("Missing sequence entry for", fi.FileName())
  382. } else if err != nil {
  383. t.Fatal(err)
  384. }
  385. if !bytes.Equal(it.Key(), dk) {
  386. t.Errorf("Wrong key for %v, expected %s, got %s", f.FileName(), it.Key(), dk)
  387. }
  388. }
  389. if err := it.Error(); err != nil {
  390. t.Fatal(err)
  391. }
  392. it.Release()
  393. it, err = ro.NewPrefixIterator([]byte{KeyTypeSequence})
  394. if err != nil {
  395. t.Fatal(err)
  396. }
  397. defer it.Release()
  398. for it.Next() {
  399. intf, ok, err := ro.getFileTrunc(it.Value(), false)
  400. if err != nil {
  401. t.Fatal(err)
  402. }
  403. fi := intf.(protocol.FileInfo)
  404. seq := ro.keyer.SequenceFromSequenceKey(it.Key())
  405. if !ok {
  406. t.Errorf("Sequence entry %v points at nothing", seq)
  407. } else if fi.SequenceNo() != seq {
  408. t.Errorf("Inconsistent sequence entry for %v: %v != %v", fi.FileName(), fi.SequenceNo(), seq)
  409. }
  410. if len(fi.Blocks) == 0 {
  411. t.Error("Missing blocks in", fi.FileName())
  412. }
  413. }
  414. if err := it.Error(); err != nil {
  415. t.Fatal(err)
  416. }
  417. it.Release()
  418. }
  419. func TestDowngrade(t *testing.T) {
  420. db := NewLowlevel(backend.OpenMemory())
  421. defer db.Close()
  422. // sets the min version etc
  423. if err := UpdateSchema(db); err != nil {
  424. t.Fatal(err)
  425. }
  426. // Bump the database version to something newer than we actually support
  427. miscDB := NewMiscDataNamespace(db)
  428. if err := miscDB.PutInt64("dbVersion", dbVersion+1); err != nil {
  429. t.Fatal(err)
  430. }
  431. l.Infoln(dbVersion)
  432. // Pretend we just opened the DB and attempt to update it again
  433. err := UpdateSchema(db)
  434. if err, ok := err.(*databaseDowngradeError); !ok {
  435. t.Fatal("Expected error due to database downgrade, got", err)
  436. } else if err.minSyncthingVersion != dbMinSyncthingVersion {
  437. t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
  438. }
  439. }
  440. func TestCheckGlobals(t *testing.T) {
  441. db := NewLowlevel(backend.OpenMemory())
  442. defer db.Close()
  443. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeFake, ""), db)
  444. // Add any file
  445. name := "foo"
  446. fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  447. {
  448. Name: name,
  449. Type: protocol.FileInfoTypeFile,
  450. Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  451. },
  452. })
  453. // Remove just the file entry
  454. if err := db.dropPrefix([]byte{KeyTypeDevice}); err != nil {
  455. t.Fatal(err)
  456. }
  457. // Clean up global entry of the now missing file
  458. if err := db.checkGlobals([]byte(fs.folder)); err != nil {
  459. t.Fatal(err)
  460. }
  461. // Check that the global entry is gone
  462. gk, err := db.keyer.GenerateGlobalVersionKey(nil, []byte(fs.folder), []byte(name))
  463. if err != nil {
  464. t.Fatal(err)
  465. }
  466. _, err = db.Get(gk)
  467. if !backend.IsNotFound(err) {
  468. t.Error("Expected key missing error, got", err)
  469. }
  470. }
  471. func TestUpdateTo10(t *testing.T) {
  472. ldb, err := openJSONS("./testdata/v1.4.0-updateTo10.json")
  473. if err != nil {
  474. t.Fatal(err)
  475. }
  476. db := NewLowlevel(ldb)
  477. defer db.Close()
  478. UpdateSchema(db)
  479. folder := "test"
  480. meta := db.getMetaAndCheck(folder)
  481. empty := Counts{}
  482. c := meta.Counts(protocol.LocalDeviceID, needFlag)
  483. if c.Files != 1 {
  484. t.Error("Expected 1 needed file locally, got", c.Files)
  485. }
  486. c.Files = 0
  487. if c.Deleted != 1 {
  488. t.Error("Expected 1 needed deletion locally, got", c.Deleted)
  489. }
  490. c.Deleted = 0
  491. if !c.Equal(empty) {
  492. t.Error("Expected all counts to be zero, got", c)
  493. }
  494. c = meta.Counts(remoteDevice0, needFlag)
  495. if !c.Equal(empty) {
  496. t.Error("Expected all counts to be zero, got", c)
  497. }
  498. trans, err := db.newReadOnlyTransaction()
  499. if err != nil {
  500. t.Fatal(err)
  501. }
  502. defer trans.Release()
  503. // a
  504. vl, err := trans.getGlobalVersions(nil, []byte(folder), []byte("a"))
  505. if err != nil {
  506. t.Fatal(err)
  507. }
  508. for _, v := range vl.RawVersions {
  509. if !v.Deleted {
  510. t.Error("Unexpected undeleted global version for a")
  511. }
  512. }
  513. // b
  514. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("b"))
  515. if err != nil {
  516. t.Fatal(err)
  517. }
  518. if !vl.RawVersions[0].Deleted {
  519. t.Error("vl.Versions[0] not deleted for b")
  520. }
  521. if vl.RawVersions[1].Deleted {
  522. t.Error("vl.Versions[1] deleted for b")
  523. }
  524. // c
  525. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("c"))
  526. if err != nil {
  527. t.Fatal(err)
  528. }
  529. if vl.RawVersions[0].Deleted {
  530. t.Error("vl.Versions[0] deleted for c")
  531. }
  532. if !vl.RawVersions[1].Deleted {
  533. t.Error("vl.Versions[1] not deleted for c")
  534. }
  535. }
  536. func TestDropDuplicates(t *testing.T) {
  537. names := []string{
  538. "foo",
  539. "bar",
  540. "dcxvoijnds",
  541. "3d/dsfase/4/ss2",
  542. }
  543. tcs := []struct{ in, out []int }{
  544. {[]int{0}, []int{0}},
  545. {[]int{0, 1}, []int{0, 1}},
  546. {[]int{0, 1, 0, 1}, []int{0, 1}},
  547. {[]int{0, 1, 1, 1, 1}, []int{0, 1}},
  548. {[]int{0, 0, 0, 1}, []int{0, 1}},
  549. {[]int{0, 1, 2, 3}, []int{0, 1, 2, 3}},
  550. {[]int{3, 2, 1, 0, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  551. {[]int{0, 1, 1, 3, 0, 1, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  552. }
  553. for tci, tc := range tcs {
  554. inp := make([]protocol.FileInfo, len(tc.in))
  555. expSeq := make(map[string]int)
  556. for i, j := range tc.in {
  557. inp[i] = protocol.FileInfo{Name: names[j], Sequence: int64(i)}
  558. expSeq[names[j]] = i
  559. }
  560. outp := normalizeFilenamesAndDropDuplicates(inp)
  561. if len(outp) != len(tc.out) {
  562. t.Errorf("tc %v: Expected %v entries, got %v", tci, len(tc.out), len(outp))
  563. continue
  564. }
  565. for i, f := range outp {
  566. if exp := names[tc.out[i]]; exp != f.Name {
  567. t.Errorf("tc %v: Got file %v at pos %v, expected %v", tci, f.Name, i, exp)
  568. }
  569. if exp := int64(expSeq[outp[i].Name]); exp != f.Sequence {
  570. t.Errorf("tc %v: Got sequence %v at pos %v, expected %v", tci, f.Sequence, i, exp)
  571. }
  572. }
  573. }
  574. }
  575. func TestGCIndirect(t *testing.T) {
  576. // Verify that the gcIndirect run actually removes block lists.
  577. db := NewLowlevel(backend.OpenMemory())
  578. defer db.Close()
  579. meta := newMetadataTracker(db.keyer)
  580. // Add three files with different block lists
  581. files := []protocol.FileInfo{
  582. {Name: "a", Blocks: genBlocks(100)},
  583. {Name: "b", Blocks: genBlocks(200)},
  584. {Name: "c", Blocks: genBlocks(300)},
  585. }
  586. db.updateLocalFiles([]byte("folder"), files, meta)
  587. // Run a GC pass
  588. db.gcIndirect(context.Background())
  589. // Verify that we have three different block lists
  590. n, err := numBlockLists(db)
  591. if err != nil {
  592. t.Fatal(err)
  593. }
  594. if n != len(files) {
  595. t.Fatal("expected each file to have a block list")
  596. }
  597. // Change the block lists for each file
  598. for i := range files {
  599. files[i].Version = files[i].Version.Update(42)
  600. files[i].Blocks = genBlocks(len(files[i].Blocks) + 1)
  601. }
  602. db.updateLocalFiles([]byte("folder"), files, meta)
  603. // Verify that we now have *six* different block lists
  604. n, err = numBlockLists(db)
  605. if err != nil {
  606. t.Fatal(err)
  607. }
  608. if n != 2*len(files) {
  609. t.Fatal("expected both old and new block lists to exist")
  610. }
  611. // Run a GC pass
  612. db.gcIndirect(context.Background())
  613. // Verify that we now have just the three we need, again
  614. n, err = numBlockLists(db)
  615. if err != nil {
  616. t.Fatal(err)
  617. }
  618. if n != len(files) {
  619. t.Fatal("expected GC to collect all but the needed ones")
  620. }
  621. // Double check the correctness by loading the block lists and comparing with what we stored
  622. tr, err := db.newReadOnlyTransaction()
  623. if err != nil {
  624. t.Fatal()
  625. }
  626. defer tr.Release()
  627. for _, f := range files {
  628. fi, ok, err := tr.getFile([]byte("folder"), protocol.LocalDeviceID[:], []byte(f.Name))
  629. if err != nil {
  630. t.Fatal(err)
  631. }
  632. if !ok {
  633. t.Fatal("mysteriously missing")
  634. }
  635. if len(fi.Blocks) != len(f.Blocks) {
  636. t.Fatal("block list mismatch")
  637. }
  638. for i := range fi.Blocks {
  639. if !bytes.Equal(fi.Blocks[i].Hash, f.Blocks[i].Hash) {
  640. t.Fatal("hash mismatch")
  641. }
  642. }
  643. }
  644. }
  645. func TestUpdateTo14(t *testing.T) {
  646. db := NewLowlevel(backend.OpenMemory())
  647. defer db.Close()
  648. folderStr := "default"
  649. folder := []byte(folderStr)
  650. name := []byte("foo")
  651. file := protocol.FileInfo{Name: string(name), Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(blocksIndirectionCutoff - 1)}
  652. file.BlocksHash = protocol.BlocksHash(file.Blocks)
  653. fileWOBlocks := file
  654. fileWOBlocks.Blocks = nil
  655. meta := db.loadMetadataTracker(folderStr)
  656. // Initally add the correct file the usual way, all good here.
  657. if err := db.updateLocalFiles(folder, []protocol.FileInfo{file}, meta); err != nil {
  658. t.Fatal(err)
  659. }
  660. // Simulate the previous bug, where .putFile could write a file info without
  661. // blocks, even though the file has them (and thus a non-nil BlocksHash).
  662. trans, err := db.newReadWriteTransaction()
  663. if err != nil {
  664. t.Fatal(err)
  665. }
  666. defer trans.close()
  667. key, err := db.keyer.GenerateDeviceFileKey(nil, folder, protocol.LocalDeviceID[:], name)
  668. if err != nil {
  669. t.Fatal(err)
  670. }
  671. fiBs := mustMarshal(&fileWOBlocks)
  672. if err := trans.Put(key, fiBs); err != nil {
  673. t.Fatal(err)
  674. }
  675. if err := trans.Commit(); err != nil {
  676. t.Fatal(err)
  677. }
  678. trans.close()
  679. // Run migration, pretending were still on schema 13.
  680. if err := (&schemaUpdater{db}).updateSchemaTo14(13); err != nil {
  681. t.Fatal(err)
  682. }
  683. // checks
  684. ro, err := db.newReadOnlyTransaction()
  685. if err != nil {
  686. t.Fatal(err)
  687. }
  688. defer ro.close()
  689. if f, ok, err := ro.getFileByKey(key); err != nil {
  690. t.Fatal(err)
  691. } else if !ok {
  692. t.Error("file missing")
  693. } else if !f.MustRescan() {
  694. t.Error("file not marked as MustRescan")
  695. }
  696. if vl, err := ro.getGlobalVersions(nil, folder, name); err != nil {
  697. t.Fatal(err)
  698. } else if fv, ok := vl.GetGlobal(); !ok {
  699. t.Error("missing global")
  700. } else if !fv.IsInvalid() {
  701. t.Error("global not marked as invalid")
  702. }
  703. }
  704. func TestFlushRecursion(t *testing.T) {
  705. // Verify that a commit hook can write to the transaction without
  706. // causing another flush and thus recursion.
  707. db := NewLowlevel(backend.OpenMemory())
  708. defer db.Close()
  709. // A commit hook that writes a small piece of data to the transaction.
  710. hookFired := 0
  711. hook := func(tx backend.WriteTransaction) error {
  712. err := tx.Put([]byte(fmt.Sprintf("hook-key-%d", hookFired)), []byte(fmt.Sprintf("hook-value-%d", hookFired)))
  713. if err != nil {
  714. t.Fatal(err)
  715. }
  716. hookFired++
  717. return nil
  718. }
  719. // A transaction.
  720. tx, err := db.NewWriteTransaction(hook)
  721. if err != nil {
  722. t.Fatal(err)
  723. }
  724. defer tx.Release()
  725. // Write stuff until the transaction flushes, thus firing the hook.
  726. i := 0
  727. for hookFired == 0 {
  728. err := tx.Put([]byte(fmt.Sprintf("key-%d", i)), []byte(fmt.Sprintf("value-%d", i)))
  729. if err != nil {
  730. t.Fatal(err)
  731. }
  732. i++
  733. }
  734. // The hook should have fired precisely once.
  735. if hookFired != 1 {
  736. t.Error("expect one hook fire, not", hookFired)
  737. }
  738. }
  739. func TestCheckLocalNeed(t *testing.T) {
  740. db := NewLowlevel(backend.OpenMemory())
  741. defer db.Close()
  742. folderStr := "test"
  743. fs := NewFileSet(folderStr, fs.NewFilesystem(fs.FilesystemTypeFake, ""), db)
  744. // Add files such that we are in sync for a and b, and need c and d.
  745. files := []protocol.FileInfo{
  746. {Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  747. {Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  748. {Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  749. {Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  750. }
  751. fs.Update(protocol.LocalDeviceID, files)
  752. files[2].Version = files[2].Version.Update(remoteDevice0.Short())
  753. files[3].Version = files[2].Version.Update(remoteDevice0.Short())
  754. fs.Update(remoteDevice0, files)
  755. checkNeed := func() {
  756. snap := fs.Snapshot()
  757. defer snap.Release()
  758. c := snap.NeedSize(protocol.LocalDeviceID)
  759. if c.Files != 2 {
  760. t.Errorf("Expected 2 needed files locally, got %v in meta", c.Files)
  761. }
  762. needed := make([]protocol.FileInfo, 0, 2)
  763. snap.WithNeed(protocol.LocalDeviceID, func(fi protocol.FileIntf) bool {
  764. needed = append(needed, fi.(protocol.FileInfo))
  765. return true
  766. })
  767. if l := len(needed); l != 2 {
  768. t.Errorf("Expected 2 needed files locally, got %v in db", l)
  769. } else if needed[0].Name != "c" || needed[1].Name != "d" {
  770. t.Errorf("Expected files c and d to be needed, got %v and %v", needed[0].Name, needed[1].Name)
  771. }
  772. }
  773. checkNeed()
  774. trans, err := db.newReadWriteTransaction()
  775. if err != nil {
  776. t.Fatal(err)
  777. }
  778. defer trans.close()
  779. // Add "b" to needed and remove "d"
  780. folder := []byte(folderStr)
  781. key, err := trans.keyer.GenerateNeedFileKey(nil, folder, []byte(files[1].Name))
  782. if err != nil {
  783. t.Fatal(err)
  784. }
  785. if err = trans.Put(key, nil); err != nil {
  786. t.Fatal(err)
  787. }
  788. key, err = trans.keyer.GenerateNeedFileKey(nil, folder, []byte(files[3].Name))
  789. if err != nil {
  790. t.Fatal(err)
  791. }
  792. if err = trans.Delete(key); err != nil {
  793. t.Fatal(err)
  794. }
  795. if err := trans.Commit(); err != nil {
  796. t.Fatal(err)
  797. }
  798. if repaired, err := db.checkLocalNeed(folder); err != nil {
  799. t.Fatal(err)
  800. } else if repaired != 2 {
  801. t.Error("Expected 2 repaired local need items, got", repaired)
  802. }
  803. checkNeed()
  804. }
  805. func TestDuplicateNeedCount(t *testing.T) {
  806. db := NewLowlevel(backend.OpenMemory())
  807. defer db.Close()
  808. folder := "test"
  809. testFs := fs.NewFilesystem(fs.FilesystemTypeFake, "")
  810. fs := NewFileSet(folder, testFs, db)
  811. files := []protocol.FileInfo{{Name: "foo", Version: protocol.Vector{}.Update(myID), Sequence: 1}}
  812. fs.Update(protocol.LocalDeviceID, files)
  813. files[0].Version = files[0].Version.Update(remoteDevice0.Short())
  814. fs.Update(remoteDevice0, files)
  815. db.checkRepair()
  816. fs = NewFileSet(folder, testFs, db)
  817. found := false
  818. for _, c := range fs.meta.counts.Counts {
  819. if bytes.Equal(protocol.LocalDeviceID[:], c.DeviceID) && c.LocalFlags == needFlag {
  820. if found {
  821. t.Fatal("second need count for local device encountered")
  822. }
  823. found = true
  824. }
  825. }
  826. if !found {
  827. t.Fatal("no need count for local device encountered")
  828. }
  829. }
  830. func numBlockLists(db *Lowlevel) (int, error) {
  831. it, err := db.Backend.NewPrefixIterator([]byte{KeyTypeBlockList})
  832. if err != nil {
  833. return 0, err
  834. }
  835. defer it.Release()
  836. n := 0
  837. for it.Next() {
  838. n++
  839. }
  840. if err := it.Error(); err != nil {
  841. return 0, err
  842. }
  843. return n, nil
  844. }