schemaupdater.go 12 KB

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