1
0

leveldb_dbinstance.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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 http://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "bytes"
  9. "encoding/binary"
  10. "os"
  11. "path/filepath"
  12. "sort"
  13. "strings"
  14. "github.com/syncthing/syncthing/lib/osutil"
  15. "github.com/syncthing/syncthing/lib/protocol"
  16. "github.com/syncthing/syncthing/lib/sync"
  17. "github.com/syndtr/goleveldb/leveldb"
  18. "github.com/syndtr/goleveldb/leveldb/errors"
  19. "github.com/syndtr/goleveldb/leveldb/iterator"
  20. "github.com/syndtr/goleveldb/leveldb/opt"
  21. "github.com/syndtr/goleveldb/leveldb/storage"
  22. "github.com/syndtr/goleveldb/leveldb/util"
  23. )
  24. type deletionHandler func(t readWriteTransaction, folder, device, name []byte, dbi iterator.Iterator) int64
  25. type Instance struct {
  26. *leveldb.DB
  27. folderIdx *smallIndex
  28. deviceIdx *smallIndex
  29. }
  30. const (
  31. keyPrefixLen = 1
  32. keyFolderLen = 4 // indexed
  33. keyDeviceLen = 4 // indexed
  34. keyHashLen = 32
  35. )
  36. func Open(file string) (*Instance, error) {
  37. opts := &opt.Options{
  38. OpenFilesCacheCapacity: 100,
  39. WriteBuffer: 4 << 20,
  40. }
  41. if _, err := os.Stat(file); os.IsNotExist(err) {
  42. // The file we are looking to open does not exist. This may be the
  43. // first launch so we should look for an old version and try to
  44. // convert it.
  45. if err := checkConvertDatabase(file); err != nil {
  46. l.Infoln("Converting old database:", err)
  47. l.Infoln("Will rescan from scratch.")
  48. }
  49. }
  50. db, err := leveldb.OpenFile(file, opts)
  51. if leveldbIsCorrupted(err) {
  52. db, err = leveldb.RecoverFile(file, opts)
  53. }
  54. if leveldbIsCorrupted(err) {
  55. // The database is corrupted, and we've tried to recover it but it
  56. // didn't work. At this point there isn't much to do beyond dropping
  57. // the database and reindexing...
  58. l.Infoln("Database corruption detected, unable to recover. Reinitializing...")
  59. if err := os.RemoveAll(file); err != nil {
  60. return nil, err
  61. }
  62. db, err = leveldb.OpenFile(file, opts)
  63. }
  64. if err != nil {
  65. return nil, err
  66. }
  67. return newDBInstance(db), nil
  68. }
  69. func OpenMemory() *Instance {
  70. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  71. return newDBInstance(db)
  72. }
  73. func newDBInstance(db *leveldb.DB) *Instance {
  74. i := &Instance{
  75. DB: db,
  76. }
  77. i.folderIdx = newSmallIndex(i, []byte{KeyTypeFolderIdx})
  78. i.deviceIdx = newSmallIndex(i, []byte{KeyTypeDeviceIdx})
  79. return i
  80. }
  81. func (db *Instance) Compact() error {
  82. return db.CompactRange(util.Range{})
  83. }
  84. func (db *Instance) genericReplace(folder, device []byte, fs []protocol.FileInfo, localSize, globalSize *sizeTracker, deleteFn deletionHandler) int64 {
  85. sort.Sort(fileList(fs)) // sort list on name, same as in the database
  86. t := db.newReadWriteTransaction()
  87. defer t.close()
  88. dbi := t.NewIterator(util.BytesPrefix(db.deviceKey(folder, device, nil)[:keyPrefixLen+keyFolderLen+keyDeviceLen]), nil)
  89. defer dbi.Release()
  90. moreDb := dbi.Next()
  91. fsi := 0
  92. var maxLocalVer int64
  93. isLocalDevice := bytes.Equal(device, protocol.LocalDeviceID[:])
  94. for {
  95. var newName, oldName []byte
  96. moreFs := fsi < len(fs)
  97. if !moreDb && !moreFs {
  98. break
  99. }
  100. if moreFs {
  101. newName = []byte(fs[fsi].Name)
  102. }
  103. if moreDb {
  104. oldName = db.deviceKeyName(dbi.Key())
  105. }
  106. cmp := bytes.Compare(newName, oldName)
  107. l.Debugf("generic replace; folder=%q device=%v moreFs=%v moreDb=%v cmp=%d newName=%q oldName=%q", folder, protocol.DeviceIDFromBytes(device), moreFs, moreDb, cmp, newName, oldName)
  108. switch {
  109. case moreFs && (!moreDb || cmp == -1):
  110. l.Debugln("generic replace; missing - insert")
  111. // Database is missing this file. Insert it.
  112. if lv := t.insertFile(folder, device, fs[fsi]); lv > maxLocalVer {
  113. maxLocalVer = lv
  114. }
  115. if isLocalDevice {
  116. localSize.addFile(fs[fsi])
  117. }
  118. if fs[fsi].IsInvalid() {
  119. t.removeFromGlobal(folder, device, newName, globalSize)
  120. } else {
  121. t.updateGlobal(folder, device, fs[fsi], globalSize)
  122. }
  123. fsi++
  124. case moreFs && moreDb && cmp == 0:
  125. // File exists on both sides - compare versions. We might get an
  126. // update with the same version and different flags if a device has
  127. // marked a file as invalid, so handle that too.
  128. l.Debugln("generic replace; exists - compare")
  129. var ef FileInfoTruncated
  130. ef.UnmarshalXDR(dbi.Value())
  131. if !fs[fsi].Version.Equal(ef.Version) || fs[fsi].Flags != ef.Flags {
  132. l.Debugln("generic replace; differs - insert")
  133. if lv := t.insertFile(folder, device, fs[fsi]); lv > maxLocalVer {
  134. maxLocalVer = lv
  135. }
  136. if isLocalDevice {
  137. localSize.removeFile(ef)
  138. localSize.addFile(fs[fsi])
  139. }
  140. if fs[fsi].IsInvalid() {
  141. t.removeFromGlobal(folder, device, newName, globalSize)
  142. } else {
  143. t.updateGlobal(folder, device, fs[fsi], globalSize)
  144. }
  145. } else {
  146. l.Debugln("generic replace; equal - ignore")
  147. }
  148. fsi++
  149. moreDb = dbi.Next()
  150. case moreDb && (!moreFs || cmp == 1):
  151. l.Debugln("generic replace; exists - remove")
  152. if lv := deleteFn(t, folder, device, oldName, dbi); lv > maxLocalVer {
  153. maxLocalVer = lv
  154. }
  155. moreDb = dbi.Next()
  156. }
  157. // Write out and reuse the batch every few records, to avoid the batch
  158. // growing too large and thus allocating unnecessarily much memory.
  159. t.checkFlush()
  160. }
  161. return maxLocalVer
  162. }
  163. func (db *Instance) replace(folder, device []byte, fs []protocol.FileInfo, localSize, globalSize *sizeTracker) int64 {
  164. // TODO: Return the remaining maxLocalVer?
  165. return db.genericReplace(folder, device, fs, localSize, globalSize, func(t readWriteTransaction, folder, device, name []byte, dbi iterator.Iterator) int64 {
  166. // Database has a file that we are missing. Remove it.
  167. l.Debugf("delete; folder=%q device=%v name=%q", folder, protocol.DeviceIDFromBytes(device), name)
  168. t.removeFromGlobal(folder, device, name, globalSize)
  169. t.Delete(dbi.Key())
  170. return 0
  171. })
  172. }
  173. func (db *Instance) updateFiles(folder, device []byte, fs []protocol.FileInfo, localSize, globalSize *sizeTracker) int64 {
  174. t := db.newReadWriteTransaction()
  175. defer t.close()
  176. var maxLocalVer int64
  177. var fk []byte
  178. isLocalDevice := bytes.Equal(device, protocol.LocalDeviceID[:])
  179. for _, f := range fs {
  180. name := []byte(f.Name)
  181. fk = db.deviceKeyInto(fk[:cap(fk)], folder, device, name)
  182. bs, err := t.Get(fk, nil)
  183. if err == leveldb.ErrNotFound {
  184. if isLocalDevice {
  185. localSize.addFile(f)
  186. }
  187. if lv := t.insertFile(folder, device, f); lv > maxLocalVer {
  188. maxLocalVer = lv
  189. }
  190. if f.IsInvalid() {
  191. t.removeFromGlobal(folder, device, name, globalSize)
  192. } else {
  193. t.updateGlobal(folder, device, f, globalSize)
  194. }
  195. continue
  196. }
  197. var ef FileInfoTruncated
  198. err = ef.UnmarshalXDR(bs)
  199. if err != nil {
  200. panic(err)
  201. }
  202. // Flags might change without the version being bumped when we set the
  203. // invalid flag on an existing file.
  204. if !ef.Version.Equal(f.Version) || ef.Flags != f.Flags {
  205. if isLocalDevice {
  206. localSize.removeFile(ef)
  207. localSize.addFile(f)
  208. }
  209. if lv := t.insertFile(folder, device, f); lv > maxLocalVer {
  210. maxLocalVer = lv
  211. }
  212. if f.IsInvalid() {
  213. t.removeFromGlobal(folder, device, name, globalSize)
  214. } else {
  215. t.updateGlobal(folder, device, f, globalSize)
  216. }
  217. }
  218. // Write out and reuse the batch every few records, to avoid the batch
  219. // growing too large and thus allocating unnecessarily much memory.
  220. t.checkFlush()
  221. }
  222. return maxLocalVer
  223. }
  224. func (db *Instance) withHave(folder, device, prefix []byte, truncate bool, fn Iterator) {
  225. t := db.newReadOnlyTransaction()
  226. defer t.close()
  227. dbi := t.NewIterator(util.BytesPrefix(db.deviceKey(folder, device, prefix)[:keyPrefixLen+keyFolderLen+keyDeviceLen+len(prefix)]), nil)
  228. defer dbi.Release()
  229. for dbi.Next() {
  230. // The iterator function may keep a reference to the unmarshalled
  231. // struct, which in turn references the buffer it was unmarshalled
  232. // from. dbi.Value() just returns an internal slice that it reuses, so
  233. // we need to copy it.
  234. f, err := unmarshalTrunc(append([]byte{}, dbi.Value()...), truncate)
  235. if err != nil {
  236. panic(err)
  237. }
  238. if cont := fn(f); !cont {
  239. return
  240. }
  241. }
  242. }
  243. func (db *Instance) withAllFolderTruncated(folder []byte, fn func(device []byte, f FileInfoTruncated) bool) {
  244. t := db.newReadWriteTransaction()
  245. defer t.close()
  246. dbi := t.NewIterator(util.BytesPrefix(db.deviceKey(folder, nil, nil)[:keyPrefixLen+keyFolderLen]), nil)
  247. defer dbi.Release()
  248. for dbi.Next() {
  249. device := db.deviceKeyDevice(dbi.Key())
  250. var f FileInfoTruncated
  251. // The iterator function may keep a reference to the unmarshalled
  252. // struct, which in turn references the buffer it was unmarshalled
  253. // from. dbi.Value() just returns an internal slice that it reuses, so
  254. // we need to copy it.
  255. err := f.UnmarshalXDR(append([]byte{}, dbi.Value()...))
  256. if err != nil {
  257. panic(err)
  258. }
  259. switch f.Name {
  260. case "", ".", "..", "/": // A few obviously invalid filenames
  261. l.Infof("Dropping invalid filename %q from database", f.Name)
  262. t.removeFromGlobal(folder, device, nil, nil)
  263. t.Delete(dbi.Key())
  264. t.checkFlush()
  265. continue
  266. }
  267. if cont := fn(device, f); !cont {
  268. return
  269. }
  270. }
  271. }
  272. func (db *Instance) getFile(folder, device, file []byte) (protocol.FileInfo, bool) {
  273. return getFile(db, db.deviceKey(folder, device, file))
  274. }
  275. func (db *Instance) getGlobal(folder, file []byte, truncate bool) (FileIntf, bool) {
  276. k := db.globalKey(folder, file)
  277. t := db.newReadOnlyTransaction()
  278. defer t.close()
  279. bs, err := t.Get(k, nil)
  280. if err == leveldb.ErrNotFound {
  281. return nil, false
  282. }
  283. if err != nil {
  284. panic(err)
  285. }
  286. var vl versionList
  287. err = vl.UnmarshalXDR(bs)
  288. if err != nil {
  289. panic(err)
  290. }
  291. if len(vl.versions) == 0 {
  292. l.Debugln(k)
  293. panic("no versions?")
  294. }
  295. k = db.deviceKey(folder, vl.versions[0].device, file)
  296. bs, err = t.Get(k, nil)
  297. if err != nil {
  298. panic(err)
  299. }
  300. fi, err := unmarshalTrunc(bs, truncate)
  301. if err != nil {
  302. panic(err)
  303. }
  304. return fi, true
  305. }
  306. func (db *Instance) withGlobal(folder, prefix []byte, truncate bool, fn Iterator) {
  307. t := db.newReadOnlyTransaction()
  308. defer t.close()
  309. dbi := t.NewIterator(util.BytesPrefix(db.globalKey(folder, prefix)), nil)
  310. defer dbi.Release()
  311. var fk []byte
  312. for dbi.Next() {
  313. var vl versionList
  314. err := vl.UnmarshalXDR(dbi.Value())
  315. if err != nil {
  316. panic(err)
  317. }
  318. if len(vl.versions) == 0 {
  319. l.Debugln(dbi.Key())
  320. panic("no versions?")
  321. }
  322. name := db.globalKeyName(dbi.Key())
  323. fk = db.deviceKeyInto(fk[:cap(fk)], folder, vl.versions[0].device, name)
  324. bs, err := t.Get(fk, nil)
  325. if err != nil {
  326. l.Debugf("folder: %q (%x)", folder, folder)
  327. l.Debugf("key: %q (%x)", dbi.Key(), dbi.Key())
  328. l.Debugf("vl: %v", vl)
  329. l.Debugf("vl.versions[0].device: %x", vl.versions[0].device)
  330. l.Debugf("name: %q (%x)", name, name)
  331. l.Debugf("fk: %q", fk)
  332. l.Debugf("fk: %x %x %x",
  333. fk[keyPrefixLen:keyPrefixLen+keyFolderLen],
  334. fk[keyPrefixLen+keyFolderLen:keyPrefixLen+keyFolderLen+keyDeviceLen],
  335. fk[keyPrefixLen+keyFolderLen+keyDeviceLen:])
  336. panic(err)
  337. }
  338. f, err := unmarshalTrunc(bs, truncate)
  339. if err != nil {
  340. panic(err)
  341. }
  342. if cont := fn(f); !cont {
  343. return
  344. }
  345. }
  346. }
  347. func (db *Instance) availability(folder, file []byte) []protocol.DeviceID {
  348. k := db.globalKey(folder, file)
  349. bs, err := db.Get(k, nil)
  350. if err == leveldb.ErrNotFound {
  351. return nil
  352. }
  353. if err != nil {
  354. panic(err)
  355. }
  356. var vl versionList
  357. err = vl.UnmarshalXDR(bs)
  358. if err != nil {
  359. panic(err)
  360. }
  361. var devices []protocol.DeviceID
  362. for _, v := range vl.versions {
  363. if !v.version.Equal(vl.versions[0].version) {
  364. break
  365. }
  366. n := protocol.DeviceIDFromBytes(v.device)
  367. devices = append(devices, n)
  368. }
  369. return devices
  370. }
  371. func (db *Instance) withNeed(folder, device []byte, truncate bool, fn Iterator) {
  372. t := db.newReadOnlyTransaction()
  373. defer t.close()
  374. dbi := t.NewIterator(util.BytesPrefix(db.globalKey(folder, nil)[:keyPrefixLen+keyFolderLen]), nil)
  375. defer dbi.Release()
  376. var fk []byte
  377. nextFile:
  378. for dbi.Next() {
  379. var vl versionList
  380. err := vl.UnmarshalXDR(dbi.Value())
  381. if err != nil {
  382. panic(err)
  383. }
  384. if len(vl.versions) == 0 {
  385. l.Debugln(dbi.Key())
  386. panic("no versions?")
  387. }
  388. have := false // If we have the file, any version
  389. need := false // If we have a lower version of the file
  390. var haveVersion protocol.Vector
  391. for _, v := range vl.versions {
  392. if bytes.Compare(v.device, device) == 0 {
  393. have = true
  394. haveVersion = v.version
  395. // XXX: This marks Concurrent (i.e. conflicting) changes as
  396. // needs. Maybe we should do that, but it needs special
  397. // handling in the puller.
  398. need = !v.version.GreaterEqual(vl.versions[0].version)
  399. break
  400. }
  401. }
  402. if need || !have {
  403. name := db.globalKeyName(dbi.Key())
  404. needVersion := vl.versions[0].version
  405. nextVersion:
  406. for i := range vl.versions {
  407. if !vl.versions[i].version.Equal(needVersion) {
  408. // We haven't found a valid copy of the file with the needed version.
  409. continue nextFile
  410. }
  411. fk = db.deviceKeyInto(fk[:cap(fk)], folder, vl.versions[i].device, name)
  412. bs, err := t.Get(fk, nil)
  413. if err != nil {
  414. var id protocol.DeviceID
  415. copy(id[:], device)
  416. l.Debugf("device: %v", id)
  417. l.Debugf("need: %v, have: %v", need, have)
  418. l.Debugf("key: %q (%x)", dbi.Key(), dbi.Key())
  419. l.Debugf("vl: %v", vl)
  420. l.Debugf("i: %v", i)
  421. l.Debugf("fk: %q (%x)", fk, fk)
  422. l.Debugf("name: %q (%x)", name, name)
  423. panic(err)
  424. }
  425. gf, err := unmarshalTrunc(bs, truncate)
  426. if err != nil {
  427. panic(err)
  428. }
  429. if gf.IsInvalid() {
  430. // The file is marked invalid for whatever reason, don't use it.
  431. continue nextVersion
  432. }
  433. if gf.IsDeleted() && !have {
  434. // We don't need deleted files that we don't have
  435. continue nextFile
  436. }
  437. l.Debugf("need folder=%q device=%v name=%q need=%v have=%v haveV=%d globalV=%d", folder, protocol.DeviceIDFromBytes(device), name, need, have, haveVersion, vl.versions[0].version)
  438. if cont := fn(gf); !cont {
  439. return
  440. }
  441. // This file is handled, no need to look further in the version list
  442. continue nextFile
  443. }
  444. }
  445. }
  446. }
  447. func (db *Instance) ListFolders() []string {
  448. t := db.newReadOnlyTransaction()
  449. defer t.close()
  450. dbi := t.NewIterator(util.BytesPrefix([]byte{KeyTypeGlobal}), nil)
  451. defer dbi.Release()
  452. folderExists := make(map[string]bool)
  453. for dbi.Next() {
  454. folder := string(db.globalKeyFolder(dbi.Key()))
  455. if !folderExists[folder] {
  456. folderExists[folder] = true
  457. }
  458. }
  459. folders := make([]string, 0, len(folderExists))
  460. for k := range folderExists {
  461. folders = append(folders, k)
  462. }
  463. sort.Strings(folders)
  464. return folders
  465. }
  466. func (db *Instance) dropFolder(folder []byte) {
  467. t := db.newReadOnlyTransaction()
  468. defer t.close()
  469. // Remove all items related to the given folder from the device->file bucket
  470. dbi := t.NewIterator(util.BytesPrefix([]byte{KeyTypeDevice}), nil)
  471. for dbi.Next() {
  472. itemFolder := db.deviceKeyFolder(dbi.Key())
  473. if bytes.Compare(folder, itemFolder) == 0 {
  474. db.Delete(dbi.Key(), nil)
  475. }
  476. }
  477. dbi.Release()
  478. // Remove all items related to the given folder from the global bucket
  479. dbi = t.NewIterator(util.BytesPrefix([]byte{KeyTypeGlobal}), nil)
  480. for dbi.Next() {
  481. itemFolder := db.globalKeyFolder(dbi.Key())
  482. if bytes.Compare(folder, itemFolder) == 0 {
  483. db.Delete(dbi.Key(), nil)
  484. }
  485. }
  486. dbi.Release()
  487. }
  488. func (db *Instance) checkGlobals(folder []byte, globalSize *sizeTracker) {
  489. t := db.newReadWriteTransaction()
  490. defer t.close()
  491. dbi := t.NewIterator(util.BytesPrefix(db.globalKey(folder, nil)[:keyPrefixLen+keyFolderLen]), nil)
  492. defer dbi.Release()
  493. var fk []byte
  494. for dbi.Next() {
  495. gk := dbi.Key()
  496. var vl versionList
  497. err := vl.UnmarshalXDR(dbi.Value())
  498. if err != nil {
  499. panic(err)
  500. }
  501. // Check the global version list for consistency. An issue in previous
  502. // versions of goleveldb could result in reordered writes so that
  503. // there are global entries pointing to no longer existing files. Here
  504. // we find those and clear them out.
  505. name := db.globalKeyName(gk)
  506. var newVL versionList
  507. for i, version := range vl.versions {
  508. fk = db.deviceKeyInto(fk[:cap(fk)], folder, version.device, name)
  509. _, err := t.Get(fk, nil)
  510. if err == leveldb.ErrNotFound {
  511. continue
  512. }
  513. if err != nil {
  514. panic(err)
  515. }
  516. newVL.versions = append(newVL.versions, version)
  517. if i == 0 {
  518. fi, ok := t.getFile(folder, version.device, name)
  519. if !ok {
  520. panic("nonexistent global master file")
  521. }
  522. globalSize.addFile(fi)
  523. }
  524. }
  525. if len(newVL.versions) != len(vl.versions) {
  526. t.Put(dbi.Key(), newVL.MustMarshalXDR())
  527. t.checkFlush()
  528. }
  529. }
  530. l.Debugf("db check completed for %q", folder)
  531. }
  532. // deviceKey returns a byte slice encoding the following information:
  533. // keyTypeDevice (1 byte)
  534. // folder (4 bytes)
  535. // device (4 bytes)
  536. // name (variable size)
  537. func (db *Instance) deviceKey(folder, device, file []byte) []byte {
  538. return db.deviceKeyInto(nil, folder, device, file)
  539. }
  540. func (db *Instance) deviceKeyInto(k []byte, folder, device, file []byte) []byte {
  541. reqLen := keyPrefixLen + keyFolderLen + keyDeviceLen + len(file)
  542. if len(k) < reqLen {
  543. k = make([]byte, reqLen)
  544. }
  545. k[0] = KeyTypeDevice
  546. binary.BigEndian.PutUint32(k[keyPrefixLen:], db.folderIdx.ID(folder))
  547. binary.BigEndian.PutUint32(k[keyPrefixLen+keyFolderLen:], db.deviceIdx.ID(device))
  548. copy(k[keyPrefixLen+keyFolderLen+keyDeviceLen:], []byte(file))
  549. return k[:reqLen]
  550. }
  551. // deviceKeyName returns the device ID from the key
  552. func (db *Instance) deviceKeyName(key []byte) []byte {
  553. return key[keyPrefixLen+keyFolderLen+keyDeviceLen:]
  554. }
  555. // deviceKeyFolder returns the folder name from the key
  556. func (db *Instance) deviceKeyFolder(key []byte) []byte {
  557. folder, ok := db.folderIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen:]))
  558. if !ok {
  559. panic("bug: lookup of nonexistent folder ID")
  560. }
  561. return folder
  562. }
  563. // deviceKeyDevice returns the device ID from the key
  564. func (db *Instance) deviceKeyDevice(key []byte) []byte {
  565. device, ok := db.deviceIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen+keyFolderLen:]))
  566. if !ok {
  567. panic("bug: lookup of nonexistent device ID")
  568. }
  569. return device
  570. }
  571. // globalKey returns a byte slice encoding the following information:
  572. // keyTypeGlobal (1 byte)
  573. // folder (4 bytes)
  574. // name (variable size)
  575. func (db *Instance) globalKey(folder, file []byte) []byte {
  576. k := make([]byte, keyPrefixLen+keyFolderLen+len(file))
  577. k[0] = KeyTypeGlobal
  578. binary.BigEndian.PutUint32(k[keyPrefixLen:], db.folderIdx.ID(folder))
  579. copy(k[keyPrefixLen+keyFolderLen:], []byte(file))
  580. return k
  581. }
  582. // globalKeyName returns the filename from the key
  583. func (db *Instance) globalKeyName(key []byte) []byte {
  584. return key[keyPrefixLen+keyFolderLen:]
  585. }
  586. // globalKeyFolder returns the folder name from the key
  587. func (db *Instance) globalKeyFolder(key []byte) []byte {
  588. folder, ok := db.folderIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen:]))
  589. if !ok {
  590. panic("bug: lookup of nonexistent folder ID")
  591. }
  592. return folder
  593. }
  594. func unmarshalTrunc(bs []byte, truncate bool) (FileIntf, error) {
  595. if truncate {
  596. var tf FileInfoTruncated
  597. err := tf.UnmarshalXDR(bs)
  598. return tf, err
  599. }
  600. var tf protocol.FileInfo
  601. err := tf.UnmarshalXDR(bs)
  602. return tf, err
  603. }
  604. // A "better" version of leveldb's errors.IsCorrupted.
  605. func leveldbIsCorrupted(err error) bool {
  606. switch {
  607. case err == nil:
  608. return false
  609. case errors.IsCorrupted(err):
  610. return true
  611. case strings.Contains(err.Error(), "corrupted"):
  612. return true
  613. }
  614. return false
  615. }
  616. // checkConvertDatabase tries to convert an existing old (v0.11) database to
  617. // new (v0.13) format.
  618. func checkConvertDatabase(dbFile string) error {
  619. oldLoc := filepath.Join(filepath.Dir(dbFile), "index-v0.11.0.db")
  620. if _, err := os.Stat(oldLoc); os.IsNotExist(err) {
  621. // The old database file does not exist; that's ok, continue as if
  622. // everything succeeded.
  623. return nil
  624. } else if err != nil {
  625. // Any other error is weird.
  626. return err
  627. }
  628. // There exists a database in the old format. We run a one time
  629. // conversion from old to new.
  630. fromDb, err := leveldb.OpenFile(oldLoc, nil)
  631. if err != nil {
  632. return err
  633. }
  634. toDb, err := leveldb.OpenFile(dbFile, nil)
  635. if err != nil {
  636. return err
  637. }
  638. err = convertKeyFormat(fromDb, toDb)
  639. if err != nil {
  640. return err
  641. }
  642. err = toDb.Close()
  643. if err != nil {
  644. return err
  645. }
  646. // We've done this one, we don't want to do it again (if the user runs
  647. // -reset or so). We don't care too much about errors any more at this stage.
  648. fromDb.Close()
  649. osutil.Rename(oldLoc, oldLoc+".converted")
  650. return nil
  651. }
  652. // A smallIndex is an in memory bidirectional []byte to uint32 map. It gives
  653. // fast lookups in both directions and persists to the database. Don't use for
  654. // storing more items than fit comfortably in RAM.
  655. type smallIndex struct {
  656. db *Instance
  657. prefix []byte
  658. id2val map[uint32]string
  659. val2id map[string]uint32
  660. nextID uint32
  661. mut sync.Mutex
  662. }
  663. func newSmallIndex(db *Instance, prefix []byte) *smallIndex {
  664. idx := &smallIndex{
  665. db: db,
  666. prefix: prefix,
  667. id2val: make(map[uint32]string),
  668. val2id: make(map[string]uint32),
  669. mut: sync.NewMutex(),
  670. }
  671. idx.load()
  672. return idx
  673. }
  674. // load iterates over the prefix space in the database and populates the in
  675. // memory maps.
  676. func (i *smallIndex) load() {
  677. tr := i.db.newReadOnlyTransaction()
  678. it := tr.NewIterator(util.BytesPrefix(i.prefix), nil)
  679. for it.Next() {
  680. val := string(it.Value())
  681. id := binary.BigEndian.Uint32(it.Key()[len(i.prefix):])
  682. i.id2val[id] = val
  683. i.val2id[val] = id
  684. if id >= i.nextID {
  685. i.nextID = id + 1
  686. }
  687. }
  688. it.Release()
  689. tr.close()
  690. }
  691. // ID returns the index number for the given byte slice, allocating a new one
  692. // and persisting this to the database if necessary.
  693. func (i *smallIndex) ID(val []byte) uint32 {
  694. i.mut.Lock()
  695. // intentionally avoiding defer here as we want this call to be as fast as
  696. // possible in the general case (folder ID already exists). The map lookup
  697. // with the conversion of []byte to string is compiler optimized to not
  698. // copy the []byte, which is why we don't assign it to a temp variable
  699. // here.
  700. if id, ok := i.val2id[string(val)]; ok {
  701. i.mut.Unlock()
  702. return id
  703. }
  704. id := i.nextID
  705. i.nextID++
  706. valStr := string(val)
  707. i.val2id[valStr] = id
  708. i.id2val[id] = valStr
  709. key := make([]byte, len(i.prefix)+8) // prefix plus uint32 id
  710. copy(key, i.prefix)
  711. binary.BigEndian.PutUint32(key[len(i.prefix):], id)
  712. i.db.Put(key, val, nil)
  713. i.mut.Unlock()
  714. return id
  715. }
  716. // Val returns the value for the given index number, or (nil, false) if there
  717. // is no such index number.
  718. func (i *smallIndex) Val(id uint32) ([]byte, bool) {
  719. i.mut.Lock()
  720. val, ok := i.id2val[id]
  721. i.mut.Unlock()
  722. if !ok {
  723. return nil, false
  724. }
  725. return []byte(val), true
  726. }