meta.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright (C) 2017 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. "time"
  9. "github.com/syncthing/syncthing/lib/protocol"
  10. "github.com/syncthing/syncthing/lib/sync"
  11. )
  12. // like protocol.LocalDeviceID but with 0xf8 in all positions
  13. var globalDeviceID = protocol.DeviceID{0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8}
  14. type metadataTracker struct {
  15. mut sync.RWMutex
  16. counts CountsSet
  17. indexes map[protocol.DeviceID]int // device ID -> index in counts
  18. }
  19. func newMetadataTracker() *metadataTracker {
  20. return &metadataTracker{
  21. mut: sync.NewRWMutex(),
  22. indexes: make(map[protocol.DeviceID]int),
  23. }
  24. }
  25. // Unmarshal loads a metadataTracker from the corresponding protobuf
  26. // representation
  27. func (m *metadataTracker) Unmarshal(bs []byte) error {
  28. if err := m.counts.Unmarshal(bs); err != nil {
  29. return err
  30. }
  31. // Initialize the index map
  32. for i, c := range m.counts.Counts {
  33. m.indexes[protocol.DeviceIDFromBytes(c.DeviceID)] = i
  34. }
  35. return nil
  36. }
  37. // Unmarshal returns the protobuf representation of the metadataTracker
  38. func (m *metadataTracker) Marshal() ([]byte, error) {
  39. return m.counts.Marshal()
  40. }
  41. // toDB saves the marshalled metadataTracker to the given db, under the key
  42. // corresponding to the given folder
  43. func (m *metadataTracker) toDB(db *Instance, folder []byte) error {
  44. key := db.folderMetaKey(folder)
  45. bs, err := m.Marshal()
  46. if err != nil {
  47. return err
  48. }
  49. return db.Put(key, bs, nil)
  50. }
  51. // fromDB initializes the metadataTracker from the marshalled data found in
  52. // the database under the key corresponding to the given folder
  53. func (m *metadataTracker) fromDB(db *Instance, folder []byte) error {
  54. key := db.folderMetaKey(folder)
  55. bs, err := db.Get(key, nil)
  56. if err != nil {
  57. return err
  58. }
  59. return m.Unmarshal(bs)
  60. }
  61. // countsPtr returns a pointer to the corresponding Counts struct, if
  62. // necessary allocating one in the process
  63. func (m *metadataTracker) countsPtr(dev protocol.DeviceID) *Counts {
  64. // must be called with the mutex held
  65. idx, ok := m.indexes[dev]
  66. if !ok {
  67. idx = len(m.counts.Counts)
  68. m.counts.Counts = append(m.counts.Counts, Counts{DeviceID: dev[:]})
  69. m.indexes[dev] = idx
  70. }
  71. return &m.counts.Counts[idx]
  72. }
  73. // addFile adds a file to the counts, adjusting the sequence number as
  74. // appropriate
  75. func (m *metadataTracker) addFile(dev protocol.DeviceID, f FileIntf) {
  76. if f.IsInvalid() {
  77. return
  78. }
  79. m.mut.Lock()
  80. cp := m.countsPtr(dev)
  81. switch {
  82. case f.IsDeleted():
  83. cp.Deleted++
  84. case f.IsDirectory() && !f.IsSymlink():
  85. cp.Directories++
  86. case f.IsSymlink():
  87. cp.Symlinks++
  88. default:
  89. cp.Files++
  90. }
  91. cp.Bytes += f.FileSize()
  92. if seq := f.SequenceNo(); seq > cp.Sequence {
  93. cp.Sequence = seq
  94. }
  95. m.mut.Unlock()
  96. }
  97. // removeFile removes a file from the counts
  98. func (m *metadataTracker) removeFile(dev protocol.DeviceID, f FileIntf) {
  99. if f.IsInvalid() {
  100. return
  101. }
  102. m.mut.Lock()
  103. cp := m.countsPtr(dev)
  104. switch {
  105. case f.IsDeleted():
  106. cp.Deleted--
  107. case f.IsDirectory() && !f.IsSymlink():
  108. cp.Directories--
  109. case f.IsSymlink():
  110. cp.Symlinks--
  111. default:
  112. cp.Files--
  113. }
  114. cp.Bytes -= f.FileSize()
  115. // If we've run into an impossible situation, correct it for now and set
  116. // the created timestamp to zero. Next time we start up the metadata
  117. // will be seen as infinitely old and recalculated from scratch.
  118. if cp.Deleted < 0 {
  119. cp.Deleted = 0
  120. m.counts.Created = 0
  121. }
  122. if cp.Files < 0 {
  123. cp.Files = 0
  124. m.counts.Created = 0
  125. }
  126. if cp.Directories < 0 {
  127. cp.Directories = 0
  128. m.counts.Created = 0
  129. }
  130. if cp.Symlinks < 0 {
  131. cp.Symlinks = 0
  132. m.counts.Created = 0
  133. }
  134. m.mut.Unlock()
  135. }
  136. // resetAll resets all metadata for the given device
  137. func (m *metadataTracker) resetAll(dev protocol.DeviceID) {
  138. m.mut.Lock()
  139. *m.countsPtr(dev) = Counts{DeviceID: dev[:]}
  140. m.mut.Unlock()
  141. }
  142. // resetCounts resets the file, dir, etc. counters, while retaining the
  143. // sequence number
  144. func (m *metadataTracker) resetCounts(dev protocol.DeviceID) {
  145. m.mut.Lock()
  146. c := m.countsPtr(dev)
  147. c.Bytes = 0
  148. c.Deleted = 0
  149. c.Directories = 0
  150. c.Files = 0
  151. c.Symlinks = 0
  152. // c.Sequence deliberately untouched
  153. m.mut.Unlock()
  154. }
  155. // Counts returns the counts for the given device ID
  156. func (m *metadataTracker) Counts(dev protocol.DeviceID) Counts {
  157. m.mut.RLock()
  158. defer m.mut.RUnlock()
  159. idx, ok := m.indexes[dev]
  160. if !ok {
  161. return Counts{}
  162. }
  163. return m.counts.Counts[idx]
  164. }
  165. // nextSeq allocates a new sequence number for the given device
  166. func (m *metadataTracker) nextSeq(dev protocol.DeviceID) int64 {
  167. m.mut.Lock()
  168. defer m.mut.Unlock()
  169. c := m.countsPtr(dev)
  170. c.Sequence++
  171. return c.Sequence
  172. }
  173. // devices returns the list of devices tracked, excluding the local device
  174. // (which we don't know the ID of)
  175. func (m *metadataTracker) devices() []protocol.DeviceID {
  176. devs := make([]protocol.DeviceID, 0, len(m.counts.Counts))
  177. m.mut.RLock()
  178. for _, dev := range m.counts.Counts {
  179. if dev.Sequence > 0 {
  180. id := protocol.DeviceIDFromBytes(dev.DeviceID)
  181. if id == globalDeviceID || id == protocol.LocalDeviceID {
  182. continue
  183. }
  184. devs = append(devs, id)
  185. }
  186. }
  187. m.mut.RUnlock()
  188. return devs
  189. }
  190. func (m *metadataTracker) Created() time.Time {
  191. m.mut.RLock()
  192. defer m.mut.RUnlock()
  193. return time.Unix(0, m.counts.Created)
  194. }
  195. func (m *metadataTracker) SetCreated() {
  196. m.mut.Lock()
  197. m.counts.Created = time.Now().UnixNano()
  198. m.mut.Unlock()
  199. }