Browse Source

Perform initial scan asynchronously (fixes #509, fixes #464)

Jakob Borg 11 years ago
parent
commit
2091e12e82
4 changed files with 18 additions and 48 deletions
  1. 0 7
      cmd/syncthing/main.go
  2. 6 25
      internal/model/model.go
  3. 12 1
      internal/model/puller.go
  4. 0 15
      internal/scanner/walk.go

+ 0 - 7
cmd/syncthing/main.go

@@ -522,13 +522,6 @@ nextFolder:
 		}
 	}
 
-	// Walk the folder and update the local model before establishing any
-	// connections to other devices.
-
-	m.CleanFolders()
-	l.Infoln("Performing initial folder scan")
-	m.ScanFolders()
-
 	// Remove all .idx* files that don't belong to an active folder.
 
 	validIndexes := make(map[string]bool)

+ 6 - 25
internal/model/model.go

@@ -171,10 +171,9 @@ func (m *Model) StartFolderRW(folder string) {
 // pull in any external changes.
 func (m *Model) StartFolderRO(folder string) {
 	intv := time.Duration(m.folderCfgs[folder].RescanIntervalS) * time.Second
+	initialScanCompleted := false
 	go func() {
 		for {
-			time.Sleep(intv)
-
 			if debug {
 				l.Debugln(m, "rescan", folder)
 			}
@@ -185,6 +184,11 @@ func (m *Model) StartFolderRO(folder string) {
 				return
 			}
 			m.setState(folder, FolderIdle)
+			if !initialScanCompleted {
+				l.Infoln("Completed initial scan (ro) of folder", folder)
+				initialScanCompleted = true
+			}
+			time.Sleep(intv)
 		}
 	}()
 }
@@ -959,29 +963,6 @@ func (m *Model) ScanFolders() {
 	wg.Wait()
 }
 
-func (m *Model) CleanFolders() {
-	m.fmut.RLock()
-	var dirs = make([]string, 0, len(m.folderCfgs))
-	for _, cfg := range m.folderCfgs {
-		dirs = append(dirs, cfg.Path)
-	}
-	m.fmut.RUnlock()
-
-	var wg sync.WaitGroup
-	wg.Add(len(dirs))
-	for _, dir := range dirs {
-		w := &scanner.Walker{
-			Dir:       dir,
-			TempNamer: defTempNamer,
-		}
-		go func() {
-			w.CleanTempFiles()
-			wg.Done()
-		}()
-	}
-	wg.Wait()
-}
-
 func (m *Model) ScanFolder(folder string) error {
 	return m.ScanFolderSub(folder, "")
 }

+ 12 - 1
internal/model/puller.go

@@ -70,7 +70,7 @@ func (p *Puller) Serve() {
 	p.stop = make(chan struct{})
 
 	pullTimer := time.NewTimer(checkPullIntv)
-	scanTimer := time.NewTimer(p.scanIntv)
+	scanTimer := time.NewTimer(time.Millisecond) // The first scan should be done immediately.
 
 	defer func() {
 		pullTimer.Stop()
@@ -84,6 +84,9 @@ func (p *Puller) Serve() {
 	// Clean out old temporaries before we start pulling
 	p.clean()
 
+	// We don't start pulling files until a scan has been completed.
+	initialScanCompleted := false
+
 loop:
 	for {
 		select {
@@ -96,6 +99,10 @@ loop:
 		// repeatable benchmark of how long it takes to sync a change from
 		// device A to device B, so we have something to work against.
 		case <-pullTimer.C:
+			if !initialScanCompleted {
+				continue
+			}
+
 			// RemoteLocalVersion() is a fast call, doesn't touch the database.
 			curVer := p.model.RemoteLocalVersion(p.folder)
 			if curVer == prevVer {
@@ -163,6 +170,10 @@ loop:
 			}
 			p.model.setState(p.folder, FolderIdle)
 			scanTimer.Reset(p.scanIntv)
+			if !initialScanCompleted {
+				l.Infoln("Completed initial scan (rw) of folder", p.folder)
+				initialScanCompleted = true
+			}
 		}
 	}
 }

+ 0 - 15
internal/scanner/walk.go

@@ -73,11 +73,6 @@ func (w *Walker) Walk() (chan protocol.FileInfo, error) {
 	return hashedFiles, nil
 }
 
-// CleanTempFiles removes all files that match the temporary filename pattern.
-func (w *Walker) CleanTempFiles() {
-	filepath.Walk(w.Dir, w.cleanTempFile)
-}
-
 func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFunc {
 	return func(p string, info os.FileInfo, err error) error {
 		if err != nil {
@@ -181,16 +176,6 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun
 	}
 }
 
-func (w *Walker) cleanTempFile(path string, info os.FileInfo, err error) error {
-	if err != nil {
-		return err
-	}
-	if info.Mode()&os.ModeType == 0 && w.TempNamer.IsTemporary(path) {
-		os.Remove(path)
-	}
-	return nil
-}
-
 func checkDir(dir string) error {
 	if info, err := os.Lstat(dir); err != nil {
 		return err