set.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
  2. // Use of this source code is governed by an MIT-style license that can be
  3. // found in the LICENSE file.
  4. // Package files provides a set type to track local/remote files with newness checks.
  5. package files
  6. import (
  7. "sync"
  8. "github.com/calmh/syncthing/cid"
  9. "github.com/calmh/syncthing/lamport"
  10. "github.com/calmh/syncthing/protocol"
  11. "github.com/calmh/syncthing/scanner"
  12. )
  13. type fileRecord struct {
  14. File scanner.File
  15. Usage int
  16. Global bool
  17. }
  18. type bitset uint64
  19. type Set struct {
  20. sync.Mutex
  21. files map[key]fileRecord
  22. remoteKey [64]map[string]key
  23. changes [64]uint64
  24. globalAvailability map[string]bitset
  25. globalKey map[string]key
  26. }
  27. func NewSet() *Set {
  28. var m = Set{
  29. files: make(map[key]fileRecord),
  30. globalAvailability: make(map[string]bitset),
  31. globalKey: make(map[string]key),
  32. }
  33. return &m
  34. }
  35. func (m *Set) Replace(id uint, fs []scanner.File) {
  36. if debug {
  37. l.Debugf("Replace(%d, [%d])", id, len(fs))
  38. }
  39. if id > 63 {
  40. panic("Connection ID must be in the range 0 - 63 inclusive")
  41. }
  42. m.Lock()
  43. if len(fs) == 0 || !m.equals(id, fs) {
  44. m.changes[id]++
  45. m.replace(id, fs)
  46. }
  47. m.Unlock()
  48. }
  49. func (m *Set) ReplaceWithDelete(id uint, fs []scanner.File) {
  50. if debug {
  51. l.Debugf("ReplaceWithDelete(%d, [%d])", id, len(fs))
  52. }
  53. if id > 63 {
  54. panic("Connection ID must be in the range 0 - 63 inclusive")
  55. }
  56. m.Lock()
  57. if len(fs) == 0 || !m.equals(id, fs) {
  58. m.changes[id]++
  59. var nf = make(map[string]key, len(fs))
  60. for _, f := range fs {
  61. nf[f.Name] = keyFor(f)
  62. }
  63. // For previously existing files not in the list, add them to the list
  64. // with the relevant delete flags etc set. Previously existing files
  65. // with the delete bit already set are not modified.
  66. for _, ck := range m.remoteKey[cid.LocalID] {
  67. if _, ok := nf[ck.Name]; !ok {
  68. cf := m.files[ck].File
  69. if !protocol.IsDeleted(cf.Flags) {
  70. cf.Flags |= protocol.FlagDeleted
  71. cf.Blocks = nil
  72. cf.Size = 0
  73. cf.Version = lamport.Default.Tick(cf.Version)
  74. }
  75. fs = append(fs, cf)
  76. if debug {
  77. l.Debugln("deleted:", ck.Name)
  78. }
  79. }
  80. }
  81. m.replace(id, fs)
  82. }
  83. m.Unlock()
  84. }
  85. func (m *Set) Update(id uint, fs []scanner.File) {
  86. if debug {
  87. l.Debugf("Update(%d, [%d])", id, len(fs))
  88. }
  89. m.Lock()
  90. m.update(id, fs)
  91. m.changes[id]++
  92. m.Unlock()
  93. }
  94. func (m *Set) Need(id uint) []scanner.File {
  95. if debug {
  96. l.Debugf("Need(%d)", id)
  97. }
  98. m.Lock()
  99. var fs = make([]scanner.File, 0, len(m.globalKey)/2) // Just a guess, but avoids too many reallocations
  100. rkID := m.remoteKey[id]
  101. for gk, gf := range m.files {
  102. if !gf.Global || gf.File.Suppressed {
  103. continue
  104. }
  105. if rk, ok := rkID[gk.Name]; gk.newerThan(rk) {
  106. if protocol.IsDeleted(gf.File.Flags) && (!ok || protocol.IsDeleted(m.files[rk].File.Flags)) {
  107. // We don't need to delete files we don't have or that are already deleted
  108. continue
  109. }
  110. fs = append(fs, gf.File)
  111. }
  112. }
  113. m.Unlock()
  114. return fs
  115. }
  116. func (m *Set) Have(id uint) []scanner.File {
  117. if debug {
  118. l.Debugf("Have(%d)", id)
  119. }
  120. var fs = make([]scanner.File, 0, len(m.remoteKey[id]))
  121. m.Lock()
  122. for _, rk := range m.remoteKey[id] {
  123. fs = append(fs, m.files[rk].File)
  124. }
  125. m.Unlock()
  126. return fs
  127. }
  128. func (m *Set) Global() []scanner.File {
  129. if debug {
  130. l.Debugf("Global()")
  131. }
  132. m.Lock()
  133. var fs = make([]scanner.File, 0, len(m.globalKey))
  134. for _, file := range m.files {
  135. if file.Global {
  136. fs = append(fs, file.File)
  137. }
  138. }
  139. m.Unlock()
  140. return fs
  141. }
  142. func (m *Set) Get(id uint, file string) scanner.File {
  143. m.Lock()
  144. defer m.Unlock()
  145. if debug {
  146. l.Debugf("Get(%d, %q)", id, file)
  147. }
  148. return m.files[m.remoteKey[id][file]].File
  149. }
  150. func (m *Set) GetGlobal(file string) scanner.File {
  151. m.Lock()
  152. defer m.Unlock()
  153. if debug {
  154. l.Debugf("GetGlobal(%q)", file)
  155. }
  156. return m.files[m.globalKey[file]].File
  157. }
  158. func (m *Set) Availability(name string) bitset {
  159. m.Lock()
  160. defer m.Unlock()
  161. av := m.globalAvailability[name]
  162. if debug {
  163. l.Debugf("Availability(%q) = %0x", name, av)
  164. }
  165. return av
  166. }
  167. func (m *Set) Changes(id uint) uint64 {
  168. m.Lock()
  169. defer m.Unlock()
  170. if debug {
  171. l.Debugf("Changes(%d)", id)
  172. }
  173. return m.changes[id]
  174. }
  175. func (m *Set) equals(id uint, fs []scanner.File) bool {
  176. curWithoutDeleted := make(map[string]key)
  177. for _, k := range m.remoteKey[id] {
  178. f := m.files[k].File
  179. if !protocol.IsDeleted(f.Flags) {
  180. curWithoutDeleted[f.Name] = k
  181. }
  182. }
  183. if len(curWithoutDeleted) != len(fs) {
  184. return false
  185. }
  186. for _, f := range fs {
  187. if curWithoutDeleted[f.Name] != keyFor(f) {
  188. return false
  189. }
  190. }
  191. return true
  192. }
  193. func (m *Set) update(cid uint, fs []scanner.File) {
  194. remFiles := m.remoteKey[cid]
  195. if remFiles == nil {
  196. l.Fatalln("update before replace for cid", cid)
  197. }
  198. for _, f := range fs {
  199. n := f.Name
  200. fk := keyFor(f)
  201. if ck, ok := remFiles[n]; ok && ck == fk {
  202. // The remote already has exactly this file, skip it
  203. continue
  204. }
  205. remFiles[n] = fk
  206. // Keep the block list or increment the usage
  207. if br, ok := m.files[fk]; !ok {
  208. m.files[fk] = fileRecord{
  209. Usage: 1,
  210. File: f,
  211. }
  212. } else {
  213. br.Usage++
  214. m.files[fk] = br
  215. }
  216. // Update global view
  217. gk, ok := m.globalKey[n]
  218. switch {
  219. case ok && fk == gk:
  220. av := m.globalAvailability[n]
  221. av |= 1 << cid
  222. m.globalAvailability[n] = av
  223. case fk.newerThan(gk):
  224. if ok {
  225. f := m.files[gk]
  226. f.Global = false
  227. m.files[gk] = f
  228. }
  229. f := m.files[fk]
  230. f.Global = true
  231. m.files[fk] = f
  232. m.globalKey[n] = fk
  233. m.globalAvailability[n] = 1 << cid
  234. }
  235. }
  236. }
  237. func (m *Set) replace(cid uint, fs []scanner.File) {
  238. // Decrement usage for all files belonging to this remote, and remove
  239. // those that are no longer needed.
  240. for _, fk := range m.remoteKey[cid] {
  241. br, ok := m.files[fk]
  242. switch {
  243. case ok && br.Usage == 1:
  244. delete(m.files, fk)
  245. case ok && br.Usage > 1:
  246. br.Usage--
  247. m.files[fk] = br
  248. }
  249. }
  250. // Clear existing remote remoteKey
  251. m.remoteKey[cid] = make(map[string]key)
  252. // Recalculate global based on all remaining remoteKey
  253. for n := range m.globalKey {
  254. var nk key // newest key
  255. var na bitset // newest availability
  256. for i, rem := range m.remoteKey {
  257. if rk, ok := rem[n]; ok {
  258. switch {
  259. case rk == nk:
  260. na |= 1 << uint(i)
  261. case rk.newerThan(nk):
  262. nk = rk
  263. na = 1 << uint(i)
  264. }
  265. }
  266. }
  267. if na != 0 {
  268. // Someone had the file
  269. f := m.files[nk]
  270. f.Global = true
  271. m.files[nk] = f
  272. m.globalKey[n] = nk
  273. m.globalAvailability[n] = na
  274. } else {
  275. // Noone had the file
  276. delete(m.globalKey, n)
  277. delete(m.globalAvailability, n)
  278. }
  279. }
  280. // Add new remote remoteKey to the mix
  281. m.update(cid, fs)
  282. }