lib/model: Do Revert/Override synchronously (#6460)

This commit is contained in:
Simon Frei 2020-03-27 13:05:09 +01:00 committed by GitHub
parent c7cf3ef899
commit 79a758be3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 13 deletions

View File

@ -50,7 +50,6 @@ type folder struct {
scanInterval time.Duration scanInterval time.Duration
scanTimer *time.Timer scanTimer *time.Timer
scanNow chan rescanRequest
scanDelay chan time.Duration scanDelay chan time.Duration
initialScanFinished chan struct{} initialScanFinished chan struct{}
scanErrors []FileError scanErrors []FileError
@ -58,6 +57,8 @@ type folder struct {
pullScheduled chan struct{} pullScheduled chan struct{}
doInSyncChan chan syncRequest
watchCancel context.CancelFunc watchCancel context.CancelFunc
watchChan chan []string watchChan chan []string
restartWatchChan chan struct{} restartWatchChan chan struct{}
@ -67,8 +68,8 @@ type folder struct {
puller puller puller puller
} }
type rescanRequest struct { type syncRequest struct {
subdirs []string fn func() error
err chan error err chan error
} }
@ -90,13 +91,14 @@ func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg conf
scanInterval: time.Duration(cfg.RescanIntervalS) * time.Second, scanInterval: time.Duration(cfg.RescanIntervalS) * time.Second,
scanTimer: time.NewTimer(time.Millisecond), // The first scan should be done immediately. scanTimer: time.NewTimer(time.Millisecond), // The first scan should be done immediately.
scanNow: make(chan rescanRequest),
scanDelay: make(chan time.Duration), scanDelay: make(chan time.Duration),
initialScanFinished: make(chan struct{}), initialScanFinished: make(chan struct{}),
scanErrorsMut: sync.NewMutex(), scanErrorsMut: sync.NewMutex(),
pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes. pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes.
doInSyncChan: make(chan syncRequest),
watchCancel: func() {}, watchCancel: func() {},
restartWatchChan: make(chan struct{}, 1), restartWatchChan: make(chan struct{}, 1),
watchMut: sync.NewMutex(), watchMut: sync.NewMutex(),
@ -172,9 +174,9 @@ func (f *folder) serve(ctx context.Context) {
l.Debugln(f, "Scanning due to timer") l.Debugln(f, "Scanning due to timer")
f.scanTimerFired() f.scanTimerFired()
case req := <-f.scanNow: case req := <-f.doInSyncChan:
l.Debugln(f, "Scanning due to request") l.Debugln(f, "Running something due to request")
req.err <- f.scanSubdirs(req.subdirs) req.err <- req.fn()
case next := <-f.scanDelay: case next := <-f.scanDelay:
l.Debugln(f, "Delaying scan") l.Debugln(f, "Delaying scan")
@ -224,13 +226,19 @@ func (f *folder) Jobs(_, _ int) ([]string, []string, int) {
func (f *folder) Scan(subdirs []string) error { func (f *folder) Scan(subdirs []string) error {
<-f.initialScanFinished <-f.initialScanFinished
req := rescanRequest{ return f.doInSync(func() error { return f.scanSubdirs(subdirs) })
subdirs: subdirs, }
err: make(chan error),
// doInSync allows to run functions synchronously in folder.serve from exported,
// asynchronously called methods.
func (f *folder) doInSync(fn func() error) error {
req := syncRequest{
fn: fn,
err: make(chan error, 1),
} }
select { select {
case f.scanNow <- req: case f.doInSyncChan <- req:
return <-req.err return <-req.err
case <-f.ctx.Done(): case <-f.ctx.Done():
return f.ctx.Err() return f.ctx.Err()

View File

@ -64,6 +64,10 @@ func newReceiveOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matche
} }
func (f *receiveOnlyFolder) Revert() { func (f *receiveOnlyFolder) Revert() {
f.doInSync(func() error { f.revert(); return nil })
}
func (f *receiveOnlyFolder) revert() {
l.Infof("Reverting folder %v", f.Description) l.Infof("Reverting folder %v", f.Description)
f.setState(FolderScanning) f.setState(FolderScanning)

View File

@ -97,9 +97,15 @@ func (f *sendOnlyFolder) pull() bool {
} }
func (f *sendOnlyFolder) Override() { func (f *sendOnlyFolder) Override() {
f.doInSync(func() error { f.override(); return nil })
}
func (f *sendOnlyFolder) override() {
l.Infof("Overriding global state on folder %v", f.Description) l.Infof("Overriding global state on folder %v", f.Description)
f.setState(FolderScanning) f.setState(FolderScanning)
defer f.setState(FolderIdle)
batch := make([]protocol.FileInfo, 0, maxBatchSizeFiles) batch := make([]protocol.FileInfo, 0, maxBatchSizeFiles)
batchSizeBytes := 0 batchSizeBytes := 0
snap := f.fset.Snapshot() snap := f.fset.Snapshot()
@ -134,5 +140,4 @@ func (f *sendOnlyFolder) Override() {
if len(batch) > 0 { if len(batch) > 0 {
f.updateLocalsFromScanning(batch) f.updateLocalsFromScanning(batch)
} }
f.setState(FolderIdle)
} }