瀏覽代碼

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

Simon Frei 5 年之前
父節點
當前提交
79a758be3c
共有 3 個文件被更改,包括 30 次插入13 次删除
  1. 20 12
      lib/model/folder.go
  2. 4 0
      lib/model/folder_recvonly.go
  3. 6 1
      lib/model/folder_sendonly.go

+ 20 - 12
lib/model/folder.go

@@ -50,7 +50,6 @@ type folder struct {
 
 	scanInterval        time.Duration
 	scanTimer           *time.Timer
-	scanNow             chan rescanRequest
 	scanDelay           chan time.Duration
 	initialScanFinished chan struct{}
 	scanErrors          []FileError
@@ -58,6 +57,8 @@ type folder struct {
 
 	pullScheduled chan struct{}
 
+	doInSyncChan chan syncRequest
+
 	watchCancel      context.CancelFunc
 	watchChan        chan []string
 	restartWatchChan chan struct{}
@@ -67,9 +68,9 @@ type folder struct {
 	puller puller
 }
 
-type rescanRequest struct {
-	subdirs []string
-	err     chan error
+type syncRequest struct {
+	fn  func() error
+	err chan error
 }
 
 type puller interface {
@@ -90,13 +91,14 @@ func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg conf
 
 		scanInterval:        time.Duration(cfg.RescanIntervalS) * time.Second,
 		scanTimer:           time.NewTimer(time.Millisecond), // The first scan should be done immediately.
-		scanNow:             make(chan rescanRequest),
 		scanDelay:           make(chan time.Duration),
 		initialScanFinished: make(chan struct{}),
 		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.
 
+		doInSyncChan: make(chan syncRequest),
+
 		watchCancel:      func() {},
 		restartWatchChan: make(chan struct{}, 1),
 		watchMut:         sync.NewMutex(),
@@ -172,9 +174,9 @@ func (f *folder) serve(ctx context.Context) {
 			l.Debugln(f, "Scanning due to timer")
 			f.scanTimerFired()
 
-		case req := <-f.scanNow:
-			l.Debugln(f, "Scanning due to request")
-			req.err <- f.scanSubdirs(req.subdirs)
+		case req := <-f.doInSyncChan:
+			l.Debugln(f, "Running something due to request")
+			req.err <- req.fn()
 
 		case next := <-f.scanDelay:
 			l.Debugln(f, "Delaying scan")
@@ -224,13 +226,19 @@ func (f *folder) Jobs(_, _ int) ([]string, []string, int) {
 
 func (f *folder) Scan(subdirs []string) error {
 	<-f.initialScanFinished
-	req := rescanRequest{
-		subdirs: subdirs,
-		err:     make(chan error),
+	return f.doInSync(func() error { return f.scanSubdirs(subdirs) })
+}
+
+// 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 {
-	case f.scanNow <- req:
+	case f.doInSyncChan <- req:
 		return <-req.err
 	case <-f.ctx.Done():
 		return f.ctx.Err()

+ 4 - 0
lib/model/folder_recvonly.go

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

+ 6 - 1
lib/model/folder_sendonly.go

@@ -97,9 +97,15 @@ func (f *sendOnlyFolder) pull() bool {
 }
 
 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)
 
 	f.setState(FolderScanning)
+	defer f.setState(FolderIdle)
+
 	batch := make([]protocol.FileInfo, 0, maxBatchSizeFiles)
 	batchSizeBytes := 0
 	snap := f.fset.Snapshot()
@@ -134,5 +140,4 @@ func (f *sendOnlyFolder) Override() {
 	if len(batch) > 0 {
 		f.updateLocalsFromScanning(batch)
 	}
-	f.setState(FolderIdle)
 }