schemaupdater.go 12 KB

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