lib/model: Refactor {ro,rw}folder serve loop into just folder (#4939)
The actual pull method (which is really the only thing that differs between them) is now an interface member which gets overridden by the subclass. "Subclass?!" Well, this is dynamic dispatch with overriding, I guess.
This commit is contained in:
@@ -39,6 +39,12 @@ type folder struct {
|
||||
restartWatchChan chan struct{}
|
||||
watchErr error
|
||||
watchErrMut sync.Mutex
|
||||
|
||||
puller puller
|
||||
}
|
||||
|
||||
type puller interface {
|
||||
pull() bool // true when successfull and should not be retried
|
||||
}
|
||||
|
||||
func newFolder(model *Model, cfg config.FolderConfiguration) folder {
|
||||
@@ -64,6 +70,89 @@ func newFolder(model *Model, cfg config.FolderConfiguration) folder {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *folder) Serve() {
|
||||
l.Debugln(f, "starting")
|
||||
defer l.Debugln(f, "exiting")
|
||||
|
||||
defer func() {
|
||||
f.scan.timer.Stop()
|
||||
f.setState(FolderIdle)
|
||||
}()
|
||||
|
||||
pause := f.basePause()
|
||||
pullFailTimer := time.NewTimer(0)
|
||||
<-pullFailTimer.C
|
||||
|
||||
if f.FSWatcherEnabled && f.CheckHealth() == nil {
|
||||
f.startWatch()
|
||||
}
|
||||
|
||||
initialCompleted := f.initialScanFinished
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-f.ctx.Done():
|
||||
return
|
||||
|
||||
case <-f.pullScheduled:
|
||||
pullFailTimer.Stop()
|
||||
select {
|
||||
case <-pullFailTimer.C:
|
||||
default:
|
||||
}
|
||||
|
||||
if !f.puller.pull() {
|
||||
// Pulling failed, try again later.
|
||||
pullFailTimer.Reset(pause)
|
||||
}
|
||||
|
||||
case <-pullFailTimer.C:
|
||||
if f.puller.pull() {
|
||||
// We're good. Don't schedule another fail pull and reset
|
||||
// the pause interval.
|
||||
pause = f.basePause()
|
||||
continue
|
||||
}
|
||||
|
||||
// Pulling failed, try again later.
|
||||
l.Infof("Folder %v isn't making sync progress - retrying in %v.", f.Description(), pause)
|
||||
pullFailTimer.Reset(pause)
|
||||
// Back off from retrying to pull with an upper limit.
|
||||
if pause < 60*f.basePause() {
|
||||
pause *= 2
|
||||
}
|
||||
|
||||
case <-initialCompleted:
|
||||
// Initial scan has completed, we should do a pull
|
||||
initialCompleted = nil // never hit this case again
|
||||
if !f.puller.pull() {
|
||||
// Pulling failed, try again later.
|
||||
pullFailTimer.Reset(pause)
|
||||
}
|
||||
|
||||
// The reason for running the scanner from within the puller is that
|
||||
// this is the easiest way to make sure we are not doing both at the
|
||||
// same time.
|
||||
case <-f.scan.timer.C:
|
||||
l.Debugln(f, "Scanning subdirectories")
|
||||
f.scanTimerFired()
|
||||
|
||||
case req := <-f.scan.now:
|
||||
req.err <- f.scanSubdirs(req.subdirs)
|
||||
|
||||
case next := <-f.scan.delay:
|
||||
f.scan.timer.Reset(next)
|
||||
|
||||
case fsEvents := <-f.watchChan:
|
||||
l.Debugln(f, "filesystem notification rescan")
|
||||
f.scanSubdirs(fsEvents)
|
||||
|
||||
case <-f.restartWatchChan:
|
||||
f.restartWatch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *folder) BringToFront(string) {}
|
||||
|
||||
func (f *folder) DelayScan(next time.Duration) {
|
||||
@@ -258,3 +347,10 @@ func (f *folder) setError(err error) {
|
||||
|
||||
f.stateTracker.setError(err)
|
||||
}
|
||||
|
||||
func (f *folder) basePause() time.Duration {
|
||||
if f.PullerPauseS == 0 {
|
||||
return defaultPullerPause
|
||||
}
|
||||
return time.Duration(f.PullerPauseS) * time.Second
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user