|
|
@@ -104,7 +104,8 @@ type sendReceiveFolder struct {
|
|
|
|
|
|
queue *jobQueue
|
|
|
|
|
|
- pullErrors map[string]string // path -> error string
|
|
|
+ pullErrors map[string]string // errors for most recent/current iteration
|
|
|
+ oldPullErrors map[string]string // errors from previous iterations for log filtering only
|
|
|
pullErrorsMut sync.Mutex
|
|
|
}
|
|
|
|
|
|
@@ -169,7 +170,7 @@ func (f *sendReceiveFolder) pull() bool {
|
|
|
}
|
|
|
}()
|
|
|
if err := f.ignores.Load(".stignore"); err != nil && !fs.IsNotExist(err) {
|
|
|
- err = fmt.Errorf("loading ignores: %v", err)
|
|
|
+ err = errors.Wrap(err, "loading ignores")
|
|
|
f.setError(err)
|
|
|
return false
|
|
|
}
|
|
|
@@ -210,9 +211,10 @@ func (f *sendReceiveFolder) pull() bool {
|
|
|
}
|
|
|
|
|
|
f.pullErrorsMut.Lock()
|
|
|
- hasPullErrs := len(f.pullErrors) > 0
|
|
|
+ pullErrNum := len(f.pullErrors)
|
|
|
f.pullErrorsMut.Unlock()
|
|
|
- if hasPullErrs {
|
|
|
+ if pullErrNum > 0 {
|
|
|
+ l.Infof("%v: Failed to sync %v items", f.Description(), pullErrNum)
|
|
|
f.evLogger.Log(events.FolderErrors, map[string]interface{}{
|
|
|
"folder": f.folderID,
|
|
|
"errors": f.Errors(),
|
|
|
@@ -227,6 +229,11 @@ func (f *sendReceiveFolder) pull() bool {
|
|
|
// might have failed). One puller iteration handles all files currently
|
|
|
// flagged as needed in the folder.
|
|
|
func (f *sendReceiveFolder) pullerIteration(scanChan chan<- string) int {
|
|
|
+ f.pullErrorsMut.Lock()
|
|
|
+ f.oldPullErrors = f.pullErrors
|
|
|
+ f.pullErrors = make(map[string]string)
|
|
|
+ f.pullErrorsMut.Unlock()
|
|
|
+
|
|
|
pullChan := make(chan pullBlockState)
|
|
|
copyChan := make(chan copyBlocksState)
|
|
|
finisherChan := make(chan *sharedPullerState)
|
|
|
@@ -269,9 +276,6 @@ func (f *sendReceiveFolder) pullerIteration(scanChan chan<- string) int {
|
|
|
doneWg.Done()
|
|
|
}()
|
|
|
|
|
|
- // Clear out all previous errors
|
|
|
- f.clearPullErrors()
|
|
|
-
|
|
|
changed, fileDeletions, dirDeletions, err := f.processNeeded(dbUpdateChan, copyChan, scanChan)
|
|
|
|
|
|
// Signal copy and puller routines that we are done with the in data for
|
|
|
@@ -294,6 +298,10 @@ func (f *sendReceiveFolder) pullerIteration(scanChan chan<- string) int {
|
|
|
close(dbUpdateChan)
|
|
|
updateWg.Wait()
|
|
|
|
|
|
+ f.pullErrorsMut.Lock()
|
|
|
+ f.oldPullErrors = nil
|
|
|
+ f.pullErrorsMut.Unlock()
|
|
|
+
|
|
|
return changed
|
|
|
}
|
|
|
|
|
|
@@ -1435,7 +1443,7 @@ func (f *sendReceiveFolder) pullBlock(state pullBlockState, out chan<- *sharedPu
|
|
|
select {
|
|
|
case <-f.ctx.Done():
|
|
|
state.fail(errors.Wrap(f.ctx.Err(), "folder stopped"))
|
|
|
- return
|
|
|
+ break
|
|
|
default:
|
|
|
}
|
|
|
|
|
|
@@ -1458,7 +1466,7 @@ func (f *sendReceiveFolder) pullBlock(state pullBlockState, out chan<- *sharedPu
|
|
|
// leastBusy can select another device when someone else asks.
|
|
|
activity.using(selected)
|
|
|
var buf []byte
|
|
|
- buf, lastError = f.model.requestGlobal(selected.ID, f.folderID, state.file.Name, state.block.Offset, int(state.block.Size), state.block.Hash, state.block.WeakHash, selected.FromTemporary)
|
|
|
+ buf, lastError = f.model.requestGlobal(f.ctx, selected.ID, f.folderID, state.file.Name, state.block.Offset, int(state.block.Size), state.block.Hash, state.block.WeakHash, selected.FromTemporary)
|
|
|
activity.done(selected)
|
|
|
if lastError != nil {
|
|
|
l.Debugln("request:", f.folderID, state.file.Name, state.block.Offset, state.block.Size, "returned error:", lastError)
|
|
|
@@ -1757,6 +1765,11 @@ func (f *sendReceiveFolder) moveForConflict(name, lastModBy string, scanChan cha
|
|
|
}
|
|
|
|
|
|
func (f *sendReceiveFolder) newPullError(path string, err error) {
|
|
|
+ if errors.Cause(err) == f.ctx.Err() {
|
|
|
+ // Error because the folder stopped - no point logging/tracking
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
f.pullErrorsMut.Lock()
|
|
|
defer f.pullErrorsMut.Unlock()
|
|
|
|
|
|
@@ -1767,18 +1780,19 @@ func (f *sendReceiveFolder) newPullError(path string, err error) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- l.Infof("Puller (folder %s, item %q): %v", f.Description(), path, err)
|
|
|
-
|
|
|
// Establish context to differentiate from errors while scanning.
|
|
|
// Use "syncing" as opposed to "pulling" as the latter might be used
|
|
|
// for errors occurring specificly in the puller routine.
|
|
|
- f.pullErrors[path] = fmt.Sprintln("syncing:", err)
|
|
|
-}
|
|
|
+ errStr := fmt.Sprintln("syncing:", err)
|
|
|
+ f.pullErrors[path] = errStr
|
|
|
|
|
|
-func (f *sendReceiveFolder) clearPullErrors() {
|
|
|
- f.pullErrorsMut.Lock()
|
|
|
- f.pullErrors = make(map[string]string)
|
|
|
- f.pullErrorsMut.Unlock()
|
|
|
+ if oldErr, ok := f.oldPullErrors[path]; ok && oldErr == errStr {
|
|
|
+ l.Debugf("Repeat error on puller (folder %s, item %q): %v", f.Description(), path, err)
|
|
|
+ delete(f.oldPullErrors, path) // Potential repeats are now caught by f.pullErrors itself
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ l.Infof("Puller (folder %s, item %q): %v", f.Description(), path, err)
|
|
|
}
|
|
|
|
|
|
func (f *sendReceiveFolder) Errors() []FileError {
|