diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js index 5b761feb2..32fca420e 100755 --- a/gui/default/syncthing/core/syncthingController.js +++ b/gui/default/syncthing/core/syncthingController.js @@ -1039,18 +1039,29 @@ angular.module('syncthing.core') // Do the same thing in case we only have zero byte files to sync. return 95; } - var pct = 100 * $scope.model[folder].inSyncBytes / $scope.model[folder].globalBytes; - return Math.floor(pct); + return progressIntegerPercentage($scope.model[folder].inSyncBytes, $scope.model[folder].globalBytes); }; $scope.scanPercentage = function (folder) { if (!$scope.scanProgress[folder]) { return undefined; } - var pct = 100 * $scope.scanProgress[folder].current / $scope.scanProgress[folder].total; - return Math.floor(pct); + return progressIntegerPercentage($scope.scanProgress[folder].current, $scope.scanProgress[folder].total); }; + function progressIntegerPercentage(current, total) { + // Even after whatever is being tracked (e.g. hashed or synced + // bytes) is completed, there's likely some more work to be done to + // fully finish the process (db updates, ...). Users apparently + // don't like seeing 100%, so give them 99% to indicate "about to be + // finished". + if (current === total) { + return 99; + } + var pct = 100 * current / total; + return Math.floor(pct); + } + $scope.scanRate = function (folder) { if (!$scope.scanProgress[folder]) { return 0; diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go index e971b909c..074d034aa 100644 --- a/lib/scanner/walk.go +++ b/lib/scanner/walk.go @@ -160,6 +160,11 @@ func (w *walker) walk(ctx context.Context) chan ScanResult { total += file.Size } + if len(filesToHash) == 0 { + close(finishedChan) + return + } + realToHashChan := make(chan protocol.FileInfo) done := make(chan struct{}) progress := newByteCounter() @@ -171,22 +176,27 @@ func (w *walker) walk(ctx context.Context) chan ScanResult { go func() { defer progress.Close() + emitProgressEvent := func() { + current := progress.Total() + rate := progress.Rate() + l.Debugf("%v: Walk %s %s current progress %d/%d at %.01f MiB/s (%d%%)", w, w.Folder, w.Subs, current, total, rate/1024/1024, current*100/total) + w.EventLogger.Log(events.FolderScanProgress, map[string]interface{}{ + "folder": w.Folder, + "current": current, + "total": total, + "rate": rate, // bytes per second + }) + } + for { select { case <-done: + emitProgressEvent() l.Debugln(w, "Walk progress done", w.Folder, w.Subs, w.Matcher) ticker.Stop() return case <-ticker.C: - current := progress.Total() - rate := progress.Rate() - l.Debugf("%v: Walk %s %s current progress %d/%d at %.01f MiB/s (%d%%)", w, w.Folder, w.Subs, current, total, rate/1024/1024, current*100/total) - w.EventLogger.Log(events.FolderScanProgress, map[string]interface{}{ - "folder": w.Folder, - "current": current, - "total": total, - "rate": rate, // bytes per second - }) + emitProgressEvent() case <-ctx.Done(): ticker.Stop() return