leveldb.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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 https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "bytes"
  9. "fmt"
  10. "github.com/syncthing/syncthing/lib/protocol"
  11. )
  12. const (
  13. KeyTypeDevice = iota
  14. KeyTypeGlobal
  15. KeyTypeBlock
  16. KeyTypeDeviceStatistic
  17. KeyTypeFolderStatistic
  18. KeyTypeVirtualMtime
  19. KeyTypeFolderIdx
  20. KeyTypeDeviceIdx
  21. KeyTypeIndexID
  22. KeyTypeFolderMeta
  23. KeyTypeMiscData
  24. KeyTypeSequence
  25. KeyTypeNeed
  26. )
  27. func (vl VersionList) String() string {
  28. var b bytes.Buffer
  29. var id protocol.DeviceID
  30. b.WriteString("{")
  31. for i, v := range vl.Versions {
  32. if i > 0 {
  33. b.WriteString(", ")
  34. }
  35. copy(id[:], v.Device)
  36. fmt.Fprintf(&b, "{%v, %v}", v.Version, id)
  37. }
  38. b.WriteString("}")
  39. return b.String()
  40. }
  41. // update brings the VersionList up to date with file. It returns the updated
  42. // VersionList, a potentially removed old FileVersion and its index, as well as
  43. // the index where the new FileVersion was inserted.
  44. func (vl VersionList) update(folder, device []byte, file protocol.FileInfo, db *Instance) (_ VersionList, removedFV FileVersion, removedAt int, insertedAt int) {
  45. removedAt, insertedAt = -1, -1
  46. for i, v := range vl.Versions {
  47. if bytes.Equal(v.Device, device) {
  48. removedAt = i
  49. removedFV = v
  50. vl.Versions = append(vl.Versions[:i], vl.Versions[i+1:]...)
  51. break
  52. }
  53. }
  54. nv := FileVersion{
  55. Device: device,
  56. Version: file.Version,
  57. Invalid: file.IsInvalid(),
  58. }
  59. for i, v := range vl.Versions {
  60. switch v.Version.Compare(file.Version) {
  61. case protocol.Equal:
  62. if nv.Invalid {
  63. continue
  64. }
  65. fallthrough
  66. case protocol.Lesser:
  67. // The version at this point in the list is equal to or lesser
  68. // ("older") than us. We insert ourselves in front of it.
  69. vl = vl.insertAt(i, nv)
  70. return vl, removedFV, removedAt, i
  71. case protocol.ConcurrentLesser, protocol.ConcurrentGreater:
  72. // The version at this point is in conflict with us. We must pull
  73. // the actual file metadata to determine who wins. If we win, we
  74. // insert ourselves in front of the loser here. (The "Lesser" and
  75. // "Greater" in the condition above is just based on the device
  76. // IDs in the version vector, which is not the only thing we use
  77. // to determine the winner.)
  78. //
  79. // A surprise missing file entry here is counted as a win for us.
  80. if of, ok := db.getFile(db.deviceKey(folder, v.Device, []byte(file.Name))); !ok || file.WinsConflict(of) {
  81. vl = vl.insertAt(i, nv)
  82. return vl, removedFV, removedAt, i
  83. }
  84. }
  85. }
  86. // We didn't find a position for an insert above, so append to the end.
  87. vl.Versions = append(vl.Versions, nv)
  88. return vl, removedFV, removedAt, len(vl.Versions) - 1
  89. }
  90. func (vl VersionList) insertAt(i int, v FileVersion) VersionList {
  91. vl.Versions = append(vl.Versions, FileVersion{})
  92. copy(vl.Versions[i+1:], vl.Versions[i:])
  93. vl.Versions[i] = v
  94. return vl
  95. }
  96. func (vl VersionList) Get(device []byte) (FileVersion, bool) {
  97. for _, v := range vl.Versions {
  98. if bytes.Equal(v.Device, device) {
  99. return v, true
  100. }
  101. }
  102. return FileVersion{}, false
  103. }
  104. type fileList []protocol.FileInfo
  105. func (fl fileList) Len() int {
  106. return len(fl)
  107. }
  108. func (fl fileList) Swap(a, b int) {
  109. fl[a], fl[b] = fl[b], fl[a]
  110. }
  111. func (fl fileList) Less(a, b int) bool {
  112. return fl[a].Name < fl[b].Name
  113. }
  114. // Flush batches to disk when they contain this many records.
  115. const batchFlushSize = 64