Browse Source

chore(model): delay starting a pull while there are incoming index updates (#10041)

This adds a simple delay to the process for starting the pull, by
default one second. In practice this means we're likely to wait for
initial index transfer, or multiple messages sent as part of a larger
change. This is better because we're more likely to have the whole
change for the purpose of handling renames etc, and also it's more
efficient to do one larger puller iteration instead of multiple while
also processing changes.

It does however introduce a certain amount of delay into the sync
process, so it can be tuned down or turned off entirely.
Jakob Borg 7 months ago
parent
commit
c9650fc7d5
4 changed files with 17 additions and 0 deletions
  1. 2 0
      lib/config/config_test.go
  2. 1 0
      lib/config/folderconfiguration.go
  3. 13 0
      lib/model/folder.go
  4. 1 0
      lib/model/testutils_test.go

+ 2 - 0
lib/config/config_test.go

@@ -108,6 +108,7 @@ func TestDefaultValues(t *testing.T) {
 				FSWatcherEnabled: true,
 				FSWatcherDelayS:  10,
 				IgnorePerms:      false,
+				PullerDelayS:     1,
 				AutoNormalize:    true,
 				MinDiskFree:      size,
 				Versioning: VersioningConfiguration{
@@ -184,6 +185,7 @@ func TestDeviceConfig(t *testing.T) {
 				FSWatcherDelayS:  10,
 				Copiers:          0,
 				Hashers:          0,
+				PullerDelayS:     1,
 				AutoNormalize:    true,
 				MinDiskFree:      Size{1, "%"},
 				MaxConflicts:     -1,

+ 1 - 0
lib/config/folderconfiguration.go

@@ -68,6 +68,7 @@ type FolderConfiguration struct {
 	IgnoreDelete            bool                        `json:"ignoreDelete" xml:"ignoreDelete"`
 	ScanProgressIntervalS   int                         `json:"scanProgressIntervalS" xml:"scanProgressIntervalS"`
 	PullerPauseS            int                         `json:"pullerPauseS" xml:"pullerPauseS"`
+	PullerDelayS            float64                     `json:"pullerDelayS" xml:"pullerDelayS" default:"1"`
 	MaxConflicts            int                         `json:"maxConflicts" xml:"maxConflicts" default:"10"`
 	DisableSparseFiles      bool                        `json:"disableSparseFiles" xml:"disableSparseFiles"`
 	DisableTempIndexes      bool                        `json:"disableTempIndexes" xml:"disableTempIndexes"`

+ 13 - 0
lib/model/folder.go

@@ -173,6 +173,8 @@ func (f *folder) Serve(ctx context.Context) error {
 	}
 
 	initialCompleted := f.initialScanFinished
+	pullTimer := time.NewTimer(0)
+	pullTimer.Stop()
 
 	for {
 		var err error
@@ -183,6 +185,17 @@ func (f *folder) Serve(ctx context.Context) error {
 			return nil
 
 		case <-f.pullScheduled:
+			if f.PullerDelayS > 0 {
+				// Wait for incoming updates to settle before doing the
+				// actual pull
+				f.setState(FolderSyncWaiting)
+				pullTimer.Reset(time.Duration(float64(time.Second) * f.PullerDelayS))
+			} else {
+				_, err = f.pull()
+			}
+
+		case <-pullTimer.C:
+			f.setState(FolderIdle)
 			_, err = f.pull()
 
 		case <-f.pullFailTimer.C:

+ 1 - 0
lib/model/testutils_test.go

@@ -103,6 +103,7 @@ func newDefaultCfgWrapper() (config.Wrapper, config.FolderConfiguration, context
 func newFolderConfig() config.FolderConfiguration {
 	cfg := newFolderConfiguration(defaultCfgWrapper, "default", "default", config.FilesystemTypeFake, rand.String(32)+"?content=true")
 	cfg.FSWatcherEnabled = false
+	cfg.PullerDelayS = 0
 	cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1})
 	return cfg
 }