set.go 6.1 KB

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