leveldb.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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.FileIntf) 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.FileInfoTruncated
  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 tf protocol.FileInfoTruncated
  188. err := tf.UnmarshalXDR(dbi.Value())
  189. if err != nil {
  190. panic(err)
  191. }
  192. if !tf.IsDeleted() {
  193. if debug {
  194. l.Debugf("mark deleted; repo=%q node=%v name=%q", repo, protocol.NodeIDFromBytes(node), name)
  195. }
  196. ts := clock(tf.LocalVersion)
  197. f := protocol.FileInfo{
  198. Name: tf.Name,
  199. Version: lamport.Default.Tick(tf.Version),
  200. LocalVersion: ts,
  201. Flags: tf.Flags | protocol.FlagDeleted,
  202. Modified: tf.Modified,
  203. }
  204. batch.Put(dbi.Key(), f.MarshalXDR())
  205. ldbUpdateGlobal(db, batch, repo, node, nodeKeyName(dbi.Key()), f.Version)
  206. return ts
  207. }
  208. return 0
  209. })
  210. }
  211. func ldbUpdate(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
  212. defer runtime.GC()
  213. batch := new(leveldb.Batch)
  214. snap, err := db.GetSnapshot()
  215. if err != nil {
  216. panic(err)
  217. }
  218. defer snap.Release()
  219. var maxLocalVer uint64
  220. for _, f := range fs {
  221. name := []byte(f.Name)
  222. fk := nodeKey(repo, node, name)
  223. bs, err := snap.Get(fk, nil)
  224. if err == leveldb.ErrNotFound {
  225. if lv := ldbInsert(batch, repo, node, name, f); lv > maxLocalVer {
  226. maxLocalVer = lv
  227. }
  228. ldbUpdateGlobal(snap, batch, repo, node, name, f.Version)
  229. continue
  230. }
  231. var ef protocol.FileInfoTruncated
  232. err = ef.UnmarshalXDR(bs)
  233. if err != nil {
  234. panic(err)
  235. }
  236. if ef.Version != f.Version {
  237. if lv := ldbInsert(batch, repo, node, name, f); lv > maxLocalVer {
  238. maxLocalVer = lv
  239. }
  240. ldbUpdateGlobal(snap, batch, repo, node, name, f.Version)
  241. }
  242. }
  243. err = db.Write(batch, nil)
  244. if err != nil {
  245. panic(err)
  246. }
  247. return maxLocalVer
  248. }
  249. func ldbInsert(batch dbWriter, repo, node, name []byte, file protocol.FileInfo) uint64 {
  250. if debug {
  251. l.Debugf("insert; repo=%q node=%v %v", repo, protocol.NodeIDFromBytes(node), file)
  252. }
  253. if file.LocalVersion == 0 {
  254. file.LocalVersion = clock(0)
  255. }
  256. nk := nodeKey(repo, node, name)
  257. batch.Put(nk, file.MarshalXDR())
  258. return file.LocalVersion
  259. }
  260. // ldbUpdateGlobal adds this node+version to the version list for the given
  261. // file. If the node is already present in the list, the version is updated.
  262. // If the file does not have an entry in the global list, it is created.
  263. func ldbUpdateGlobal(db dbReader, batch dbWriter, repo, node, file []byte, version uint64) bool {
  264. if debug {
  265. l.Debugf("update global; repo=%q node=%v file=%q version=%d", repo, protocol.NodeIDFromBytes(node), file, version)
  266. }
  267. gk := globalKey(repo, file)
  268. svl, err := db.Get(gk, nil)
  269. if err != nil && err != leveldb.ErrNotFound {
  270. panic(err)
  271. }
  272. var fl versionList
  273. nv := fileVersion{
  274. node: node,
  275. version: version,
  276. }
  277. if svl != nil {
  278. err = fl.UnmarshalXDR(svl)
  279. if err != nil {
  280. panic(err)
  281. }
  282. for i := range fl.versions {
  283. if bytes.Compare(fl.versions[i].node, node) == 0 {
  284. if fl.versions[i].version == version {
  285. // No need to do anything
  286. return false
  287. }
  288. fl.versions = append(fl.versions[:i], fl.versions[i+1:]...)
  289. break
  290. }
  291. }
  292. }
  293. for i := range fl.versions {
  294. if fl.versions[i].version <= version {
  295. t := append(fl.versions, fileVersion{})
  296. copy(t[i+1:], t[i:])
  297. t[i] = nv
  298. fl.versions = t
  299. goto done
  300. }
  301. }
  302. fl.versions = append(fl.versions, nv)
  303. done:
  304. batch.Put(gk, fl.MarshalXDR())
  305. return true
  306. }
  307. // ldbRemoveFromGlobal removes the node from the global version list for the
  308. // given file. If the version list is empty after this, the file entry is
  309. // removed entirely.
  310. func ldbRemoveFromGlobal(db dbReader, batch dbWriter, repo, node, file []byte) {
  311. if debug {
  312. l.Debugf("remove from global; repo=%q node=%v file=%q", repo, protocol.NodeIDFromBytes(node), file)
  313. }
  314. gk := globalKey(repo, file)
  315. svl, err := db.Get(gk, nil)
  316. if err != nil {
  317. panic(err)
  318. }
  319. var fl versionList
  320. err = fl.UnmarshalXDR(svl)
  321. if err != nil {
  322. panic(err)
  323. }
  324. for i := range fl.versions {
  325. if bytes.Compare(fl.versions[i].node, node) == 0 {
  326. fl.versions = append(fl.versions[:i], fl.versions[i+1:]...)
  327. break
  328. }
  329. }
  330. if len(fl.versions) == 0 {
  331. batch.Delete(gk)
  332. } else {
  333. batch.Put(gk, fl.MarshalXDR())
  334. }
  335. }
  336. func ldbWithHave(db *leveldb.DB, repo, node []byte, truncate bool, fn fileIterator) {
  337. start := nodeKey(repo, node, nil) // before all repo/node files
  338. limit := nodeKey(repo, node, []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  339. snap, err := db.GetSnapshot()
  340. if err != nil {
  341. panic(err)
  342. }
  343. defer snap.Release()
  344. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  345. defer dbi.Release()
  346. for dbi.Next() {
  347. f, err := unmarshalTrunc(dbi.Value(), truncate)
  348. if err != nil {
  349. panic(err)
  350. }
  351. if cont := fn(f); !cont {
  352. return
  353. }
  354. }
  355. }
  356. func ldbWithAllRepoTruncated(db *leveldb.DB, repo []byte, fn func(node []byte, f protocol.FileInfoTruncated) bool) {
  357. defer runtime.GC()
  358. start := nodeKey(repo, nil, nil) // before all repo/node files
  359. limit := nodeKey(repo, protocol.LocalNodeID[:], []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
  360. snap, err := db.GetSnapshot()
  361. if err != nil {
  362. panic(err)
  363. }
  364. defer snap.Release()
  365. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  366. defer dbi.Release()
  367. for dbi.Next() {
  368. node := nodeKeyNode(dbi.Key())
  369. var f protocol.FileInfoTruncated
  370. err := f.UnmarshalXDR(dbi.Value())
  371. if err != nil {
  372. panic(err)
  373. }
  374. if cont := fn(node, f); !cont {
  375. return
  376. }
  377. }
  378. }
  379. func ldbGet(db *leveldb.DB, repo, node, file []byte) protocol.FileInfo {
  380. nk := nodeKey(repo, node, file)
  381. bs, err := db.Get(nk, nil)
  382. if err == leveldb.ErrNotFound {
  383. return protocol.FileInfo{}
  384. }
  385. if err != nil {
  386. panic(err)
  387. }
  388. var f protocol.FileInfo
  389. err = f.UnmarshalXDR(bs)
  390. if err != nil {
  391. panic(err)
  392. }
  393. return f
  394. }
  395. func ldbGetGlobal(db *leveldb.DB, repo, file []byte) protocol.FileInfo {
  396. k := globalKey(repo, file)
  397. snap, err := db.GetSnapshot()
  398. if err != nil {
  399. panic(err)
  400. }
  401. defer snap.Release()
  402. bs, err := snap.Get(k, nil)
  403. if err == leveldb.ErrNotFound {
  404. return protocol.FileInfo{}
  405. }
  406. if err != nil {
  407. panic(err)
  408. }
  409. var vl versionList
  410. err = vl.UnmarshalXDR(bs)
  411. if err != nil {
  412. panic(err)
  413. }
  414. if len(vl.versions) == 0 {
  415. l.Debugln(k)
  416. panic("no versions?")
  417. }
  418. k = nodeKey(repo, vl.versions[0].node, file)
  419. bs, err = snap.Get(k, nil)
  420. if err != nil {
  421. panic(err)
  422. }
  423. var f protocol.FileInfo
  424. err = f.UnmarshalXDR(bs)
  425. if err != nil {
  426. panic(err)
  427. }
  428. return f
  429. }
  430. func ldbWithGlobal(db *leveldb.DB, repo []byte, truncate bool, fn fileIterator) {
  431. defer runtime.GC()
  432. start := globalKey(repo, nil)
  433. limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
  434. snap, err := db.GetSnapshot()
  435. if err != nil {
  436. panic(err)
  437. }
  438. defer snap.Release()
  439. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  440. defer dbi.Release()
  441. for dbi.Next() {
  442. var vl versionList
  443. err := vl.UnmarshalXDR(dbi.Value())
  444. if err != nil {
  445. panic(err)
  446. }
  447. if len(vl.versions) == 0 {
  448. l.Debugln(dbi.Key())
  449. panic("no versions?")
  450. }
  451. fk := nodeKey(repo, vl.versions[0].node, globalKeyName(dbi.Key()))
  452. bs, err := snap.Get(fk, nil)
  453. if err != nil {
  454. panic(err)
  455. }
  456. f, err := unmarshalTrunc(bs, truncate)
  457. if err != nil {
  458. panic(err)
  459. }
  460. if cont := fn(f); !cont {
  461. return
  462. }
  463. }
  464. }
  465. func ldbAvailability(db *leveldb.DB, repo, file []byte) []protocol.NodeID {
  466. k := globalKey(repo, file)
  467. bs, err := db.Get(k, nil)
  468. if err == leveldb.ErrNotFound {
  469. return nil
  470. }
  471. if err != nil {
  472. panic(err)
  473. }
  474. var vl versionList
  475. err = vl.UnmarshalXDR(bs)
  476. if err != nil {
  477. panic(err)
  478. }
  479. var nodes []protocol.NodeID
  480. for _, v := range vl.versions {
  481. if v.version != vl.versions[0].version {
  482. break
  483. }
  484. n := protocol.NodeIDFromBytes(v.node)
  485. nodes = append(nodes, n)
  486. }
  487. return nodes
  488. }
  489. func ldbWithNeed(db *leveldb.DB, repo, node []byte, truncate bool, fn fileIterator) {
  490. defer runtime.GC()
  491. start := globalKey(repo, nil)
  492. limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
  493. snap, err := db.GetSnapshot()
  494. if err != nil {
  495. panic(err)
  496. }
  497. defer snap.Release()
  498. dbi := snap.NewIterator(&util.Range{Start: start, Limit: limit}, nil)
  499. defer dbi.Release()
  500. for dbi.Next() {
  501. var vl versionList
  502. err := vl.UnmarshalXDR(dbi.Value())
  503. if err != nil {
  504. panic(err)
  505. }
  506. if len(vl.versions) == 0 {
  507. l.Debugln(dbi.Key())
  508. panic("no versions?")
  509. }
  510. have := false // If we have the file, any version
  511. need := false // If we have a lower version of the file
  512. var haveVersion uint64
  513. for _, v := range vl.versions {
  514. if bytes.Compare(v.node, node) == 0 {
  515. have = true
  516. haveVersion = v.version
  517. need = v.version < vl.versions[0].version
  518. break
  519. }
  520. }
  521. if need || !have {
  522. name := globalKeyName(dbi.Key())
  523. fk := nodeKey(repo, vl.versions[0].node, name)
  524. bs, err := snap.Get(fk, nil)
  525. if err != nil {
  526. panic(err)
  527. }
  528. gf, err := unmarshalTrunc(bs, truncate)
  529. if err != nil {
  530. panic(err)
  531. }
  532. if gf.IsDeleted() && !have {
  533. // We don't need deleted files that we don't have
  534. continue
  535. }
  536. if debug {
  537. 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)
  538. }
  539. if cont := fn(gf); !cont {
  540. return
  541. }
  542. }
  543. }
  544. }
  545. func unmarshalTrunc(bs []byte, truncate bool) (protocol.FileIntf, error) {
  546. if truncate {
  547. var tf protocol.FileInfoTruncated
  548. err := tf.UnmarshalXDR(bs)
  549. return tf, err
  550. } else {
  551. var tf protocol.FileInfo
  552. err := tf.UnmarshalXDR(bs)
  553. return tf, err
  554. }
  555. }