set.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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 gk.newerThan(rkID[gk.Name]) {
  106. fs = append(fs, gf.File)
  107. }
  108. }
  109. m.Unlock()
  110. return fs
  111. }
  112. func (m *Set) Have(id uint) []scanner.File {
  113. if debug {
  114. l.Debugf("Have(%d)", id)
  115. }
  116. var fs = make([]scanner.File, 0, len(m.remoteKey[id]))
  117. m.Lock()
  118. for _, rk := range m.remoteKey[id] {
  119. fs = append(fs, m.files[rk].File)
  120. }
  121. m.Unlock()
  122. return fs
  123. }
  124. func (m *Set) Global() []scanner.File {
  125. if debug {
  126. l.Debugf("Global()")
  127. }
  128. m.Lock()
  129. var fs = make([]scanner.File, 0, len(m.globalKey))
  130. for _, file := range m.files {
  131. if file.Global {
  132. fs = append(fs, file.File)
  133. }
  134. }
  135. m.Unlock()
  136. return fs
  137. }
  138. func (m *Set) Get(id uint, file string) scanner.File {
  139. m.Lock()
  140. defer m.Unlock()
  141. if debug {
  142. l.Debugf("Get(%d, %q)", id, file)
  143. }
  144. return m.files[m.remoteKey[id][file]].File
  145. }
  146. func (m *Set) GetGlobal(file string) scanner.File {
  147. m.Lock()
  148. defer m.Unlock()
  149. if debug {
  150. l.Debugf("GetGlobal(%q)", file)
  151. }
  152. return m.files[m.globalKey[file]].File
  153. }
  154. func (m *Set) Availability(name string) bitset {
  155. m.Lock()
  156. defer m.Unlock()
  157. av := m.globalAvailability[name]
  158. if debug {
  159. l.Debugf("Availability(%q) = %0x", name, av)
  160. }
  161. return av
  162. }
  163. func (m *Set) Changes(id uint) uint64 {
  164. m.Lock()
  165. defer m.Unlock()
  166. if debug {
  167. l.Debugf("Changes(%d)", id)
  168. }
  169. return m.changes[id]
  170. }
  171. func (m *Set) equals(id uint, fs []scanner.File) bool {
  172. curWithoutDeleted := make(map[string]key)
  173. for _, k := range m.remoteKey[id] {
  174. f := m.files[k].File
  175. if !protocol.IsDeleted(f.Flags) {
  176. curWithoutDeleted[f.Name] = k
  177. }
  178. }
  179. if len(curWithoutDeleted) != len(fs) {
  180. return false
  181. }
  182. for _, f := range fs {
  183. if curWithoutDeleted[f.Name] != keyFor(f) {
  184. return false
  185. }
  186. }
  187. return true
  188. }
  189. func (m *Set) update(cid uint, fs []scanner.File) {
  190. remFiles := m.remoteKey[cid]
  191. if remFiles == nil {
  192. l.Fatalln("update before replace for cid", cid)
  193. }
  194. for _, f := range fs {
  195. n := f.Name
  196. fk := keyFor(f)
  197. if ck, ok := remFiles[n]; ok && ck == fk {
  198. // The remote already has exactly this file, skip it
  199. continue
  200. }
  201. remFiles[n] = fk
  202. // Keep the block list or increment the usage
  203. if br, ok := m.files[fk]; !ok {
  204. m.files[fk] = fileRecord{
  205. Usage: 1,
  206. File: f,
  207. }
  208. } else {
  209. br.Usage++
  210. m.files[fk] = br
  211. }
  212. // Update global view
  213. gk, ok := m.globalKey[n]
  214. switch {
  215. case ok && fk == gk:
  216. av := m.globalAvailability[n]
  217. av |= 1 << cid
  218. m.globalAvailability[n] = av
  219. case fk.newerThan(gk):
  220. if ok {
  221. f := m.files[gk]
  222. f.Global = false
  223. m.files[gk] = f
  224. }
  225. f := m.files[fk]
  226. f.Global = true
  227. m.files[fk] = f
  228. m.globalKey[n] = fk
  229. m.globalAvailability[n] = 1 << cid
  230. }
  231. }
  232. }
  233. func (m *Set) replace(cid uint, fs []scanner.File) {
  234. // Decrement usage for all files belonging to this remote, and remove
  235. // those that are no longer needed.
  236. for _, fk := range m.remoteKey[cid] {
  237. br, ok := m.files[fk]
  238. switch {
  239. case ok && br.Usage == 1:
  240. delete(m.files, fk)
  241. case ok && br.Usage > 1:
  242. br.Usage--
  243. m.files[fk] = br
  244. }
  245. }
  246. // Clear existing remote remoteKey
  247. m.remoteKey[cid] = make(map[string]key)
  248. // Recalculate global based on all remaining remoteKey
  249. for n := range m.globalKey {
  250. var nk key // newest key
  251. var na bitset // newest availability
  252. for i, rem := range m.remoteKey {
  253. if rk, ok := rem[n]; ok {
  254. switch {
  255. case rk == nk:
  256. na |= 1 << uint(i)
  257. case rk.newerThan(nk):
  258. nk = rk
  259. na = 1 << uint(i)
  260. }
  261. }
  262. }
  263. if na != 0 {
  264. // Someone had the file
  265. m.globalKey[n] = nk
  266. m.globalAvailability[n] = na
  267. } else {
  268. // Noone had the file
  269. delete(m.globalKey, n)
  270. delete(m.globalAvailability, n)
  271. }
  272. }
  273. // Add new remote remoteKey to the mix
  274. m.update(cid, fs)
  275. }