meta.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. "bytes"
  9. "math/bits"
  10. "time"
  11. "github.com/syncthing/syncthing/lib/protocol"
  12. "github.com/syncthing/syncthing/lib/sync"
  13. )
  14. // metadataTracker keeps metadata on a per device, per local flag basis.
  15. type metadataTracker struct {
  16. mut sync.RWMutex
  17. counts CountsSet
  18. indexes map[metaKey]int // device ID + local flags -> index in counts
  19. }
  20. type metaKey struct {
  21. dev protocol.DeviceID
  22. flags uint32
  23. }
  24. func newMetadataTracker() *metadataTracker {
  25. return &metadataTracker{
  26. mut: sync.NewRWMutex(),
  27. indexes: make(map[metaKey]int),
  28. }
  29. }
  30. // Unmarshal loads a metadataTracker from the corresponding protobuf
  31. // representation
  32. func (m *metadataTracker) Unmarshal(bs []byte) error {
  33. if err := m.counts.Unmarshal(bs); err != nil {
  34. return err
  35. }
  36. // Initialize the index map
  37. for i, c := range m.counts.Counts {
  38. m.indexes[metaKey{protocol.DeviceIDFromBytes(c.DeviceID), c.LocalFlags}] = i
  39. }
  40. return nil
  41. }
  42. // Unmarshal returns the protobuf representation of the metadataTracker
  43. func (m *metadataTracker) Marshal() ([]byte, error) {
  44. return m.counts.Marshal()
  45. }
  46. // toDB saves the marshalled metadataTracker to the given db, under the key
  47. // corresponding to the given folder
  48. func (m *metadataTracker) toDB(db *Instance, folder []byte) error {
  49. key := db.folderMetaKey(folder)
  50. bs, err := m.Marshal()
  51. if err != nil {
  52. return err
  53. }
  54. return db.Put(key, bs, nil)
  55. }
  56. // fromDB initializes the metadataTracker from the marshalled data found in
  57. // the database under the key corresponding to the given folder
  58. func (m *metadataTracker) fromDB(db *Instance, folder []byte) error {
  59. key := db.folderMetaKey(folder)
  60. bs, err := db.Get(key, nil)
  61. if err != nil {
  62. return err
  63. }
  64. return m.Unmarshal(bs)
  65. }
  66. // countsPtr returns a pointer to the corresponding Counts struct, if
  67. // necessary allocating one in the process
  68. func (m *metadataTracker) countsPtr(dev protocol.DeviceID, flags uint32) *Counts {
  69. // must be called with the mutex held
  70. key := metaKey{dev, flags}
  71. idx, ok := m.indexes[key]
  72. if !ok {
  73. idx = len(m.counts.Counts)
  74. m.counts.Counts = append(m.counts.Counts, Counts{DeviceID: dev[:], LocalFlags: flags})
  75. m.indexes[key] = idx
  76. }
  77. return &m.counts.Counts[idx]
  78. }
  79. // addFile adds a file to the counts, adjusting the sequence number as
  80. // appropriate
  81. func (m *metadataTracker) addFile(dev protocol.DeviceID, f FileIntf) {
  82. if f.IsInvalid() && f.FileLocalFlags() == 0 {
  83. // This is a remote invalid file; it does not count.
  84. return
  85. }
  86. m.mut.Lock()
  87. if flags := f.FileLocalFlags(); flags == 0 {
  88. // Account regular files in the zero-flags bucket.
  89. m.addFileLocked(dev, 0, f)
  90. } else {
  91. // Account in flag specific buckets.
  92. eachFlagBit(flags, func(flag uint32) {
  93. m.addFileLocked(dev, flag, f)
  94. })
  95. }
  96. m.mut.Unlock()
  97. }
  98. func (m *metadataTracker) addFileLocked(dev protocol.DeviceID, flags uint32, f FileIntf) {
  99. cp := m.countsPtr(dev, flags)
  100. switch {
  101. case f.IsDeleted():
  102. cp.Deleted++
  103. case f.IsDirectory() && !f.IsSymlink():
  104. cp.Directories++
  105. case f.IsSymlink():
  106. cp.Symlinks++
  107. default:
  108. cp.Files++
  109. }
  110. cp.Bytes += f.FileSize()
  111. if seq := f.SequenceNo(); seq > cp.Sequence {
  112. cp.Sequence = seq
  113. }
  114. }
  115. // removeFile removes a file from the counts
  116. func (m *metadataTracker) removeFile(dev protocol.DeviceID, f FileIntf) {
  117. if f.IsInvalid() && f.FileLocalFlags() == 0 {
  118. // This is a remote invalid file; it does not count.
  119. return
  120. }
  121. m.mut.Lock()
  122. if flags := f.FileLocalFlags(); flags == 0 {
  123. // Remove regular files from the zero-flags bucket
  124. m.removeFileLocked(dev, 0, f)
  125. } else {
  126. // Remove from flag specific buckets.
  127. eachFlagBit(flags, func(flag uint32) {
  128. m.removeFileLocked(dev, flag, f)
  129. })
  130. }
  131. m.mut.Unlock()
  132. }
  133. func (m *metadataTracker) removeFileLocked(dev protocol.DeviceID, flags uint32, f FileIntf) {
  134. cp := m.countsPtr(dev, f.FileLocalFlags())
  135. switch {
  136. case f.IsDeleted():
  137. cp.Deleted--
  138. case f.IsDirectory() && !f.IsSymlink():
  139. cp.Directories--
  140. case f.IsSymlink():
  141. cp.Symlinks--
  142. default:
  143. cp.Files--
  144. }
  145. cp.Bytes -= f.FileSize()
  146. // If we've run into an impossible situation, correct it for now and set
  147. // the created timestamp to zero. Next time we start up the metadata
  148. // will be seen as infinitely old and recalculated from scratch.
  149. if cp.Deleted < 0 {
  150. cp.Deleted = 0
  151. m.counts.Created = 0
  152. }
  153. if cp.Files < 0 {
  154. cp.Files = 0
  155. m.counts.Created = 0
  156. }
  157. if cp.Directories < 0 {
  158. cp.Directories = 0
  159. m.counts.Created = 0
  160. }
  161. if cp.Symlinks < 0 {
  162. cp.Symlinks = 0
  163. m.counts.Created = 0
  164. }
  165. }
  166. // resetAll resets all metadata for the given device
  167. func (m *metadataTracker) resetAll(dev protocol.DeviceID) {
  168. m.mut.Lock()
  169. for i, c := range m.counts.Counts {
  170. if bytes.Equal(c.DeviceID, dev[:]) {
  171. m.counts.Counts[i] = Counts{
  172. DeviceID: c.DeviceID,
  173. LocalFlags: c.LocalFlags,
  174. }
  175. }
  176. }
  177. m.mut.Unlock()
  178. }
  179. // resetCounts resets the file, dir, etc. counters, while retaining the
  180. // sequence number
  181. func (m *metadataTracker) resetCounts(dev protocol.DeviceID) {
  182. m.mut.Lock()
  183. for i, c := range m.counts.Counts {
  184. if bytes.Equal(c.DeviceID, dev[:]) {
  185. m.counts.Counts[i] = Counts{
  186. DeviceID: c.DeviceID,
  187. Sequence: c.Sequence,
  188. LocalFlags: c.LocalFlags,
  189. }
  190. }
  191. }
  192. m.mut.Unlock()
  193. }
  194. // Counts returns the counts for the given device ID and flag. `flag` should
  195. // be zero or have exactly one bit set.
  196. func (m *metadataTracker) Counts(dev protocol.DeviceID, flag uint32) Counts {
  197. if bits.OnesCount32(flag) > 1 {
  198. panic("incorrect usage: set at most one bit in flag")
  199. }
  200. m.mut.RLock()
  201. defer m.mut.RUnlock()
  202. idx, ok := m.indexes[metaKey{dev, flag}]
  203. if !ok {
  204. return Counts{}
  205. }
  206. return m.counts.Counts[idx]
  207. }
  208. // nextSeq allocates a new sequence number for the given device
  209. func (m *metadataTracker) nextSeq(dev protocol.DeviceID) int64 {
  210. m.mut.Lock()
  211. defer m.mut.Unlock()
  212. c := m.countsPtr(dev, 0)
  213. c.Sequence++
  214. return c.Sequence
  215. }
  216. // devices returns the list of devices tracked, excluding the local device
  217. // (which we don't know the ID of)
  218. func (m *metadataTracker) devices() []protocol.DeviceID {
  219. devs := make(map[protocol.DeviceID]struct{}, len(m.counts.Counts))
  220. m.mut.RLock()
  221. for _, dev := range m.counts.Counts {
  222. if dev.Sequence > 0 {
  223. id := protocol.DeviceIDFromBytes(dev.DeviceID)
  224. if id == protocol.GlobalDeviceID || id == protocol.LocalDeviceID {
  225. continue
  226. }
  227. devs[id] = struct{}{}
  228. }
  229. }
  230. m.mut.RUnlock()
  231. devList := make([]protocol.DeviceID, 0, len(devs))
  232. for dev := range devs {
  233. devList = append(devList, dev)
  234. }
  235. return devList
  236. }
  237. func (m *metadataTracker) Created() time.Time {
  238. m.mut.RLock()
  239. defer m.mut.RUnlock()
  240. return time.Unix(0, m.counts.Created)
  241. }
  242. func (m *metadataTracker) SetCreated() {
  243. m.mut.Lock()
  244. m.counts.Created = time.Now().UnixNano()
  245. m.mut.Unlock()
  246. }
  247. // eachFlagBit calls the function once for every bit that is set in flags
  248. func eachFlagBit(flags uint32, fn func(flag uint32)) {
  249. // Test each bit from the right, as long as there are bits left in the
  250. // flag set. Clear any bits found and stop testing as soon as there are
  251. // no more bits set.
  252. currentBit := uint32(1 << 0)
  253. for flags != 0 {
  254. if flags&currentBit != 0 {
  255. fn(currentBit)
  256. flags &^= currentBit
  257. }
  258. currentBit <<= 1
  259. }
  260. }