schemaupdater.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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/protocol"
  11. )
  12. // List of all dbVersion to dbMinSyncthingVersion pairs for convenience
  13. // 0: v0.14.0
  14. // 1: v0.14.46
  15. // 2: v0.14.48
  16. // 3: v0.14.49
  17. // 4: v0.14.49
  18. // 5: v0.14.49
  19. // 6: v0.14.50
  20. // 7: v0.14.53
  21. const (
  22. dbVersion = 7
  23. dbMinSyncthingVersion = "v0.14.53"
  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. miscDB := NewMiscDataNamespace(db.Lowlevel)
  43. prevVersion, _, err := miscDB.Int64("dbVersion")
  44. if err != nil {
  45. return err
  46. }
  47. if prevVersion > dbVersion {
  48. err := databaseDowngradeError{}
  49. if minSyncthingVersion, ok, dbErr := miscDB.String("dbMinSyncthingVersion"); dbErr != nil {
  50. return dbErr
  51. } else if ok {
  52. err.minSyncthingVersion = minSyncthingVersion
  53. }
  54. return err
  55. }
  56. if prevVersion == dbVersion {
  57. return nil
  58. }
  59. if prevVersion < 1 {
  60. if err := db.updateSchema0to1(); err != nil {
  61. return err
  62. }
  63. }
  64. if prevVersion < 2 {
  65. if err := db.updateSchema1to2(); err != nil {
  66. return err
  67. }
  68. }
  69. if prevVersion < 3 {
  70. if err := db.updateSchema2to3(); err != nil {
  71. return err
  72. }
  73. }
  74. // This update fixes problems existing in versions 3 and 4
  75. if prevVersion == 3 || prevVersion == 4 {
  76. if err := db.updateSchemaTo5(); err != nil {
  77. return err
  78. }
  79. }
  80. if prevVersion < 6 {
  81. if err := db.updateSchema5to6(); err != nil {
  82. return err
  83. }
  84. }
  85. if prevVersion < 7 {
  86. if err := db.updateSchema6to7(); err != nil {
  87. return err
  88. }
  89. }
  90. if err := miscDB.PutInt64("dbVersion", dbVersion); err != nil {
  91. return err
  92. }
  93. if err := miscDB.PutString("dbMinSyncthingVersion", dbMinSyncthingVersion); err != nil {
  94. return err
  95. }
  96. return nil
  97. }
  98. func (db *schemaUpdater) updateSchema0to1() error {
  99. t, err := db.newReadWriteTransaction()
  100. if err != nil {
  101. return err
  102. }
  103. defer t.close()
  104. dbi, err := t.NewPrefixIterator([]byte{KeyTypeDevice})
  105. if err != nil {
  106. return err
  107. }
  108. defer dbi.Release()
  109. symlinkConv := 0
  110. changedFolders := make(map[string]struct{})
  111. ignAdded := 0
  112. meta := newMetadataTracker() // dummy metadata tracker
  113. var gk, buf []byte
  114. for dbi.Next() {
  115. folder, ok := db.keyer.FolderFromDeviceFileKey(dbi.Key())
  116. if !ok {
  117. // not having the folder in the index is bad; delete and continue
  118. if err := t.Delete(dbi.Key()); err != nil {
  119. return err
  120. }
  121. continue
  122. }
  123. device, ok := db.keyer.DeviceFromDeviceFileKey(dbi.Key())
  124. if !ok {
  125. // not having the device in the index is bad; delete and continue
  126. if err := t.Delete(dbi.Key()); err != nil {
  127. return err
  128. }
  129. continue
  130. }
  131. name := db.keyer.NameFromDeviceFileKey(dbi.Key())
  132. // Remove files with absolute path (see #4799)
  133. if strings.HasPrefix(string(name), "/") {
  134. if _, ok := changedFolders[string(folder)]; !ok {
  135. changedFolders[string(folder)] = struct{}{}
  136. }
  137. gk, err = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
  138. if err != nil {
  139. return err
  140. }
  141. buf, err = t.removeFromGlobal(gk, buf, folder, device, nil, nil)
  142. if err != nil {
  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. }
  187. for folder := range changedFolders {
  188. if err := db.dropFolderMeta([]byte(folder)); err != nil {
  189. return err
  190. }
  191. }
  192. return t.commit()
  193. }
  194. // updateSchema1to2 introduces a sequenceKey->deviceKey bucket for local items
  195. // to allow iteration in sequence order (simplifies sending indexes).
  196. func (db *schemaUpdater) updateSchema1to2() error {
  197. t, err := db.newReadWriteTransaction()
  198. if err != nil {
  199. return err
  200. }
  201. defer t.close()
  202. var sk []byte
  203. var dk []byte
  204. for _, folderStr := range db.ListFolders() {
  205. folder := []byte(folderStr)
  206. var putErr error
  207. err := db.withHave(folder, protocol.LocalDeviceID[:], nil, true, func(f FileIntf) bool {
  208. sk, putErr = db.keyer.GenerateSequenceKey(sk, folder, f.SequenceNo())
  209. if putErr != nil {
  210. return false
  211. }
  212. dk, putErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], []byte(f.FileName()))
  213. if putErr != nil {
  214. return false
  215. }
  216. putErr = t.Put(sk, dk)
  217. return putErr == nil
  218. })
  219. if putErr != nil {
  220. return putErr
  221. }
  222. if err != nil {
  223. return err
  224. }
  225. }
  226. return t.commit()
  227. }
  228. // updateSchema2to3 introduces a needKey->nil bucket for locally needed files.
  229. func (db *schemaUpdater) updateSchema2to3() error {
  230. t, err := db.newReadWriteTransaction()
  231. if err != nil {
  232. return err
  233. }
  234. defer t.close()
  235. var nk []byte
  236. var dk []byte
  237. for _, folderStr := range db.ListFolders() {
  238. folder := []byte(folderStr)
  239. var putErr error
  240. err := db.withGlobal(folder, nil, true, func(f FileIntf) bool {
  241. name := []byte(f.FileName())
  242. dk, putErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], name)
  243. if putErr != nil {
  244. return false
  245. }
  246. var v protocol.Vector
  247. haveFile, ok, err := t.getFileTrunc(dk, true)
  248. if err != nil {
  249. putErr = err
  250. return false
  251. }
  252. if ok {
  253. v = haveFile.FileVersion()
  254. }
  255. if !need(f, ok, v) {
  256. return true
  257. }
  258. nk, putErr = t.keyer.GenerateNeedFileKey(nk, folder, []byte(f.FileName()))
  259. if putErr != nil {
  260. return false
  261. }
  262. putErr = t.Put(nk, nil)
  263. return putErr == nil
  264. })
  265. if putErr != nil {
  266. return putErr
  267. }
  268. if err != nil {
  269. return err
  270. }
  271. }
  272. return t.commit()
  273. }
  274. // updateSchemaTo5 resets the need bucket due to bugs existing in the v0.14.49
  275. // release candidates (dbVersion 3 and 4)
  276. // https://github.com/syncthing/syncthing/issues/5007
  277. // https://github.com/syncthing/syncthing/issues/5053
  278. func (db *schemaUpdater) updateSchemaTo5() error {
  279. t, err := db.newReadWriteTransaction()
  280. if err != nil {
  281. return err
  282. }
  283. var nk []byte
  284. for _, folderStr := range db.ListFolders() {
  285. nk, err = db.keyer.GenerateNeedFileKey(nk, []byte(folderStr), nil)
  286. if err != nil {
  287. return err
  288. }
  289. if err := t.deleteKeyPrefix(nk[:keyPrefixLen+keyFolderLen]); err != nil {
  290. return err
  291. }
  292. }
  293. if err := t.commit(); err != nil {
  294. return err
  295. }
  296. return db.updateSchema2to3()
  297. }
  298. func (db *schemaUpdater) updateSchema5to6() error {
  299. // For every local file with the Invalid bit set, clear the Invalid bit and
  300. // set LocalFlags = FlagLocalIgnored.
  301. t, err := db.newReadWriteTransaction()
  302. if err != nil {
  303. return err
  304. }
  305. defer t.close()
  306. var dk []byte
  307. for _, folderStr := range db.ListFolders() {
  308. folder := []byte(folderStr)
  309. var putErr error
  310. err := db.withHave(folder, protocol.LocalDeviceID[:], nil, false, func(f FileIntf) bool {
  311. if !f.IsInvalid() {
  312. return true
  313. }
  314. fi := f.(protocol.FileInfo)
  315. fi.RawInvalid = false
  316. fi.LocalFlags = protocol.FlagLocalIgnored
  317. bs, _ := fi.Marshal()
  318. dk, putErr = db.keyer.GenerateDeviceFileKey(dk, folder, protocol.LocalDeviceID[:], []byte(fi.Name))
  319. if putErr != nil {
  320. return false
  321. }
  322. putErr = t.Put(dk, bs)
  323. return putErr == nil
  324. })
  325. if putErr != nil {
  326. return putErr
  327. }
  328. if err != nil {
  329. return err
  330. }
  331. }
  332. return t.commit()
  333. }
  334. // updateSchema6to7 checks whether all currently locally needed files are really
  335. // needed and removes them if not.
  336. func (db *schemaUpdater) updateSchema6to7() error {
  337. t, err := db.newReadWriteTransaction()
  338. if err != nil {
  339. return err
  340. }
  341. defer t.close()
  342. var gk []byte
  343. var nk []byte
  344. for _, folderStr := range db.ListFolders() {
  345. folder := []byte(folderStr)
  346. var delErr error
  347. err := db.withNeedLocal(folder, false, func(f FileIntf) bool {
  348. name := []byte(f.FileName())
  349. global := f.(protocol.FileInfo)
  350. gk, delErr = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
  351. if delErr != nil {
  352. return false
  353. }
  354. svl, err := t.Get(gk)
  355. if err != nil {
  356. // If there is no global list, we hardly need it.
  357. key, err := t.keyer.GenerateNeedFileKey(nk, folder, name)
  358. if err != nil {
  359. delErr = err
  360. return false
  361. }
  362. delErr = t.Delete(key)
  363. return delErr == nil
  364. }
  365. var fl VersionList
  366. err = fl.Unmarshal(svl)
  367. if err != nil {
  368. // This can't happen, but it's ignored everywhere else too,
  369. // so lets not act on it.
  370. return true
  371. }
  372. if localFV, haveLocalFV := fl.Get(protocol.LocalDeviceID[:]); !need(global, haveLocalFV, localFV.Version) {
  373. key, err := t.keyer.GenerateNeedFileKey(nk, folder, name)
  374. if err != nil {
  375. delErr = err
  376. return false
  377. }
  378. delErr = t.Delete(key)
  379. }
  380. return delErr == nil
  381. })
  382. if err != nil {
  383. return err
  384. }
  385. }
  386. return t.commit()
  387. }