db_test.go 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  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/events"
  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(t, ldb)
  34. defer db.Close()
  35. if err := UpdateSchema(db); err != nil {
  36. t.Fatal(err)
  37. }
  38. fs := newFileSet(t, "test", db)
  39. // The contents of the database are like this:
  40. //
  41. // fs := newFileSet(t, "test", 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 := snapshot(t, fs)
  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][]protocol.FileInfo
  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][]protocol.FileInfo{
  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(t, 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, protocol.FileInfoComparison{IgnorePerms: true, IgnoreBlocks: true}) {
  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. if err != nil {
  234. t.Fatal(err)
  235. }
  236. fi, ok, err := trans.getFileTrunc(key, false)
  237. if err != nil {
  238. t.Fatal(err)
  239. }
  240. if !ok {
  241. device := "<invalid>"
  242. if dev, err := protocol.DeviceIDFromBytes(vl.Versions[0].Device); err != nil {
  243. device = dev.String()
  244. }
  245. t.Fatal("surprise missing global file", string(name), device)
  246. }
  247. e, ok := need[fi.FileName()]
  248. if !ok {
  249. t.Error("Got unexpected needed file:", fi.FileName())
  250. }
  251. f := fi.(protocol.FileInfo)
  252. delete(need, f.Name)
  253. if !f.IsEquivalentOptional(e, protocol.FileInfoComparison{IgnorePerms: true, IgnoreBlocks: true}) {
  254. t.Errorf("Wrong needed file, got %v, expected %v", f, e)
  255. }
  256. }
  257. if dbi.Error() != nil {
  258. t.Fatal(err)
  259. }
  260. for n := range need {
  261. t.Errorf(`Missing needed file "%v"`, n)
  262. }
  263. }
  264. // TestRepairSequence checks that a few hand-crafted messed-up sequence entries get fixed.
  265. func TestRepairSequence(t *testing.T) {
  266. db := newLowlevelMemory(t)
  267. defer db.Close()
  268. folderStr := "test"
  269. folder := []byte(folderStr)
  270. id := protocol.LocalDeviceID
  271. short := protocol.LocalDeviceID.Short()
  272. files := []protocol.FileInfo{
  273. {Name: "fine", Blocks: genBlocks(1)},
  274. {Name: "duplicate", Blocks: genBlocks(2)},
  275. {Name: "missing", Blocks: genBlocks(3)},
  276. {Name: "overwriting", Blocks: genBlocks(4)},
  277. {Name: "inconsistent", Blocks: genBlocks(5)},
  278. {Name: "inconsistentNotIndirected", Blocks: genBlocks(2)},
  279. }
  280. for i, f := range files {
  281. files[i].Version = f.Version.Update(short)
  282. }
  283. trans, err := db.newReadWriteTransaction()
  284. if err != nil {
  285. t.Fatal(err)
  286. }
  287. defer trans.close()
  288. addFile := func(f protocol.FileInfo, seq int64) {
  289. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  290. if err != nil {
  291. t.Fatal(err)
  292. }
  293. if err := trans.putFile(dk, f); err != nil {
  294. t.Fatal(err)
  295. }
  296. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  297. if err != nil {
  298. t.Fatal(err)
  299. }
  300. if err := trans.Put(sk, dk); err != nil {
  301. t.Fatal(err)
  302. }
  303. }
  304. // Plain normal entry
  305. var seq int64 = 1
  306. files[0].Sequence = 1
  307. addFile(files[0], seq)
  308. // Second entry once updated with original sequence still in place
  309. f := files[1]
  310. f.Sequence = int64(len(files) + 1)
  311. addFile(f, f.Sequence)
  312. // Original sequence entry
  313. seq++
  314. sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. dk, err := trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte(f.Name))
  319. if err != nil {
  320. t.Fatal(err)
  321. }
  322. if err := trans.Put(sk, dk); err != nil {
  323. t.Fatal(err)
  324. }
  325. // File later overwritten thus missing sequence entry
  326. seq++
  327. files[2].Sequence = seq
  328. addFile(files[2], seq)
  329. // File overwriting previous sequence entry (no seq bump)
  330. seq++
  331. files[3].Sequence = seq
  332. addFile(files[3], seq)
  333. // Inconistent files
  334. seq++
  335. files[4].Sequence = 101
  336. addFile(files[4], seq)
  337. seq++
  338. files[5].Sequence = 102
  339. addFile(files[5], seq)
  340. // And a sequence entry pointing at nothing because why not
  341. sk, err = trans.keyer.GenerateSequenceKey(nil, folder, 100001)
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. dk, err = trans.keyer.GenerateDeviceFileKey(nil, folder, id[:], []byte("nonexisting"))
  346. if err != nil {
  347. t.Fatal(err)
  348. }
  349. if err := trans.Put(sk, dk); err != nil {
  350. t.Fatal(err)
  351. }
  352. if err := trans.Commit(); err != nil {
  353. t.Fatal(err)
  354. }
  355. // Loading the metadata for the first time means a "re"calculation happens,
  356. // along which the sequences get repaired too.
  357. db.gcMut.RLock()
  358. _, err = db.loadMetadataTracker(folderStr)
  359. db.gcMut.RUnlock()
  360. if err != nil {
  361. t.Fatal(err)
  362. }
  363. // Check the db
  364. ro, err := db.newReadOnlyTransaction()
  365. if err != nil {
  366. t.Fatal(err)
  367. }
  368. defer ro.close()
  369. it, err := ro.NewPrefixIterator([]byte{KeyTypeDevice})
  370. if err != nil {
  371. t.Fatal(err)
  372. }
  373. defer it.Release()
  374. for it.Next() {
  375. fi, err := ro.unmarshalTrunc(it.Value(), true)
  376. if err != nil {
  377. t.Fatal(err)
  378. }
  379. if sk, err = ro.keyer.GenerateSequenceKey(sk, folder, fi.SequenceNo()); err != nil {
  380. t.Fatal(err)
  381. }
  382. dk, err := ro.Get(sk)
  383. if backend.IsNotFound(err) {
  384. t.Error("Missing sequence entry for", fi.FileName())
  385. } else if err != nil {
  386. t.Fatal(err)
  387. }
  388. if !bytes.Equal(it.Key(), dk) {
  389. t.Errorf("Wrong key for %v, expected %s, got %s", f.FileName(), it.Key(), dk)
  390. }
  391. }
  392. if err := it.Error(); err != nil {
  393. t.Fatal(err)
  394. }
  395. it.Release()
  396. it, err = ro.NewPrefixIterator([]byte{KeyTypeSequence})
  397. if err != nil {
  398. t.Fatal(err)
  399. }
  400. defer it.Release()
  401. for it.Next() {
  402. intf, ok, err := ro.getFileTrunc(it.Value(), false)
  403. if err != nil {
  404. t.Fatal(err)
  405. }
  406. fi := intf.(protocol.FileInfo)
  407. seq := ro.keyer.SequenceFromSequenceKey(it.Key())
  408. if !ok {
  409. t.Errorf("Sequence entry %v points at nothing", seq)
  410. } else if fi.SequenceNo() != seq {
  411. t.Errorf("Inconsistent sequence entry for %v: %v != %v", fi.FileName(), fi.SequenceNo(), seq)
  412. }
  413. if len(fi.Blocks) == 0 {
  414. t.Error("Missing blocks in", fi.FileName())
  415. }
  416. }
  417. if err := it.Error(); err != nil {
  418. t.Fatal(err)
  419. }
  420. it.Release()
  421. }
  422. func TestDowngrade(t *testing.T) {
  423. db := newLowlevelMemory(t)
  424. defer db.Close()
  425. // sets the min version etc
  426. if err := UpdateSchema(db); err != nil {
  427. t.Fatal(err)
  428. }
  429. // Bump the database version to something newer than we actually support
  430. miscDB := NewMiscDataNamespace(db)
  431. if err := miscDB.PutInt64("dbVersion", dbVersion+1); err != nil {
  432. t.Fatal(err)
  433. }
  434. l.Infoln(dbVersion)
  435. // Pretend we just opened the DB and attempt to update it again
  436. err := UpdateSchema(db)
  437. if err, ok := err.(*databaseDowngradeError); !ok {
  438. t.Fatal("Expected error due to database downgrade, got", err)
  439. } else if err.minSyncthingVersion != dbMinSyncthingVersion {
  440. t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
  441. }
  442. }
  443. func TestCheckGlobals(t *testing.T) {
  444. db := newLowlevelMemory(t)
  445. defer db.Close()
  446. fs := newFileSet(t, "test", db)
  447. // Add any file
  448. name := "foo"
  449. fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  450. {
  451. Name: name,
  452. Type: protocol.FileInfoTypeFile,
  453. Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  454. },
  455. })
  456. // Remove just the file entry
  457. if err := db.dropPrefix([]byte{KeyTypeDevice}); err != nil {
  458. t.Fatal(err)
  459. }
  460. // Clean up global entry of the now missing file
  461. if repaired, err := db.checkGlobals(fs.folder); err != nil {
  462. t.Fatal(err)
  463. } else if repaired != 1 {
  464. t.Error("Expected 1 repaired global item, got", repaired)
  465. }
  466. // Check that the global entry is gone
  467. gk, err := db.keyer.GenerateGlobalVersionKey(nil, []byte(fs.folder), []byte(name))
  468. if err != nil {
  469. t.Fatal(err)
  470. }
  471. _, err = db.Get(gk)
  472. if !backend.IsNotFound(err) {
  473. t.Error("Expected key missing error, got", err)
  474. }
  475. }
  476. func TestUpdateTo10(t *testing.T) {
  477. ldb, err := openJSONS("./testdata/v1.4.0-updateTo10.json")
  478. if err != nil {
  479. t.Fatal(err)
  480. }
  481. db := newLowlevel(t, ldb)
  482. defer db.Close()
  483. UpdateSchema(db)
  484. folder := "test"
  485. meta, err := db.getMetaAndCheck(folder)
  486. if err != nil {
  487. t.Fatal(err)
  488. }
  489. empty := Counts{}
  490. c := meta.Counts(protocol.LocalDeviceID, needFlag)
  491. if c.Files != 1 {
  492. t.Error("Expected 1 needed file locally, got", c.Files)
  493. }
  494. c.Files = 0
  495. if c.Deleted != 1 {
  496. t.Error("Expected 1 needed deletion locally, got", c.Deleted)
  497. }
  498. c.Deleted = 0
  499. if !c.Equal(empty) {
  500. t.Error("Expected all counts to be zero, got", c)
  501. }
  502. c = meta.Counts(remoteDevice0, needFlag)
  503. if !c.Equal(empty) {
  504. t.Error("Expected all counts to be zero, got", c)
  505. }
  506. trans, err := db.newReadOnlyTransaction()
  507. if err != nil {
  508. t.Fatal(err)
  509. }
  510. defer trans.Release()
  511. // a
  512. vl, err := trans.getGlobalVersions(nil, []byte(folder), []byte("a"))
  513. if err != nil {
  514. t.Fatal(err)
  515. }
  516. for _, v := range vl.RawVersions {
  517. if !v.Deleted {
  518. t.Error("Unexpected undeleted global version for a")
  519. }
  520. }
  521. // b
  522. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("b"))
  523. if err != nil {
  524. t.Fatal(err)
  525. }
  526. if !vl.RawVersions[0].Deleted {
  527. t.Error("vl.Versions[0] not deleted for b")
  528. }
  529. if vl.RawVersions[1].Deleted {
  530. t.Error("vl.Versions[1] deleted for b")
  531. }
  532. // c
  533. vl, err = trans.getGlobalVersions(nil, []byte(folder), []byte("c"))
  534. if err != nil {
  535. t.Fatal(err)
  536. }
  537. if vl.RawVersions[0].Deleted {
  538. t.Error("vl.Versions[0] deleted for c")
  539. }
  540. if !vl.RawVersions[1].Deleted {
  541. t.Error("vl.Versions[1] not deleted for c")
  542. }
  543. }
  544. func TestDropDuplicates(t *testing.T) {
  545. names := []string{
  546. "foo",
  547. "bar",
  548. "dcxvoijnds",
  549. "3d/dsfase/4/ss2",
  550. }
  551. tcs := []struct{ in, out []int }{
  552. {[]int{0}, []int{0}},
  553. {[]int{0, 1}, []int{0, 1}},
  554. {[]int{0, 1, 0, 1}, []int{0, 1}},
  555. {[]int{0, 1, 1, 1, 1}, []int{0, 1}},
  556. {[]int{0, 0, 0, 1}, []int{0, 1}},
  557. {[]int{0, 1, 2, 3}, []int{0, 1, 2, 3}},
  558. {[]int{3, 2, 1, 0, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  559. {[]int{0, 1, 1, 3, 0, 1, 0, 1, 2, 3}, []int{0, 1, 2, 3}},
  560. }
  561. for tci, tc := range tcs {
  562. inp := make([]protocol.FileInfo, len(tc.in))
  563. expSeq := make(map[string]int)
  564. for i, j := range tc.in {
  565. inp[i] = protocol.FileInfo{Name: names[j], Sequence: int64(i)}
  566. expSeq[names[j]] = i
  567. }
  568. outp := normalizeFilenamesAndDropDuplicates(inp)
  569. if len(outp) != len(tc.out) {
  570. t.Errorf("tc %v: Expected %v entries, got %v", tci, len(tc.out), len(outp))
  571. continue
  572. }
  573. for i, f := range outp {
  574. if exp := names[tc.out[i]]; exp != f.Name {
  575. t.Errorf("tc %v: Got file %v at pos %v, expected %v", tci, f.Name, i, exp)
  576. }
  577. if exp := int64(expSeq[outp[i].Name]); exp != f.Sequence {
  578. t.Errorf("tc %v: Got sequence %v at pos %v, expected %v", tci, f.Sequence, i, exp)
  579. }
  580. }
  581. }
  582. }
  583. func TestGCIndirect(t *testing.T) {
  584. // Verify that the gcIndirect run actually removes block lists.
  585. db := newLowlevelMemory(t)
  586. defer db.Close()
  587. meta := newMetadataTracker(db.keyer, events.NoopLogger)
  588. // Add three files with different block lists
  589. files := []protocol.FileInfo{
  590. {Name: "a", Blocks: genBlocks(100)},
  591. {Name: "b", Blocks: genBlocks(200)},
  592. {Name: "c", Blocks: genBlocks(300)},
  593. }
  594. db.updateLocalFiles([]byte("folder"), files, meta)
  595. // Run a GC pass
  596. db.gcIndirect(context.Background())
  597. // Verify that we have three different block lists
  598. n, err := numBlockLists(db)
  599. if err != nil {
  600. t.Fatal(err)
  601. }
  602. if n != len(files) {
  603. t.Fatal("expected each file to have a block list")
  604. }
  605. // Change the block lists for each file
  606. for i := range files {
  607. files[i].Version = files[i].Version.Update(42)
  608. files[i].Blocks = genBlocks(len(files[i].Blocks) + 1)
  609. }
  610. db.updateLocalFiles([]byte("folder"), files, meta)
  611. // Verify that we now have *six* different block lists
  612. n, err = numBlockLists(db)
  613. if err != nil {
  614. t.Fatal(err)
  615. }
  616. if n != 2*len(files) {
  617. t.Fatal("expected both old and new block lists to exist")
  618. }
  619. // Run a GC pass
  620. db.gcIndirect(context.Background())
  621. // Verify that we now have just the three we need, again
  622. n, err = numBlockLists(db)
  623. if err != nil {
  624. t.Fatal(err)
  625. }
  626. if n != len(files) {
  627. t.Fatal("expected GC to collect all but the needed ones")
  628. }
  629. // Double check the correctness by loading the block lists and comparing with what we stored
  630. tr, err := db.newReadOnlyTransaction()
  631. if err != nil {
  632. t.Fatal()
  633. }
  634. defer tr.Release()
  635. for _, f := range files {
  636. fi, ok, err := tr.getFile([]byte("folder"), protocol.LocalDeviceID[:], []byte(f.Name))
  637. if err != nil {
  638. t.Fatal(err)
  639. }
  640. if !ok {
  641. t.Fatal("mysteriously missing")
  642. }
  643. if len(fi.Blocks) != len(f.Blocks) {
  644. t.Fatal("block list mismatch")
  645. }
  646. for i := range fi.Blocks {
  647. if !bytes.Equal(fi.Blocks[i].Hash, f.Blocks[i].Hash) {
  648. t.Fatal("hash mismatch")
  649. }
  650. }
  651. }
  652. }
  653. func TestUpdateTo14(t *testing.T) {
  654. db := newLowlevelMemory(t)
  655. defer db.Close()
  656. folderStr := "default"
  657. folder := []byte(folderStr)
  658. name := []byte("foo")
  659. file := protocol.FileInfo{Name: string(name), Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(blocksIndirectionCutoff - 1)}
  660. file.BlocksHash = protocol.BlocksHash(file.Blocks)
  661. fileWOBlocks := file
  662. fileWOBlocks.Blocks = nil
  663. meta, err := db.loadMetadataTracker(folderStr)
  664. if err != nil {
  665. t.Fatal(err)
  666. }
  667. // Initially add the correct file the usual way, all good here.
  668. if err := db.updateLocalFiles(folder, []protocol.FileInfo{file}, meta); err != nil {
  669. t.Fatal(err)
  670. }
  671. // Simulate the previous bug, where .putFile could write a file info without
  672. // blocks, even though the file has them (and thus a non-nil BlocksHash).
  673. trans, err := db.newReadWriteTransaction()
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. defer trans.close()
  678. key, err := db.keyer.GenerateDeviceFileKey(nil, folder, protocol.LocalDeviceID[:], name)
  679. if err != nil {
  680. t.Fatal(err)
  681. }
  682. fiBs := mustMarshal(&fileWOBlocks)
  683. if err := trans.Put(key, fiBs); err != nil {
  684. t.Fatal(err)
  685. }
  686. if err := trans.Commit(); err != nil {
  687. t.Fatal(err)
  688. }
  689. trans.close()
  690. // Run migration, pretending were still on schema 13.
  691. if err := (&schemaUpdater{db}).updateSchemaTo14(13); err != nil {
  692. t.Fatal(err)
  693. }
  694. // checks
  695. ro, err := db.newReadOnlyTransaction()
  696. if err != nil {
  697. t.Fatal(err)
  698. }
  699. defer ro.close()
  700. if f, ok, err := ro.getFileByKey(key); err != nil {
  701. t.Fatal(err)
  702. } else if !ok {
  703. t.Error("file missing")
  704. } else if !f.MustRescan() {
  705. t.Error("file not marked as MustRescan")
  706. }
  707. if vl, err := ro.getGlobalVersions(nil, folder, name); err != nil {
  708. t.Fatal(err)
  709. } else if fv, ok := vl.GetGlobal(); !ok {
  710. t.Error("missing global")
  711. } else if !fv.IsInvalid() {
  712. t.Error("global not marked as invalid")
  713. }
  714. }
  715. func TestFlushRecursion(t *testing.T) {
  716. // Verify that a commit hook can write to the transaction without
  717. // causing another flush and thus recursion.
  718. db := newLowlevelMemory(t)
  719. defer db.Close()
  720. // A commit hook that writes a small piece of data to the transaction.
  721. hookFired := 0
  722. hook := func(tx backend.WriteTransaction) error {
  723. err := tx.Put([]byte(fmt.Sprintf("hook-key-%d", hookFired)), []byte(fmt.Sprintf("hook-value-%d", hookFired)))
  724. if err != nil {
  725. t.Fatal(err)
  726. }
  727. hookFired++
  728. return nil
  729. }
  730. // A transaction.
  731. tx, err := db.NewWriteTransaction(hook)
  732. if err != nil {
  733. t.Fatal(err)
  734. }
  735. defer tx.Release()
  736. // Write stuff until the transaction flushes, thus firing the hook.
  737. i := 0
  738. for hookFired == 0 {
  739. err := tx.Put([]byte(fmt.Sprintf("key-%d", i)), []byte(fmt.Sprintf("value-%d", i)))
  740. if err != nil {
  741. t.Fatal(err)
  742. }
  743. i++
  744. }
  745. // The hook should have fired precisely once.
  746. if hookFired != 1 {
  747. t.Error("expect one hook fire, not", hookFired)
  748. }
  749. }
  750. func TestCheckLocalNeed(t *testing.T) {
  751. db := newLowlevelMemory(t)
  752. defer db.Close()
  753. folderStr := "test"
  754. fs := newFileSet(t, folderStr, db)
  755. // Add files such that we are in sync for a and b, and need c and d.
  756. files := []protocol.FileInfo{
  757. {Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  758. {Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  759. {Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  760. {Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1}}}},
  761. }
  762. fs.Update(protocol.LocalDeviceID, files)
  763. files[2].Version = files[2].Version.Update(remoteDevice0.Short())
  764. files[3].Version = files[2].Version.Update(remoteDevice0.Short())
  765. fs.Update(remoteDevice0, files)
  766. checkNeed := func() {
  767. snap := snapshot(t, fs)
  768. defer snap.Release()
  769. c := snap.NeedSize(protocol.LocalDeviceID)
  770. if c.Files != 2 {
  771. t.Errorf("Expected 2 needed files locally, got %v in meta", c.Files)
  772. }
  773. needed := make([]protocol.FileInfo, 0, 2)
  774. snap.WithNeed(protocol.LocalDeviceID, func(fi protocol.FileIntf) bool {
  775. needed = append(needed, fi.(protocol.FileInfo))
  776. return true
  777. })
  778. if l := len(needed); l != 2 {
  779. t.Errorf("Expected 2 needed files locally, got %v in db", l)
  780. } else if needed[0].Name != "c" || needed[1].Name != "d" {
  781. t.Errorf("Expected files c and d to be needed, got %v and %v", needed[0].Name, needed[1].Name)
  782. }
  783. }
  784. checkNeed()
  785. trans, err := db.newReadWriteTransaction()
  786. if err != nil {
  787. t.Fatal(err)
  788. }
  789. defer trans.close()
  790. // Add "b" to needed and remove "d"
  791. folder := []byte(folderStr)
  792. key, err := trans.keyer.GenerateNeedFileKey(nil, folder, []byte(files[1].Name))
  793. if err != nil {
  794. t.Fatal(err)
  795. }
  796. if err = trans.Put(key, nil); err != nil {
  797. t.Fatal(err)
  798. }
  799. key, err = trans.keyer.GenerateNeedFileKey(nil, folder, []byte(files[3].Name))
  800. if err != nil {
  801. t.Fatal(err)
  802. }
  803. if err = trans.Delete(key); err != nil {
  804. t.Fatal(err)
  805. }
  806. if err := trans.Commit(); err != nil {
  807. t.Fatal(err)
  808. }
  809. if repaired, err := db.checkLocalNeed(folder); err != nil {
  810. t.Fatal(err)
  811. } else if repaired != 2 {
  812. t.Error("Expected 2 repaired local need items, got", repaired)
  813. }
  814. checkNeed()
  815. }
  816. func TestDuplicateNeedCount(t *testing.T) {
  817. db := newLowlevelMemory(t)
  818. defer db.Close()
  819. folder := "test"
  820. fs := newFileSet(t, folder, db)
  821. files := []protocol.FileInfo{{Name: "foo", Version: protocol.Vector{}.Update(myID), Sequence: 1}}
  822. fs.Update(protocol.LocalDeviceID, files)
  823. files[0].Version = files[0].Version.Update(remoteDevice0.Short())
  824. fs.Update(remoteDevice0, files)
  825. db.checkRepair()
  826. fs = newFileSet(t, folder, db)
  827. found := false
  828. for _, c := range fs.meta.counts.Counts {
  829. if bytes.Equal(protocol.LocalDeviceID[:], c.DeviceID) && c.LocalFlags == needFlag {
  830. if found {
  831. t.Fatal("second need count for local device encountered")
  832. }
  833. found = true
  834. }
  835. }
  836. if !found {
  837. t.Fatal("no need count for local device encountered")
  838. }
  839. }
  840. func TestNeedAfterDropGlobal(t *testing.T) {
  841. db := newLowlevelMemory(t)
  842. defer db.Close()
  843. folder := "test"
  844. fs := newFileSet(t, folder, db)
  845. // Initial:
  846. // Three devices and a file "test": local has Version 1, remoteDevice0
  847. // Version 2 and remoteDevice2 doesn't have it.
  848. // All of them have "bar", just so the db knows about remoteDevice2.
  849. files := []protocol.FileInfo{
  850. {Name: "foo", Version: protocol.Vector{}.Update(myID), Sequence: 1},
  851. {Name: "bar", Version: protocol.Vector{}.Update(myID), Sequence: 2},
  852. }
  853. fs.Update(protocol.LocalDeviceID, files)
  854. files[0].Version = files[0].Version.Update(myID)
  855. fs.Update(remoteDevice0, files)
  856. fs.Update(remoteDevice1, files[1:])
  857. // remoteDevice1 needs one file: test
  858. snap := snapshot(t, fs)
  859. c := snap.NeedSize(remoteDevice1)
  860. if c.Files != 1 {
  861. t.Errorf("Expected 1 needed files initially, got %v", c.Files)
  862. }
  863. snap.Release()
  864. // Drop remoteDevice0, i.e. remove all their files from db.
  865. // That changes the global file, which is now what local has.
  866. fs.Drop(remoteDevice0)
  867. // remoteDevice1 still needs test.
  868. snap = snapshot(t, fs)
  869. c = snap.NeedSize(remoteDevice1)
  870. if c.Files != 1 {
  871. t.Errorf("Expected still 1 needed files, got %v", c.Files)
  872. }
  873. snap.Release()
  874. }
  875. func numBlockLists(db *Lowlevel) (int, error) {
  876. it, err := db.Backend.NewPrefixIterator([]byte{KeyTypeBlockList})
  877. if err != nil {
  878. return 0, err
  879. }
  880. defer it.Release()
  881. n := 0
  882. for it.Next() {
  883. n++
  884. }
  885. if err := it.Error(); err != nil {
  886. return 0, err
  887. }
  888. return n, nil
  889. }