leveldb.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. package files
  2. import (
  3. "bytes"
  4. "runtime"
  5. "sort"
  6. "sync"
  7. "github.com/syncthing/syncthing/lamport"
  8. "github.com/syncthing/syncthing/protocol"
  9. "github.com/syndtr/goleveldb/leveldb"
  10. "github.com/syndtr/goleveldb/leveldb/iterator"
  11. "github.com/syndtr/goleveldb/leveldb/opt"
  12. "github.com/syndtr/goleveldb/leveldb/util"
  13. )
  14. var (
  15. clockTick uint64
  16. clockMut sync.Mutex
  17. )
  18. func clock(v uint64) uint64 {
  19. clockMut.Lock()
  20. defer clockMut.Unlock()
  21. if v > clockTick {
  22. clockTick = v + 1
  23. } else {
  24. clockTick++
  25. }
  26. return clockTick
  27. }
  28. const (
  29. keyTypeNode = iota
  30. keyTypeGlobal
  31. )
  32. type fileVersion struct {
  33. version uint64
  34. node []byte
  35. }
  36. type versionList struct {
  37. versions []fileVersion
  38. }
  39. type fileList []protocol.FileInfo
  40. func (l fileList) Len() int {
  41. return len(l)
  42. }
  43. func (l fileList) Swap(a, b int) {
  44. l[a], l[b] = l[b], l[a]
  45. }
  46. func (l fileList) Less(a, b int) bool {
  47. return l[a].Name < l[b].Name
  48. }
  49. type dbReader interface {
  50. Get([]byte, *opt.ReadOptions) ([]byte, error)
  51. }
  52. type dbWriter interface {
  53. Put([]byte, []byte)
  54. Delete([]byte)
  55. }
  56. /*
  57. keyTypeNode (1 byte)
  58. repository (64 bytes)
  59. node (32 bytes)
  60. name (variable size)
  61. |
  62. scanner.File
  63. keyTypeGlobal (1 byte)
  64. repository (64 bytes)
  65. name (variable size)
  66. |
  67. []fileVersion (sorted)
  68. */
  69. func nodeKey(repo, node, file []byte) []byte {
  70. k := make([]byte, 1+64+32+len(file))
  71. k[0] = keyTypeNode
  72. copy(k[1:], []byte(repo))
  73. copy(k[1+64:], node[:])
  74. copy(k[1+64+32:], []byte(file))
  75. return k
  76. }
  77. func globalKey(repo, file []byte) []byte {
  78. k := make([]byte, 1+64+len(file))
  79. k[0] = keyTypeGlobal
  80. copy(k[1:], []byte(repo))
  81. copy(k[1+64:], []byte(file))
  82. return k
  83. }
  84. func nodeKeyName(key []byte) []byte {
  85. return key[1+64+32:]
  86. }
  87. func nodeKeyRepo(key []byte) []byte {
  88. repo := key[1 : 1+64]
  89. izero := bytes.IndexByte(repo, 0)
  90. return repo[:izero]
  91. }
  92. func nodeKeyNode(key []byte) []byte {
  93. return key[1+64 : 1+64+32]
  94. }
  95. func globalKeyName(key []byte) []byte {
  96. return key[1+64:]
  97. }
  98. type deletionHandler func(db dbReader, batch dbWriter, repo, node, name []byte, dbi iterator.Iterator) uint64
  99. type fileIterator func(f protocol.FileInfo) bool
  100. func ldbGenericReplace(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo, deleteFn deletionHandler) uint64 {
  101. defer runtime.GC()
  102. sort.Sort(fileList(fs)) // sort list on name, same as on disk
  103. start := nodeKey(repo, node, nil) // before all repo/node files
  104. limit := nodeKey(repo, node, []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  105. batch := new(leveldb.Batch)
  106. snap, err := db.GetSnapshot()
  107. if err != nil {
  108. panic(err)
  109. }
  110. defer snap.Release()
  111. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  112. defer dbi.Release()
  113. moreDb := dbi.Next()
  114. fsi := 0
  115. var maxLocalVer uint64
  116. for {
  117. var newName, oldName []byte
  118. moreFs := fsi < len(fs)
  119. if !moreDb && !moreFs {
  120. break
  121. }
  122. if !moreFs && deleteFn == nil {
  123. // We don't have any more updated files to process and deletion
  124. // has not been requested, so we can exit early
  125. break
  126. }
  127. if moreFs {
  128. newName = []byte(fs[fsi].Name)
  129. }
  130. if moreDb {
  131. oldName = nodeKeyName(dbi.Key())
  132. }
  133. cmp := bytes.Compare(newName, oldName)
  134. if debug {
  135. l.Debugf("generic replace; repo=%q node=%v moreFs=%v moreDb=%v cmp=%d newName=%q oldName=%q", repo, protocol.NodeIDFromBytes(node), moreFs, moreDb, cmp, newName, oldName)
  136. }
  137. switch {
  138. case moreFs && (!moreDb || cmp == -1):
  139. // Disk is missing this file. Insert it.
  140. if lv := ldbInsert(batch, repo, node, newName, fs[fsi]); lv > maxLocalVer {
  141. maxLocalVer = lv
  142. }
  143. ldbUpdateGlobal(snap, batch, repo, node, newName, fs[fsi].Version)
  144. fsi++
  145. case moreFs && moreDb && cmp == 0:
  146. // File exists on both sides - compare versions.
  147. var ef protocol.FileInfo
  148. ef.UnmarshalXDR(dbi.Value())
  149. if fs[fsi].Version > ef.Version {
  150. if lv := ldbInsert(batch, repo, node, newName, fs[fsi]); lv > maxLocalVer {
  151. maxLocalVer = lv
  152. }
  153. ldbUpdateGlobal(snap, batch, repo, node, newName, fs[fsi].Version)
  154. }
  155. // Iterate both sides.
  156. fsi++
  157. moreDb = dbi.Next()
  158. case moreDb && (!moreFs || cmp == 1):
  159. if deleteFn != nil {
  160. if lv := deleteFn(snap, batch, repo, node, oldName, dbi); lv > maxLocalVer {
  161. maxLocalVer = lv
  162. }
  163. }
  164. moreDb = dbi.Next()
  165. }
  166. }
  167. err = db.Write(batch, nil)
  168. if err != nil {
  169. panic(err)
  170. }
  171. return maxLocalVer
  172. }
  173. func ldbReplace(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
  174. // TODO: Return the remaining maxLocalVer?
  175. return ldbGenericReplace(db, repo, node, fs, func(db dbReader, batch dbWriter, repo, node, name []byte, dbi iterator.Iterator) uint64 {
  176. // Disk has files that we are missing. Remove it.
  177. if debug {
  178. l.Debugf("delete; repo=%q node=%v name=%q", repo, protocol.NodeIDFromBytes(node), name)
  179. }
  180. ldbRemoveFromGlobal(db, batch, repo, node, name)
  181. batch.Delete(dbi.Key())
  182. return 0
  183. })
  184. }
  185. func ldbReplaceWithDelete(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
  186. return ldbGenericReplace(db, repo, node, fs, func(db dbReader, batch dbWriter, repo, node, name []byte, dbi iterator.Iterator) uint64 {
  187. var f protocol.FileInfo
  188. err := f.UnmarshalXDR(dbi.Value())
  189. if err != nil {
  190. panic(err)
  191. }
  192. if !protocol.IsDeleted(f.Flags) {
  193. if debug {
  194. l.Debugf("mark deleted; repo=%q node=%v name=%q", repo, protocol.NodeIDFromBytes(node), name)
  195. }
  196. ts := clock(f.LocalVersion)
  197. f.Blocks = nil
  198. f.Version = lamport.Default.Tick(f.Version)
  199. f.Flags |= protocol.FlagDeleted
  200. f.LocalVersion = ts
  201. batch.Put(dbi.Key(), f.MarshalXDR())
  202. ldbUpdateGlobal(db, batch, repo, node, nodeKeyName(dbi.Key()), f.Version)
  203. return ts
  204. }
  205. return 0
  206. })
  207. }
  208. func ldbUpdate(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
  209. defer runtime.GC()
  210. batch := new(leveldb.Batch)
  211. snap, err := db.GetSnapshot()
  212. if err != nil {
  213. panic(err)
  214. }
  215. defer snap.Release()
  216. var maxLocalVer uint64
  217. for _, f := range fs {
  218. name := []byte(f.Name)
  219. fk := nodeKey(repo, node, name)
  220. bs, err := snap.Get(fk, nil)
  221. if err == leveldb.ErrNotFound {
  222. if lv := ldbInsert(batch, repo, node, name, f); lv > maxLocalVer {
  223. maxLocalVer = lv
  224. }
  225. ldbUpdateGlobal(snap, batch, repo, node, name, f.Version)
  226. continue
  227. }
  228. var ef protocol.FileInfo
  229. err = ef.UnmarshalXDR(bs)
  230. if err != nil {
  231. panic(err)
  232. }
  233. if ef.Version != f.Version {
  234. if lv := ldbInsert(batch, repo, node, name, f); lv > maxLocalVer {
  235. maxLocalVer = lv
  236. }
  237. ldbUpdateGlobal(snap, batch, repo, node, name, f.Version)
  238. }
  239. }
  240. err = db.Write(batch, nil)
  241. if err != nil {
  242. panic(err)
  243. }
  244. return maxLocalVer
  245. }
  246. func ldbInsert(batch dbWriter, repo, node, name []byte, file protocol.FileInfo) uint64 {
  247. if debug {
  248. l.Debugf("insert; repo=%q node=%v %v", repo, protocol.NodeIDFromBytes(node), file)
  249. }
  250. if file.LocalVersion == 0 {
  251. file.LocalVersion = clock(0)
  252. }
  253. nk := nodeKey(repo, node, name)
  254. batch.Put(nk, file.MarshalXDR())
  255. return file.LocalVersion
  256. }
  257. // ldbUpdateGlobal adds this node+version to the version list for the given
  258. // file. If the node is already present in the list, the version is updated.
  259. // If the file does not have an entry in the global list, it is created.
  260. func ldbUpdateGlobal(db dbReader, batch dbWriter, repo, node, file []byte, version uint64) bool {
  261. if debug {
  262. l.Debugf("update global; repo=%q node=%v file=%q version=%d", repo, protocol.NodeIDFromBytes(node), file, version)
  263. }
  264. gk := globalKey(repo, file)
  265. svl, err := db.Get(gk, nil)
  266. if err != nil && err != leveldb.ErrNotFound {
  267. panic(err)
  268. }
  269. var fl versionList
  270. nv := fileVersion{
  271. node: node,
  272. version: version,
  273. }
  274. if svl != nil {
  275. err = fl.UnmarshalXDR(svl)
  276. if err != nil {
  277. panic(err)
  278. }
  279. for i := range fl.versions {
  280. if bytes.Compare(fl.versions[i].node, node) == 0 {
  281. if fl.versions[i].version == version {
  282. // No need to do anything
  283. return false
  284. }
  285. fl.versions = append(fl.versions[:i], fl.versions[i+1:]...)
  286. break
  287. }
  288. }
  289. }
  290. for i := range fl.versions {
  291. if fl.versions[i].version <= version {
  292. t := append(fl.versions, fileVersion{})
  293. copy(t[i+1:], t[i:])
  294. t[i] = nv
  295. fl.versions = t
  296. goto done
  297. }
  298. }
  299. fl.versions = append(fl.versions, nv)
  300. done:
  301. batch.Put(gk, fl.MarshalXDR())
  302. return true
  303. }
  304. // ldbRemoveFromGlobal removes the node from the global version list for the
  305. // given file. If the version list is empty after this, the file entry is
  306. // removed entirely.
  307. func ldbRemoveFromGlobal(db dbReader, batch dbWriter, repo, node, file []byte) {
  308. if debug {
  309. l.Debugf("remove from global; repo=%q node=%v file=%q", repo, protocol.NodeIDFromBytes(node), file)
  310. }
  311. gk := globalKey(repo, file)
  312. svl, err := db.Get(gk, nil)
  313. if err != nil {
  314. panic(err)
  315. }
  316. var fl versionList
  317. err = fl.UnmarshalXDR(svl)
  318. if err != nil {
  319. panic(err)
  320. }
  321. for i := range fl.versions {
  322. if bytes.Compare(fl.versions[i].node, node) == 0 {
  323. fl.versions = append(fl.versions[:i], fl.versions[i+1:]...)
  324. break
  325. }
  326. }
  327. if len(fl.versions) == 0 {
  328. batch.Delete(gk)
  329. } else {
  330. batch.Put(gk, fl.MarshalXDR())
  331. }
  332. }
  333. func ldbWithHave(db *leveldb.DB, repo, node []byte, fn fileIterator) {
  334. start := nodeKey(repo, node, nil) // before all repo/node files
  335. limit := nodeKey(repo, node, []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  336. snap, err := db.GetSnapshot()
  337. if err != nil {
  338. panic(err)
  339. }
  340. defer snap.Release()
  341. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  342. defer dbi.Release()
  343. for dbi.Next() {
  344. var f protocol.FileInfo
  345. err := f.UnmarshalXDR(dbi.Value())
  346. if err != nil {
  347. panic(err)
  348. }
  349. if cont := fn(f); !cont {
  350. return
  351. }
  352. }
  353. }
  354. func ldbWithAllRepo(db *leveldb.DB, repo []byte, fn func(node []byte, f protocol.FileInfo) bool) {
  355. defer runtime.GC()
  356. start := nodeKey(repo, nil, nil) // before all repo/node files
  357. limit := nodeKey(repo, protocol.LocalNodeID[:], []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  358. snap, err := db.GetSnapshot()
  359. if err != nil {
  360. panic(err)
  361. }
  362. defer snap.Release()
  363. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  364. defer dbi.Release()
  365. for dbi.Next() {
  366. node := nodeKeyNode(dbi.Key())
  367. var f protocol.FileInfo
  368. err := f.UnmarshalXDR(dbi.Value())
  369. if err != nil {
  370. panic(err)
  371. }
  372. if cont := fn(node, f); !cont {
  373. return
  374. }
  375. }
  376. }
  377. /*
  378. func ldbCheckGlobalConsistency(db *leveldb.DB, repo []byte) {
  379. l.Debugf("Checking global consistency for %q", repo)
  380. start := nodeKey(repo, nil, nil) // before all repo/node files
  381. limit := nodeKey(repo, protocol.LocalNodeID[:], []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  382. snap, err := db.GetSnapshot()
  383. if err != nil {
  384. panic(err)
  385. }
  386. defer snap.Release()
  387. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  388. defer dbi.Release()
  389. batch := new(leveldb.Batch)
  390. i := 0
  391. for dbi.Next() {
  392. repo := nodeKeyRepo(dbi.Key())
  393. node := nodeKeyNode(dbi.Key())
  394. var f protocol.FileInfo
  395. err := f.UnmarshalXDR(dbi.Value())
  396. if err != nil {
  397. panic(err)
  398. }
  399. if ldbUpdateGlobal(snap, batch, repo, node, []byte(f.Name), f.Version) {
  400. var nodeID protocol.NodeID
  401. copy(nodeID[:], node)
  402. l.Debugf("fixed global for %q %s %q", repo, nodeID, f.Name)
  403. }
  404. i++
  405. }
  406. l.Debugln("Done", i)
  407. }
  408. */
  409. func ldbGet(db *leveldb.DB, repo, node, file []byte) protocol.FileInfo {
  410. nk := nodeKey(repo, node, file)
  411. bs, err := db.Get(nk, nil)
  412. if err == leveldb.ErrNotFound {
  413. return protocol.FileInfo{}
  414. }
  415. if err != nil {
  416. panic(err)
  417. }
  418. var f protocol.FileInfo
  419. err = f.UnmarshalXDR(bs)
  420. if err != nil {
  421. panic(err)
  422. }
  423. return f
  424. }
  425. func ldbGetGlobal(db *leveldb.DB, repo, file []byte) protocol.FileInfo {
  426. k := globalKey(repo, file)
  427. snap, err := db.GetSnapshot()
  428. if err != nil {
  429. panic(err)
  430. }
  431. defer snap.Release()
  432. bs, err := snap.Get(k, nil)
  433. if err == leveldb.ErrNotFound {
  434. return protocol.FileInfo{}
  435. }
  436. if err != nil {
  437. panic(err)
  438. }
  439. var vl versionList
  440. err = vl.UnmarshalXDR(bs)
  441. if err != nil {
  442. panic(err)
  443. }
  444. if len(vl.versions) == 0 {
  445. l.Debugln(k)
  446. panic("no versions?")
  447. }
  448. k = nodeKey(repo, vl.versions[0].node, file)
  449. bs, err = snap.Get(k, nil)
  450. if err != nil {
  451. panic(err)
  452. }
  453. var f protocol.FileInfo
  454. err = f.UnmarshalXDR(bs)
  455. if err != nil {
  456. panic(err)
  457. }
  458. return f
  459. }
  460. func ldbWithGlobal(db *leveldb.DB, repo []byte, fn fileIterator) {
  461. defer runtime.GC()
  462. start := globalKey(repo, nil)
  463. limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
  464. snap, err := db.GetSnapshot()
  465. if err != nil {
  466. panic(err)
  467. }
  468. defer snap.Release()
  469. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  470. defer dbi.Release()
  471. for dbi.Next() {
  472. var vl versionList
  473. err := vl.UnmarshalXDR(dbi.Value())
  474. if err != nil {
  475. panic(err)
  476. }
  477. if len(vl.versions) == 0 {
  478. l.Debugln(dbi.Key())
  479. panic("no versions?")
  480. }
  481. fk := nodeKey(repo, vl.versions[0].node, globalKeyName(dbi.Key()))
  482. bs, err := snap.Get(fk, nil)
  483. if err != nil {
  484. panic(err)
  485. }
  486. var f protocol.FileInfo
  487. err = f.UnmarshalXDR(bs)
  488. if err != nil {
  489. panic(err)
  490. }
  491. if cont := fn(f); !cont {
  492. return
  493. }
  494. }
  495. }
  496. func ldbAvailability(db *leveldb.DB, repo, file []byte) []protocol.NodeID {
  497. k := globalKey(repo, file)
  498. bs, err := db.Get(k, nil)
  499. if err == leveldb.ErrNotFound {
  500. return nil
  501. }
  502. if err != nil {
  503. panic(err)
  504. }
  505. var vl versionList
  506. err = vl.UnmarshalXDR(bs)
  507. if err != nil {
  508. panic(err)
  509. }
  510. var nodes []protocol.NodeID
  511. for _, v := range vl.versions {
  512. if v.version != vl.versions[0].version {
  513. break
  514. }
  515. n := protocol.NodeIDFromBytes(v.node)
  516. nodes = append(nodes, n)
  517. }
  518. return nodes
  519. }
  520. func ldbWithNeed(db *leveldb.DB, repo, node []byte, fn fileIterator) {
  521. defer runtime.GC()
  522. start := globalKey(repo, nil)
  523. limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
  524. snap, err := db.GetSnapshot()
  525. if err != nil {
  526. panic(err)
  527. }
  528. defer snap.Release()
  529. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  530. defer dbi.Release()
  531. for dbi.Next() {
  532. var vl versionList
  533. err := vl.UnmarshalXDR(dbi.Value())
  534. if err != nil {
  535. panic(err)
  536. }
  537. if len(vl.versions) == 0 {
  538. l.Debugln(dbi.Key())
  539. panic("no versions?")
  540. }
  541. have := false // If we have the file, any version
  542. need := false // If we have a lower version of the file
  543. var haveVersion uint64
  544. for _, v := range vl.versions {
  545. if bytes.Compare(v.node, node) == 0 {
  546. have = true
  547. haveVersion = v.version
  548. need = v.version < vl.versions[0].version
  549. break
  550. }
  551. }
  552. if need || !have {
  553. name := globalKeyName(dbi.Key())
  554. fk := nodeKey(repo, vl.versions[0].node, name)
  555. bs, err := snap.Get(fk, nil)
  556. if err != nil {
  557. panic(err)
  558. }
  559. var gf protocol.FileInfo
  560. err = gf.UnmarshalXDR(bs)
  561. if err != nil {
  562. panic(err)
  563. }
  564. if protocol.IsDeleted(gf.Flags) && !have {
  565. // We don't need deleted files that we don't have
  566. continue
  567. }
  568. if debug {
  569. l.Debugf("need repo=%q node=%v name=%q need=%v have=%v haveV=%d globalV=%d", repo, protocol.NodeIDFromBytes(node), name, need, have, haveVersion, vl.versions[0].version)
  570. }
  571. if cont := fn(gf); !cont {
  572. return
  573. }
  574. }
  575. }
  576. }