db_test.go 25 KB

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