rofolder.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright (C) 2014 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 model
  7. import (
  8. "fmt"
  9. "github.com/syncthing/syncthing/lib/config"
  10. "github.com/syncthing/syncthing/lib/db"
  11. "github.com/syncthing/syncthing/lib/fs"
  12. "github.com/syncthing/syncthing/lib/protocol"
  13. "github.com/syncthing/syncthing/lib/versioner"
  14. )
  15. func init() {
  16. folderFactories[config.FolderTypeSendOnly] = newSendOnlyFolder
  17. }
  18. type sendOnlyFolder struct {
  19. folder
  20. }
  21. func newSendOnlyFolder(model *Model, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem) service {
  22. return &sendOnlyFolder{folder: newFolder(model, cfg)}
  23. }
  24. func (f *sendOnlyFolder) Serve() {
  25. l.Debugln(f, "starting")
  26. defer l.Debugln(f, "exiting")
  27. defer func() {
  28. f.scan.timer.Stop()
  29. }()
  30. if f.FSWatcherEnabled && f.CheckHealth() == nil {
  31. f.startWatch()
  32. }
  33. for {
  34. select {
  35. case <-f.ctx.Done():
  36. return
  37. case <-f.pullScheduled:
  38. f.pull()
  39. case <-f.restartWatchChan:
  40. f.restartWatch()
  41. case <-f.scan.timer.C:
  42. l.Debugln(f, "Scanning subdirectories")
  43. f.scanTimerFired()
  44. case req := <-f.scan.now:
  45. req.err <- f.scanSubdirs(req.subdirs)
  46. case next := <-f.scan.delay:
  47. f.scan.timer.Reset(next)
  48. case fsEvents := <-f.watchChan:
  49. l.Debugln(f, "filesystem notification rescan")
  50. f.scanSubdirs(fsEvents)
  51. }
  52. }
  53. }
  54. func (f *sendOnlyFolder) String() string {
  55. return fmt.Sprintf("sendOnlyFolder/%s@%p", f.folderID, f)
  56. }
  57. func (f *sendOnlyFolder) PullErrors() []FileError {
  58. return nil
  59. }
  60. // pull checks need for files that only differ by metadata (no changes on disk)
  61. func (f *sendOnlyFolder) pull() {
  62. select {
  63. case <-f.initialScanFinished:
  64. default:
  65. // Once the initial scan finished, a pull will be scheduled
  66. return
  67. }
  68. f.model.fmut.RLock()
  69. folderFiles := f.model.folderFiles[f.folderID]
  70. ignores := f.model.folderIgnores[f.folderID]
  71. f.model.fmut.RUnlock()
  72. batch := make([]protocol.FileInfo, 0, maxBatchSizeFiles)
  73. batchSizeBytes := 0
  74. folderFiles.WithNeed(protocol.LocalDeviceID, func(intf db.FileIntf) bool {
  75. if len(batch) == maxBatchSizeFiles || batchSizeBytes > maxBatchSizeBytes {
  76. f.model.updateLocalsFromPulling(f.folderID, batch)
  77. batch = batch[:0]
  78. batchSizeBytes = 0
  79. }
  80. if ignores.ShouldIgnore(intf.FileName()) {
  81. file := intf.(protocol.FileInfo)
  82. file.Invalidate(f.shortID)
  83. batch = append(batch, file)
  84. batchSizeBytes += file.ProtoSize()
  85. l.Debugln(f, "Handling ignored file", file)
  86. return true
  87. }
  88. curFile, ok := f.model.CurrentFolderFile(f.folderID, intf.FileName())
  89. if !ok {
  90. if intf.IsDeleted() {
  91. panic("Should never get a deleted file as needed when we don't have it")
  92. }
  93. return true
  94. }
  95. file := intf.(protocol.FileInfo)
  96. if !file.IsEquivalent(curFile, f.IgnorePerms, false) {
  97. return true
  98. }
  99. file.Version = file.Version.Merge(curFile.Version)
  100. batch = append(batch, file)
  101. batchSizeBytes += file.ProtoSize()
  102. l.Debugln(f, "Merging versions of identical file", file)
  103. return true
  104. })
  105. if len(batch) > 0 {
  106. f.model.updateLocalsFromPulling(f.folderID, batch)
  107. }
  108. }