浏览代码

lib/api, lib/model: Avoid contention on filesystem for DB status call (ref #7270) (#7271)

This splits the ignore getting to two methods, one that loads from disk
(the old one) and one that just returns whatever is already loaded (the
new one). The folder summary service which is just interested in stats
now uses the latter method. This means that it, and API calls that call
it, does not get blocked by folder I/O.
Jakob Borg 4 年之前
父节点
当前提交
253049a4cc
共有 5 个文件被更改,包括 40 次插入12 次删除
  1. 1 1
      lib/api/api.go
  2. 5 1
      lib/api/mocked_model_test.go
  3. 1 1
      lib/model/folder_summary.go
  4. 28 4
      lib/model/model.go
  5. 5 5
      lib/model/model_test.go

+ 1 - 1
lib/api/api.go

@@ -1218,7 +1218,7 @@ func (s *service) getDBIgnores(w http.ResponseWriter, r *http.Request) {
 
 
 	folder := qs.Get("folder")
 	folder := qs.Get("folder")
 
 
-	lines, patterns, err := s.model.GetIgnores(folder)
+	lines, patterns, err := s.model.LoadIgnores(folder)
 	if err != nil && !ignore.IsParseError(err) {
 	if err != nil && !ignore.IsParseError(err) {
 		http.Error(w, err.Error(), 500)
 		http.Error(w, err.Error(), 500)
 		return
 		return

+ 5 - 1
lib/api/mocked_model_test.go

@@ -80,7 +80,11 @@ func (m *mockedModel) Availability(folder string, file protocol.FileInfo, block
 	return nil
 	return nil
 }
 }
 
 
-func (m *mockedModel) GetIgnores(folder string) ([]string, []string, error) {
+func (m *mockedModel) LoadIgnores(folder string) ([]string, []string, error) {
+	return nil, nil, nil
+}
+
+func (m *mockedModel) CurrentIgnores(folder string) ([]string, []string, error) {
 	return nil, nil, nil
 	return nil, nil, nil
 }
 }
 
 

+ 1 - 1
lib/model/folder_summary.go

@@ -142,7 +142,7 @@ func (c *folderSummaryService) Summary(folder string) (map[string]interface{}, e
 	res["version"] = ourSeq + remoteSeq  // legacy
 	res["version"] = ourSeq + remoteSeq  // legacy
 	res["sequence"] = ourSeq + remoteSeq // new name
 	res["sequence"] = ourSeq + remoteSeq // new name
 
 
-	ignorePatterns, _, _ := c.model.GetIgnores(folder)
+	ignorePatterns, _, _ := c.model.CurrentIgnores(folder)
 	res["ignorePatterns"] = false
 	res["ignorePatterns"] = false
 	for _, line := range ignorePatterns {
 	for _, line := range ignorePatterns {
 		if len(line) > 0 && !strings.HasPrefix(line, "//") {
 		if len(line) > 0 && !strings.HasPrefix(line, "//") {

+ 28 - 4
lib/model/model.go

@@ -83,7 +83,8 @@ type Model interface {
 	Override(folder string)
 	Override(folder string)
 	Revert(folder string)
 	Revert(folder string)
 	BringToFront(folder, file string)
 	BringToFront(folder, file string)
-	GetIgnores(folder string) ([]string, []string, error)
+	LoadIgnores(folder string) ([]string, []string, error)
+	CurrentIgnores(folder string) ([]string, []string, error)
 	SetIgnores(folder string, content []string) error
 	SetIgnores(folder string, content []string) error
 
 
 	GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
 	GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
@@ -648,7 +649,7 @@ func (m *model) UsageReportingStats(report *contract.Report, version int, previe
 		// Ignore stats
 		// Ignore stats
 		var seenPrefix [3]bool
 		var seenPrefix [3]bool
 		for folder := range m.cfg.Folders() {
 		for folder := range m.cfg.Folders() {
-			lines, _, err := m.GetIgnores(folder)
+			lines, _, err := m.CurrentIgnores(folder)
 			if err != nil {
 			if err != nil {
 				continue
 				continue
 			}
 			}
@@ -1971,7 +1972,9 @@ func (m *model) Connection(deviceID protocol.DeviceID) (protocol.Connection, boo
 	return cn, ok
 	return cn, ok
 }
 }
 
 
-func (m *model) GetIgnores(folder string) ([]string, []string, error) {
+// LoadIgnores loads or refreshes the ignore patterns from disk, if the
+// folder is healthy, and returns the refreshed lines and patterns.
+func (m *model) LoadIgnores(folder string) ([]string, []string, error) {
 	m.fmut.RLock()
 	m.fmut.RLock()
 	cfg, cfgOk := m.folderCfgs[folder]
 	cfg, cfgOk := m.folderCfgs[folder]
 	ignores, ignoresOk := m.folderIgnores[folder]
 	ignores, ignoresOk := m.folderIgnores[folder]
@@ -1990,7 +1993,7 @@ func (m *model) GetIgnores(folder string) ([]string, []string, error) {
 	}
 	}
 
 
 	if !ignoresOk {
 	if !ignoresOk {
-		ignores = ignore.New(fs.NewFilesystem(cfg.FilesystemType, cfg.Path))
+		ignores = ignore.New(cfg.Filesystem())
 	}
 	}
 
 
 	err := ignores.Load(".stignore")
 	err := ignores.Load(".stignore")
@@ -2004,6 +2007,27 @@ func (m *model) GetIgnores(folder string) ([]string, []string, error) {
 	return ignores.Lines(), ignores.Patterns(), err
 	return ignores.Lines(), ignores.Patterns(), err
 }
 }
 
 
+// CurrentIgnores returns the currently loaded set of ignore patterns,
+// whichever it may be. No attempt is made to load or refresh ignore
+// patterns from disk.
+func (m *model) CurrentIgnores(folder string) ([]string, []string, error) {
+	m.fmut.RLock()
+	_, cfgOk := m.folderCfgs[folder]
+	ignores, ignoresOk := m.folderIgnores[folder]
+	m.fmut.RUnlock()
+
+	if !cfgOk {
+		return nil, nil, fmt.Errorf("folder %s does not exist", folder)
+	}
+
+	if !ignoresOk {
+		// Empty ignore patterns
+		return []string{}, []string{}, nil
+	}
+
+	return ignores.Lines(), ignores.Patterns(), nil
+}
+
 func (m *model) SetIgnores(folder string, content []string) error {
 func (m *model) SetIgnores(folder string, content []string) error {
 	cfg, ok := m.cfg.Folder(folder)
 	cfg, ok := m.cfg.Folder(folder)
 	if !ok {
 	if !ok {

+ 5 - 5
lib/model/model_test.go

@@ -1405,7 +1405,7 @@ func changeIgnores(t *testing.T, m *testModel, expected []string) {
 		return true
 		return true
 	}
 	}
 
 
-	ignores, _, err := m.GetIgnores("default")
+	ignores, _, err := m.LoadIgnores("default")
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
@@ -1421,7 +1421,7 @@ func changeIgnores(t *testing.T, m *testModel, expected []string) {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
 
 
-	ignores2, _, err := m.GetIgnores("default")
+	ignores2, _, err := m.LoadIgnores("default")
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
@@ -1441,7 +1441,7 @@ func changeIgnores(t *testing.T, m *testModel, expected []string) {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
 
 
-	ignores, _, err = m.GetIgnores("default")
+	ignores, _, err = m.LoadIgnores("default")
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
@@ -1472,7 +1472,7 @@ func TestIgnores(t *testing.T) {
 
 
 	changeIgnores(t, m, expected)
 	changeIgnores(t, m, expected)
 
 
-	_, _, err := m.GetIgnores("doesnotexist")
+	_, _, err := m.LoadIgnores("doesnotexist")
 	if err == nil {
 	if err == nil {
 		t.Error("No error")
 		t.Error("No error")
 	}
 	}
@@ -1490,7 +1490,7 @@ func TestIgnores(t *testing.T) {
 	m.folderIgnores[fcfg.ID] = ignores
 	m.folderIgnores[fcfg.ID] = ignores
 	m.fmut.Unlock()
 	m.fmut.Unlock()
 
 
-	_, _, err = m.GetIgnores("fresh")
+	_, _, err = m.LoadIgnores("fresh")
 	if err == nil {
 	if err == nil {
 		t.Error("No error")
 		t.Error("No error")
 	}
 	}