Browse Source

lib/model: Don't reset db while folder is running (fixes #7935) (#7936)

Simon Frei 4 years ago
parent
commit
721cd740d8
3 changed files with 56 additions and 8 deletions
  1. 8 2
      lib/api/api.go
  2. 39 4
      lib/model/mocks/model.go
  3. 9 2
      lib/model/model.go

+ 8 - 2
lib/api/api.go

@@ -1016,12 +1016,18 @@ func (s *service) postSystemReset(w http.ResponseWriter, r *http.Request) {
 	if len(folder) == 0 {
 		// Reset all folders.
 		for folder := range s.cfg.Folders() {
-			s.model.ResetFolder(folder)
+			if err := s.model.ResetFolder(folder); err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
 		}
 		s.flushResponse(`{"ok": "resetting database"}`, w)
 	} else {
 		// Reset a specific folder, assuming it's supposed to exist.
-		s.model.ResetFolder(folder)
+		if err := s.model.ResetFolder(folder); err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 		s.flushResponse(`{"ok": "resetting folder `+folder+`"}`, w)
 	}
 

+ 39 - 4
lib/model/mocks/model.go

@@ -468,11 +468,17 @@ type Model struct {
 		result1 protocol.RequestResponse
 		result2 error
 	}
-	ResetFolderStub        func(string)
+	ResetFolderStub        func(string) error
 	resetFolderMutex       sync.RWMutex
 	resetFolderArgsForCall []struct {
 		arg1 string
 	}
+	resetFolderReturns struct {
+		result1 error
+	}
+	resetFolderReturnsOnCall map[int]struct {
+		result1 error
+	}
 	RestoreFolderVersionsStub        func(string, map[string]time.Time) (map[string]error, error)
 	restoreFolderVersionsMutex       sync.RWMutex
 	restoreFolderVersionsArgsForCall []struct {
@@ -2737,17 +2743,23 @@ func (fake *Model) RequestReturnsOnCall(i int, result1 protocol.RequestResponse,
 	}{result1, result2}
 }
 
-func (fake *Model) ResetFolder(arg1 string) {
+func (fake *Model) ResetFolder(arg1 string) error {
 	fake.resetFolderMutex.Lock()
+	ret, specificReturn := fake.resetFolderReturnsOnCall[len(fake.resetFolderArgsForCall)]
 	fake.resetFolderArgsForCall = append(fake.resetFolderArgsForCall, struct {
 		arg1 string
 	}{arg1})
 	stub := fake.ResetFolderStub
+	fakeReturns := fake.resetFolderReturns
 	fake.recordInvocation("ResetFolder", []interface{}{arg1})
 	fake.resetFolderMutex.Unlock()
 	if stub != nil {
-		fake.ResetFolderStub(arg1)
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
 	}
+	return fakeReturns.result1
 }
 
 func (fake *Model) ResetFolderCallCount() int {
@@ -2756,7 +2768,7 @@ func (fake *Model) ResetFolderCallCount() int {
 	return len(fake.resetFolderArgsForCall)
 }
 
-func (fake *Model) ResetFolderCalls(stub func(string)) {
+func (fake *Model) ResetFolderCalls(stub func(string) error) {
 	fake.resetFolderMutex.Lock()
 	defer fake.resetFolderMutex.Unlock()
 	fake.ResetFolderStub = stub
@@ -2769,6 +2781,29 @@ func (fake *Model) ResetFolderArgsForCall(i int) string {
 	return argsForCall.arg1
 }
 
+func (fake *Model) ResetFolderReturns(result1 error) {
+	fake.resetFolderMutex.Lock()
+	defer fake.resetFolderMutex.Unlock()
+	fake.ResetFolderStub = nil
+	fake.resetFolderReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ResetFolderReturnsOnCall(i int, result1 error) {
+	fake.resetFolderMutex.Lock()
+	defer fake.resetFolderMutex.Unlock()
+	fake.ResetFolderStub = nil
+	if fake.resetFolderReturnsOnCall == nil {
+		fake.resetFolderReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.resetFolderReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
 func (fake *Model) RestoreFolderVersions(arg1 string, arg2 map[string]time.Time) (map[string]error, error) {
 	fake.restoreFolderVersionsMutex.Lock()
 	ret, specificReturn := fake.restoreFolderVersionsReturnsOnCall[len(fake.restoreFolderVersionsArgsForCall)]

+ 9 - 2
lib/model/model.go

@@ -72,7 +72,7 @@ type Model interface {
 
 	connections.Model
 
-	ResetFolder(folder string)
+	ResetFolder(folder string) error
 	DelayScan(folder string, next time.Duration)
 	ScanFolder(folder string) error
 	ScanFolders() map[string]error
@@ -2764,9 +2764,16 @@ func (m *model) BringToFront(folder, file string) {
 	}
 }
 
-func (m *model) ResetFolder(folder string) {
+func (m *model) ResetFolder(folder string) error {
+	m.fmut.RLock()
+	defer m.fmut.RUnlock()
+	_, ok := m.folderRunners[folder]
+	if ok {
+		return errors.New("folder must be paused when resetting")
+	}
 	l.Infof("Cleaning metadata for reset folder %q", folder)
 	db.DropFolder(m.db, folder)
+	return nil
 }
 
 func (m *model) String() string {