all: Add filesystem notification support

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3986
This commit is contained in:
Michael Ploujnikov
2017-10-20 14:52:55 +00:00
committed by Audrius Butkevicius
parent c704ba9ef9
commit f98c21b68e
62 changed files with 6079 additions and 18 deletions

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/watchaggregator"
)
type folder struct {
@@ -22,6 +23,9 @@ type folder struct {
ctx context.Context
cancel context.CancelFunc
initialScanFinished chan struct{}
watchCancel context.CancelFunc
watchChan chan []string
ignoresUpdated chan struct{} // The ignores changed, we need to restart watcher
}
func newFolder(model *Model, cfg config.FolderConfiguration) folder {
@@ -92,3 +96,35 @@ func (f *folder) scanTimerFired() {
f.scan.Reschedule()
}
func (f *folder) startWatcher() {
ctx, cancel := context.WithCancel(f.ctx)
f.model.fmut.RLock()
ignores := f.model.folderIgnores[f.folderID]
f.model.fmut.RUnlock()
eventChan, err := f.Filesystem().Watch(".", ignores, ctx, f.IgnorePerms)
if err != nil {
l.Warnf("Failed to start filesystem watcher for folder %s: %v", f.Description(), err)
} else {
f.watchChan = make(chan []string)
f.watchCancel = cancel
watchaggregator.Aggregate(eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, ctx)
l.Infoln("Started filesystem watcher for folder", f.Description())
}
}
func (f *folder) restartWatcher() {
f.watchCancel()
f.startWatcher()
f.Scan(nil)
}
func (f *folder) IgnoresUpdated() {
select {
case f.ignoresUpdated <- struct{}{}:
default:
// We might be busy doing a pull and thus not reading from this
// channel. The channel is 1-buffered, so one notification will be
// queued to ensure we recheck after the pull.
}
}

View File

@@ -48,6 +48,7 @@ type service interface {
BringToFront(string)
DelayScan(d time.Duration)
IndexUpdated() // Remote index was updated notification
IgnoresUpdated() // ignore matcher was updated notification
Jobs() ([]string, []string) // In progress, Queued
Scan(subs []string) error
Serve()
@@ -260,6 +261,7 @@ func (m *Model) startFolderLocked(folder string) config.FolderType {
ffs.Hide(".stignore")
p := folderFactory(m, cfg, ver, ffs)
m.folderRunners[folder] = p
m.warnAboutOverwritingProtectedFiles(folder)
@@ -1858,7 +1860,7 @@ func (m *Model) internalScanFolderSubdirs(ctx context.Context, folder string, su
defer func() {
if ignores.Hash() != oldHash {
l.Debugln("Folder", folder, "ignore patterns changed; triggering puller")
runner.IndexUpdated()
runner.IgnoresUpdated()
}
}()

View File

@@ -34,11 +34,20 @@ func (f *sendOnlyFolder) Serve() {
f.scan.timer.Stop()
}()
if f.FSWatcherEnabled {
f.startWatcher()
}
for {
select {
case <-f.ctx.Done():
return
case <-f.ignoresUpdated:
if f.FSWatcherEnabled {
f.restartWatcher()
}
case <-f.scan.timer.C:
l.Debugln(f, "Scanning subdirectories")
f.scanTimerFired()
@@ -48,6 +57,10 @@ func (f *sendOnlyFolder) Serve() {
case next := <-f.scan.delay:
f.scan.timer.Reset(next)
case fsEvents := <-f.watchChan:
l.Debugln(f, "filesystem notification rescan")
f.scanSubdirs(fsEvents)
}
}
}

View File

@@ -164,6 +164,10 @@ func (f *sendReceiveFolder) Serve() {
var prevSec int64
var prevIgnoreHash string
if f.FSWatcherEnabled {
f.startWatcher()
}
for {
select {
case <-f.ctx.Done():
@@ -174,6 +178,12 @@ func (f *sendReceiveFolder) Serve() {
f.pullTimer.Reset(0)
l.Debugln(f, "remote index updated, rescheduling pull")
case <-f.ignoresUpdated:
if f.FSWatcherEnabled {
f.restartWatcher()
}
f.IndexUpdated()
case <-f.pullTimer.C:
select {
case <-f.initialScanFinished:
@@ -278,6 +288,10 @@ func (f *sendReceiveFolder) Serve() {
case next := <-f.scan.delay:
f.scan.timer.Reset(next)
case fsEvents := <-f.watchChan:
l.Debugln(f, "filesystem notification rescan")
f.scanSubdirs(fsEvents)
}
}
}