meta.go 7.9 KB

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