From 9e0e04f4de17f3a5e0c0d3b08d3dfe6bd068e17c Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Mon, 11 Jun 2018 15:47:54 +0200 Subject: [PATCH] all: Fix FS watcher restarting and web UI indication (fixes #4923) (#4962) --- cmd/syncthing/summaryservice.go | 8 ++-- gui/default/assets/lang/lang-en.json | 2 + gui/default/index.html | 35 +++++++++++++++-- .../syncthing/core/syncthingController.js | 13 +++++++ lib/events/events.go | 5 +++ lib/model/folder.go | 39 +++++++++++++++---- 6 files changed, 87 insertions(+), 15 deletions(-) diff --git a/cmd/syncthing/summaryservice.go b/cmd/syncthing/summaryservice.go index 0c23f5f11..b8710456c 100644 --- a/cmd/syncthing/summaryservice.go +++ b/cmd/syncthing/summaryservice.go @@ -60,7 +60,7 @@ func (c *folderSummaryService) Stop() { // listenForUpdates subscribes to the event bus and makes note of folders that // need their data recalculated. func (c *folderSummaryService) listenForUpdates() { - sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged | events.RemoteDownloadProgress | events.DeviceConnected) + sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged | events.RemoteDownloadProgress | events.DeviceConnected | events.FolderWatchStateChanged) defer events.Default.Unsubscribe(sub) for { @@ -105,14 +105,14 @@ func (c *folderSummaryService) listenForUpdates() { // c.immediate must be nonblocking so that we can continue // handling events. + c.foldersMut.Lock() select { case c.immediate <- folder: - c.foldersMut.Lock() delete(c.folders, folder) - c.foldersMut.Unlock() - default: + c.folders[folder] = struct{}{} } + c.foldersMut.Unlock() } default: diff --git a/gui/default/assets/lang/lang-en.json b/gui/default/assets/lang/lang-en.json index 5746f03d3..04741fc68 100644 --- a/gui/default/assets/lang/lang-en.json +++ b/gui/default/assets/lang/lang-en.json @@ -109,6 +109,7 @@ "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.", "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.", "Filesystem Notifications": "Filesystem Notifications", + "Filesystem Watcher Errors": "Filesystem Watcher Errors", "Filter by date": "Filter by date", "Filter by name": "Filter by name", "Folder": "Folder", @@ -117,6 +118,7 @@ "Folder Path": "Folder Path", "Folder Type": "Folder Type", "Folders": "Folders", + "For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.", "Full Rescan Interval (s)": "Full Rescan Interval (s)", "GUI": "GUI", "GUI Authentication Password": "GUI Authentication Password", diff --git a/gui/default/index.html b/gui/default/index.html index aa6140d6e..3acedfa83 100644 --- a/gui/default/index.html +++ b/gui/default/index.html @@ -257,6 +257,33 @@ + + +
+
+
+
+

+
+ +
+ Filesystem Watcher Errors +

+
+
+

+ For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't. Support +

+ + + + +
{{folderLabel(id)}}{{err}}
+
+
+
+
+
@@ -378,11 +405,11 @@  {{folder.rescanIntervalS | duration}}   Disabled - +  {{folder.rescanIntervalS | duration}}   Enabled - +  {{folder.rescanIntervalS | duration}}   Failed to setup, retrying @@ -392,11 +419,11 @@  Disabled Disabled - +  Disabled Enabled - +  Disabled Failed to setup, retrying diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js index 69292f325..42793d228 100755 --- a/gui/default/syncthing/core/syncthingController.js +++ b/gui/default/syncthing/core/syncthingController.js @@ -1466,6 +1466,16 @@ angular.module('syncthing.core') $http.post(urlbase + '/system/error/clear'); }; + $scope.fsWatcherErrorMap = function () { + var errs = {} + $.each($scope.folders, function (id, cfg) { + if (cfg.fsWatcherEnabled && $scope.model[cfg.id] && $scope.model[id].watchError && !cfg.paused && $scope.folderStatus(cfg) !== 'stopped') { + errs[id] = $scope.model[id].watchError; + } + }); + return errs; + } + $scope.friendlyDevices = function (str) { for (var i = 0; i < $scope.devices.length; i++) { var cfg = $scope.devices[i]; @@ -2248,6 +2258,9 @@ angular.module('syncthing.core') }; $scope.sizeOf = function (dict) { + if (dict === undefined) { + return 0; + } return Object.keys(dict).length; }; diff --git a/lib/events/events.go b/lib/events/events.go index 8b3e8df88..63d9b59cf 100644 --- a/lib/events/events.go +++ b/lib/events/events.go @@ -44,6 +44,7 @@ const ( FolderScanProgress FolderPaused FolderResumed + FolderWatchStateChanged ListenAddressesChanged LoginAttempt @@ -110,6 +111,8 @@ func (t EventType) String() string { return "ListenAddressesChanged" case LoginAttempt: return "LoginAttempt" + case FolderWatchStateChanged: + return "FolderWatchStateChanged" default: return "Unknown" } @@ -187,6 +190,8 @@ func UnmarshalEventType(s string) EventType { return ListenAddressesChanged case "LoginAttempt": return LoginAttempt + case "FolderWatchStateChanged": + return FolderWatchStateChanged default: return 0 } diff --git a/lib/model/folder.go b/lib/model/folder.go index ef921a007..97f5c0713 100644 --- a/lib/model/folder.go +++ b/lib/model/folder.go @@ -15,6 +15,7 @@ import ( "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/db" + "github.com/syncthing/syncthing/lib/events" "github.com/syncthing/syncthing/lib/ignore" "github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/sync" @@ -76,13 +77,14 @@ func newFolder(model *Model, cfg config.FolderConfiguration) folder { scanNow: make(chan rescanRequest), scanDelay: make(chan time.Duration), initialScanFinished: make(chan struct{}), + stopped: make(chan struct{}), pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes. - watchCancel: func() {}, - watchErr: errWatchNotStarted, - watchErrMut: sync.NewMutex(), - stopped: make(chan struct{}), + watchCancel: func() {}, + restartWatchChan: make(chan struct{}, 1), + watchErr: errWatchNotStarted, + watchErrMut: sync.NewMutex(), } } @@ -295,8 +297,19 @@ func (f *folder) WatchError() error { func (f *folder) stopWatch() { f.watchCancel() f.watchErrMut.Lock() + prevErr := f.watchErr f.watchErr = errWatchNotStarted f.watchErrMut.Unlock() + if prevErr != errWatchNotStarted { + data := map[string]interface{}{ + "folder": f.ID, + "to": errWatchNotStarted.Error(), + } + if prevErr != nil { + data["from"] = prevErr.Error() + } + events.Default.Log(events.FolderWatchStateChanged, data) + } } // scheduleWatchRestart makes sure watching is restarted from the main for loop @@ -316,7 +329,7 @@ func (f *folder) scheduleWatchRestart() { func (f *folder) restartWatch() { f.stopWatch() f.startWatch() - f.Scan(nil) + f.scanSubdirs(nil) } // startWatch should only ever be called synchronously. If you want to use @@ -343,11 +356,23 @@ func (f *folder) startWatchAsync(ctx context.Context, ignores *ignore.Matcher) { prevErr := f.watchErr f.watchErr = err f.watchErrMut.Unlock() + if err != prevErr { + data := map[string]interface{}{ + "folder": f.ID, + } + if prevErr != nil { + data["from"] = prevErr.Error() + } + if err != nil { + data["to"] = err.Error() + } + events.Default.Log(events.FolderWatchStateChanged, data) + } if err != nil { if prevErr == errWatchNotStarted { - l.Warnf("Failed to start filesystem watcher for folder %s: %v", f.Description(), err) + l.Infof("Error while trying to start filesystem watcher for folder %s, trying again in 1min: %v", f.Description(), err) } else { - l.Debugf("Failed to start filesystem watcher for folder %s again: %v", f.Description(), err) + l.Debugf("Repeat error while trying to start filesystem watcher for folder %s, trying again in 1min: %v", f.Description(), err) } timer.Reset(time.Minute) continue