schemaupdater.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. // Copyright (C) 2018 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. "fmt"
  9. "strings"
  10. "github.com/syncthing/syncthing/lib/db/backend"
  11. "github.com/syncthing/syncthing/lib/protocol"
  12. )
  13. // List of all dbVersion to dbMinSyncthingVersion pairs for convenience
  14. // 0: v0.14.0
  15. // 1: v0.14.46
  16. // 2: v0.14.48
  17. // 3-5: v0.14.49
  18. // 6: v0.14.50
  19. // 7: v0.14.53
  20. // 8-9: v1.4.0
  21. // 10-11: v1.6.0
  22. const (
  23. dbVersion = 11
  24. dbMinSyncthingVersion = "v1.6.0"
  25. )
  26. type databaseDowngradeError struct {
  27. minSyncthingVersion string
  28. }
  29. func (e databaseDowngradeError) Error() string {
  30. if e.minSyncthingVersion == "" {
  31. return "newer Syncthing required"
  32. }
  33. return fmt.Sprintf("Syncthing %s required", e.minSyncthingVersion)
  34. }
  35. func UpdateSchema(db *Lowlevel) error {
  36. updater := &schemaUpdater{db}
  37. return updater.updateSchema()
  38. }
  39. type schemaUpdater struct {
  40. *Lowlevel
  41. }
  42. func (db *schemaUpdater) updateSchema() error {
  43. // Updating the schema can touch any and all parts of the database. Make
  44. // sure we do not run GC concurrently with schema migrations.
  45. db.gcMut.Lock()
  46. defer db.gcMut.Unlock()
  47. miscDB := NewMiscDataNamespace(db.Lowlevel)
  48. prevVersion, _, err := miscDB.Int64("dbVersion")
  49. if err != nil {
  50. return err
  51. }
  52. if prevVersion > dbVersion {
  53. err := databaseDowngradeError{}
  54. if minSyncthingVersion, ok, dbErr := miscDB.String("dbMinSyncthingVersion"); dbErr != nil {
  55. return dbErr
  56. } else if ok {
  57. err.minSyncthingVersion = minSyncthingVersion
  58. }
  59. return err
  60. }
  61. if prevVersion == dbVersion {
  62. return nil
  63. }
  64. type migration struct {
  65. schemaVersion int64
  66. migration func(prevVersion int) error
  67. }
  68. var migrations = []migration{
  69. {1, db.updateSchema0to1},
  70. {2, db.updateSchema1to2},
  71. {3, db.updateSchema2to3},
  72. {5, db.updateSchemaTo5},
  73. {6, db.updateSchema5to6},
  74. {7, db.updateSchema6to7},
  75. {9, db.updateSchemaTo9},
  76. {10, db.updateSchemaTo10},
  77. {11, db.updateSchemaTo11},
  78. }
  79. for _, m := range migrations {
  80. if prevVersion < m.schemaVersion {
  81. l.Infof("Migrating database to schema version %d...", m.schemaVersion)
  82. if err := m.migration(int(prevVersion)); err != nil {
  83. return err
  84. }
  85. }
  86. }
  87. if err := miscDB.PutInt64("dbVersion", dbVersion); err != nil {
  88. return err
  89. }
  90. if err := miscDB.PutString("dbMinSyncthingVersion", dbMinSyncthingVersion); err != nil {
  91. return err
  92. }
  93. l.Infoln("Compacting database after migration...")
  94. return db.Compact()
  95. }
  96. func (db *schemaUpdater) updateSchema0to1(_ int) error {
  97. t, err := db.newReadWriteTransaction()
  98. if err != nil {
  99. return err
  100. }
  101. defer t.close()
  102. dbi, err := t.NewPrefixIterator([]byte{KeyTypeDevice})
  103. if err != nil {
  104. return err
  105. }
  106. defer dbi.Release()
  107. symlinkConv := 0
  108. changedFolders := make(map[string]struct{})
  109. ignAdded := 0
  110. meta := newMetadataTracker() // dummy metadata tracker
  111. var gk, buf []byte
  112. for dbi.Next() {
  113. folder, ok := db.keyer.FolderFromDeviceFileKey(dbi.Key())
  114. if !ok {
  115. // not having the folder in the index is bad; delete and continue
  116. if err := t.Delete(dbi.Key()); err != nil {
  117. return err
  118. }
  119. continue
  120. }
  121. device, ok := db.keyer.DeviceFromDeviceFileKey(dbi.Key())
  122. if !ok {
  123. // not having the device in the index is bad; delete and continue
  124. if err := t.Delete(dbi.Key()); err != nil {
  125. return err
  126. }
  127. continue
  128. }
  129. name := db.keyer.NameFromDeviceFileKey(dbi.Key())
  130. // Remove files with absolute path (see #4799)
  131. if strings.HasPrefix(string(name), "/") {
  132. if _, ok := changedFolders[string(folder)]; !ok {
  133. changedFolders[string(folder)] = struct{}{}
  134. }
  135. gk, err = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
  136. if err != nil {
  137. return err
  138. }
  139. // Purposely pass nil file name to remove from global list,
  140. // but don't touch meta and needs
  141. buf, err = t.removeFromGlobal(gk, buf, folder, device, nil, nil)
  142. if err != nil && err != errEntryFromGlobalMissing {
  143. return err
  144. }
  145. if err := t.Delete(dbi.Key()); err != nil {
  146. return err
  147. }
  148. continue
  149. }
  150. // Change SYMLINK_FILE and SYMLINK_DIRECTORY types to the current SYMLINK
  151. // type (previously SYMLINK_UNKNOWN). It does this for all devices, both
  152. // local and remote, and does not reset delta indexes. It shouldn't really
  153. // matter what the symlink type is, but this cleans it up for a possible
  154. // future when SYMLINK_FILE and SYMLINK_DIRECTORY are no longer understood.
  155. var f protocol.FileInfo
  156. if err := f.Unmarshal(dbi.Value()); err != nil {
  157. // probably can't happen
  158. continue
  159. }
  160. if f.Type == protocol.FileInfoTypeDeprecatedSymlinkDirectory || f.Type == protocol.FileInfoTypeDeprecatedSymlinkFile {
  161. f.Type = protocol.FileInfoTypeSymlink
  162. bs, err := f.Marshal()
  163. if err != nil {
  164. panic("can't happen: " + err.Error())
  165. }
  166. if err := t.Put(dbi.Key(), bs); err != nil {
  167. return err
  168. }
  169. symlinkConv++
  170. }
  171. // Add invalid files to global list
  172. if f.IsInvalid() {
  173. gk, err = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
  174. if err != nil {
  175. return err
  176. }
  177. if buf, ok, err = t.updateGlobal(gk, buf, folder, device, f, meta); err != nil {
  178. return err
  179. } else if ok {
  180. if _, ok = changedFolders[string(folder)]; !ok {
  181. changedFolders[string(folder)] = struct{}{}
  182. }
  183. ignAdded++
  184. }
  185. }
  186. if err := t.Checkpoint(); err != nil {
  187. return err
  188. }
  189. }
  190. for folder := range changedFolders {
  191. if err := db.dropFolderMeta([]byte(folder)); err != nil {
  192. return err
  193. }
  194. }
  195. return t.Commit()
  196. }
  197. // updateSchema1to2 introduces a sequenceKey->deviceKey bucket for local items
  198. // to allow iteration in sequence order (simplifies sending indexes).
  199. func (db *schemaUpdater) updateSchema1to2(_ int) error {
  200. t, err := db.newReadWriteTransaction()
  201. if err != nil {
  202. return err
  203. }
  204. defer t.close()
  205. var sk []byte
  206. var dk []byte
  207. for _, folderStr := range db.ListFolders() {
  208. folder := []byte(folderStr)
  209. var putErr error
  210. err := t.withHave(folder, protocol.LocalDeviceID[:], nil, true, func(f FileIntf) bool {
  211. sk, putErr = db.keyer.GenerateSequenceKey(sk, folder, f.SequenceNo())
  212. if putErr != nil {
  213. return false
  214. }
  215. dk, putErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], []byte(f.FileName()))
  216. if putErr != nil {
  217. return false
  218. }
  219. putErr = t.Put(sk, dk)
  220. return putErr == nil
  221. })
  222. if putErr != nil {
  223. return putErr
  224. }
  225. if err != nil {
  226. return err
  227. }
  228. }
  229. return t.Commit()
  230. }
  231. // updateSchema2to3 introduces a needKey->nil bucket for locally needed files.
  232. func (db *schemaUpdater) updateSchema2to3(_ int) error {
  233. t, err := db.newReadWriteTransaction()
  234. if err != nil {
  235. return err
  236. }
  237. defer t.close()
  238. var nk []byte
  239. var dk []byte
  240. for _, folderStr := range db.ListFolders() {
  241. folder := []byte(folderStr)
  242. var putErr error
  243. err := t.withGlobal(folder, nil, true, func(f FileIntf) bool {
  244. name := []byte(f.FileName())
  245. dk, putErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], name)
  246. if putErr != nil {
  247. return false
  248. }
  249. var v protocol.Vector
  250. haveFile, ok, err := t.getFileTrunc(dk, true)
  251. if err != nil {
  252. putErr = err
  253. return false
  254. }
  255. if ok {
  256. v = haveFile.FileVersion()
  257. }
  258. fv := FileVersion{
  259. Version: f.FileVersion(),
  260. Invalid: f.IsInvalid(),
  261. Deleted: f.IsDeleted(),
  262. }
  263. if !need(fv, ok, v) {
  264. return true
  265. }
  266. nk, putErr = t.keyer.GenerateNeedFileKey(nk, folder, []byte(f.FileName()))
  267. if putErr != nil {
  268. return false
  269. }
  270. putErr = t.Put(nk, nil)
  271. return putErr == nil
  272. })
  273. if putErr != nil {
  274. return putErr
  275. }
  276. if err != nil {
  277. return err
  278. }
  279. }
  280. return t.Commit()
  281. }
  282. // updateSchemaTo5 resets the need bucket due to bugs existing in the v0.14.49
  283. // release candidates (dbVersion 3 and 4)
  284. // https://github.com/syncthing/syncthing/issues/5007
  285. // https://github.com/syncthing/syncthing/issues/5053
  286. func (db *schemaUpdater) updateSchemaTo5(prevVersion int) error {
  287. if prevVersion != 3 && prevVersion != 4 {
  288. return nil
  289. }
  290. t, err := db.newReadWriteTransaction()
  291. if err != nil {
  292. return err
  293. }
  294. var nk []byte
  295. for _, folderStr := range db.ListFolders() {
  296. nk, err = db.keyer.GenerateNeedFileKey(nk, []byte(folderStr), nil)
  297. if err != nil {
  298. return err
  299. }
  300. if err := t.deleteKeyPrefix(nk[:keyPrefixLen+keyFolderLen]); err != nil {
  301. return err
  302. }
  303. }
  304. if err := t.Commit(); err != nil {
  305. return err
  306. }
  307. return db.updateSchema2to3(2)
  308. }
  309. func (db *schemaUpdater) updateSchema5to6(_ int) error {
  310. // For every local file with the Invalid bit set, clear the Invalid bit and
  311. // set LocalFlags = FlagLocalIgnored.
  312. t, err := db.newReadWriteTransaction()
  313. if err != nil {
  314. return err
  315. }
  316. defer t.close()
  317. var dk []byte
  318. for _, folderStr := range db.ListFolders() {
  319. folder := []byte(folderStr)
  320. var iterErr error
  321. err := t.withHave(folder, protocol.LocalDeviceID[:], nil, false, func(f FileIntf) bool {
  322. if !f.IsInvalid() {
  323. return true
  324. }
  325. fi := f.(protocol.FileInfo)
  326. fi.RawInvalid = false
  327. fi.LocalFlags = protocol.FlagLocalIgnored
  328. bs, _ := fi.Marshal()
  329. dk, iterErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], []byte(fi.Name))
  330. if iterErr != nil {
  331. return false
  332. }
  333. if iterErr = t.Put(dk, bs); iterErr != nil {
  334. return false
  335. }
  336. iterErr = t.Checkpoint()
  337. return iterErr == nil
  338. })
  339. if iterErr != nil {
  340. return iterErr
  341. }
  342. if err != nil {
  343. return err
  344. }
  345. }
  346. return t.Commit()
  347. }
  348. // updateSchema6to7 checks whether all currently locally needed files are really
  349. // needed and removes them if not.
  350. func (db *schemaUpdater) updateSchema6to7(_ int) error {
  351. t, err := db.newReadWriteTransaction()
  352. if err != nil {
  353. return err
  354. }
  355. defer t.close()
  356. var gk []byte
  357. var nk []byte
  358. for _, folderStr := range db.ListFolders() {
  359. folder := []byte(folderStr)
  360. var delErr error
  361. err := t.withNeedLocal(folder, false, func(f FileIntf) bool {
  362. name := []byte(f.FileName())
  363. gk, delErr = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
  364. if delErr != nil {
  365. return false
  366. }
  367. svl, err := t.Get(gk)
  368. if err != nil {
  369. // If there is no global list, we hardly need it.
  370. key, err := t.keyer.GenerateNeedFileKey(nk, folder, name)
  371. if err != nil {
  372. delErr = err
  373. return false
  374. }
  375. delErr = t.Delete(key)
  376. return delErr == nil
  377. }
  378. var fl VersionList
  379. err = fl.Unmarshal(svl)
  380. if err != nil {
  381. // This can't happen, but it's ignored everywhere else too,
  382. // so lets not act on it.
  383. return true
  384. }
  385. globalFV := FileVersion{
  386. Version: f.FileVersion(),
  387. Invalid: f.IsInvalid(),
  388. Deleted: f.IsDeleted(),
  389. }
  390. if localFV, haveLocalFV := fl.Get(protocol.LocalDeviceID[:]); !need(globalFV, haveLocalFV, localFV.Version) {
  391. key, err := t.keyer.GenerateNeedFileKey(nk, folder, name)
  392. if err != nil {
  393. delErr = err
  394. return false
  395. }
  396. delErr = t.Delete(key)
  397. }
  398. return delErr == nil
  399. })
  400. if delErr != nil {
  401. return delErr
  402. }
  403. if err != nil {
  404. return err
  405. }
  406. if err := t.Checkpoint(); err != nil {
  407. return err
  408. }
  409. }
  410. return t.Commit()
  411. }
  412. func (db *schemaUpdater) updateSchemaTo9(prev int) error {
  413. // Loads and rewrites all files with blocks, to deduplicate block lists.
  414. // Checks for missing or incorrect sequence entries and rewrites those.
  415. t, err := db.newReadWriteTransaction()
  416. if err != nil {
  417. return err
  418. }
  419. defer t.close()
  420. it, err := t.NewPrefixIterator([]byte{KeyTypeDevice})
  421. if err != nil {
  422. return err
  423. }
  424. for it.Next() {
  425. intf, err := t.unmarshalTrunc(it.Value(), false)
  426. if backend.IsNotFound(err) {
  427. // Unmarshal error due to missing parts (block list), probably
  428. // due to a bad migration in a previous RC. Drop this key, as
  429. // getFile would anyway return this as a "not found" in the
  430. // normal flow of things.
  431. if err := t.Delete(it.Key()); err != nil {
  432. return err
  433. }
  434. continue
  435. } else if err != nil {
  436. return err
  437. }
  438. fi := intf.(protocol.FileInfo)
  439. if fi.Blocks == nil {
  440. continue
  441. }
  442. if err := t.putFile(it.Key(), fi, false); err != nil {
  443. return err
  444. }
  445. if err := t.Checkpoint(); err != nil {
  446. return err
  447. }
  448. }
  449. it.Release()
  450. if err := it.Error(); err != nil {
  451. return err
  452. }
  453. db.recordTime(indirectGCTimeKey)
  454. return t.Commit()
  455. }
  456. func (db *schemaUpdater) updateSchemaTo10(_ int) error {
  457. t, err := db.newReadWriteTransaction()
  458. if err != nil {
  459. return err
  460. }
  461. defer t.close()
  462. var buf []byte
  463. for _, folderStr := range db.ListFolders() {
  464. folder := []byte(folderStr)
  465. buf, err = t.keyer.GenerateGlobalVersionKey(buf, folder, nil)
  466. if err != nil {
  467. return err
  468. }
  469. buf = globalVersionKey(buf).WithoutName()
  470. dbi, err := t.NewPrefixIterator(buf)
  471. if err != nil {
  472. return err
  473. }
  474. defer dbi.Release()
  475. for dbi.Next() {
  476. var vl VersionList
  477. if err := vl.Unmarshal(dbi.Value()); err != nil {
  478. return err
  479. }
  480. changed := false
  481. name := t.keyer.NameFromGlobalVersionKey(dbi.Key())
  482. for i, fv := range vl.Versions {
  483. buf, err = t.keyer.GenerateDeviceFileKey(buf, folder, fv.Device, name)
  484. if err != nil {
  485. return err
  486. }
  487. f, ok, err := t.getFileTrunc(buf, true)
  488. if !ok {
  489. return errEntryFromGlobalMissing
  490. }
  491. if err != nil {
  492. return err
  493. }
  494. if f.IsDeleted() {
  495. vl.Versions[i].Deleted = true
  496. changed = true
  497. }
  498. }
  499. if changed {
  500. if err := t.Put(dbi.Key(), mustMarshal(&vl)); err != nil {
  501. return err
  502. }
  503. if err := t.Checkpoint(); err != nil {
  504. return err
  505. }
  506. }
  507. }
  508. dbi.Release()
  509. }
  510. // Trigger metadata recalc
  511. if err := t.deleteKeyPrefix([]byte{KeyTypeFolderMeta}); err != nil {
  512. return err
  513. }
  514. return t.Commit()
  515. }
  516. func (db *schemaUpdater) updateSchemaTo11(_ int) error {
  517. // Populates block list map for every folder.
  518. t, err := db.newReadWriteTransaction()
  519. if err != nil {
  520. return err
  521. }
  522. defer t.close()
  523. var dk []byte
  524. for _, folderStr := range db.ListFolders() {
  525. folder := []byte(folderStr)
  526. var putErr error
  527. err := t.withHave(folder, protocol.LocalDeviceID[:], nil, true, func(fi FileIntf) bool {
  528. f := fi.(FileInfoTruncated)
  529. if f.IsDirectory() || f.IsDeleted() || f.IsSymlink() || f.IsInvalid() || f.BlocksHash == nil {
  530. return true
  531. }
  532. name := []byte(f.FileName())
  533. dk, putErr = db.keyer.GenerateBlockListMapKey(dk, folder, f.BlocksHash, name)
  534. if putErr != nil {
  535. return false
  536. }
  537. if putErr = t.Put(dk, nil); putErr != nil {
  538. return false
  539. }
  540. putErr = t.Checkpoint()
  541. return putErr == nil
  542. })
  543. if putErr != nil {
  544. return putErr
  545. }
  546. if err != nil {
  547. return err
  548. }
  549. }
  550. return t.Commit()
  551. }