all: Add filesystem notification support
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3986
This commit is contained in:
committed by
Audrius Butkevicius
parent
c704ba9ef9
commit
f98c21b68e
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user