Reimplement quick startup scan

This commit is contained in:
Jakob Borg 2014-03-16 08:14:55 +01:00
parent d2d32f26c7
commit 2df78a9313
5 changed files with 63 additions and 54 deletions

View File

@ -239,8 +239,9 @@ func main() {
IgnoreFile: ".stignore", IgnoreFile: ".stignore",
FollowSymlinks: cfg.Options.FollowSymlinks, FollowSymlinks: cfg.Options.FollowSymlinks,
BlockSize: BlockSize, BlockSize: BlockSize,
Suppressor: sup,
TempNamer: defTempNamer, TempNamer: defTempNamer,
Suppressor: sup,
CurrentFiler: m,
} }
updateLocalModel(m, w) updateLocalModel(m, w)

View File

@ -397,7 +397,7 @@ func (m *Model) Request(nodeID, repo, name string, offset int64, size int) ([]by
warnf("SECURITY (nonexistent file) REQ(in): %s: %q o=%d s=%d", nodeID, name, offset, size) warnf("SECURITY (nonexistent file) REQ(in): %s: %q o=%d s=%d", nodeID, name, offset, size)
return nil, ErrNoSuchFile return nil, ErrNoSuchFile
} }
if lf.Flags&protocol.FlagInvalid != 0 { if lf.Suppressed {
return nil, ErrInvalid return nil, ErrInvalid
} }
@ -480,6 +480,14 @@ func (m *Model) SeedLocal(fs []protocol.FileInfo) {
m.recomputeNeedForGlobal() m.recomputeNeedForGlobal()
} }
// Implements scanner.CurrentFiler
func (m *Model) CurrentFile(file string) scanner.File {
m.lmut.RLock()
f := m.local[file]
m.lmut.RUnlock()
return f
}
// ConnectedTo returns true if we are connected to the named node. // ConnectedTo returns true if we are connected to the named node.
func (m *Model) ConnectedTo(nodeID string) bool { func (m *Model) ConnectedTo(nodeID string) bool {
m.pmut.RLock() m.pmut.RLock()
@ -810,7 +818,7 @@ func (m *Model) recomputeNeedForFile(gf scanner.File, toAdd []addOrder, toDelete
m.lmut.RUnlock() m.lmut.RUnlock()
if !ok || gf.NewerThan(lf) { if !ok || gf.NewerThan(lf) {
if gf.Flags&protocol.FlagInvalid != 0 { if gf.Suppressed {
// Never attempt to sync invalid files // Never attempt to sync invalid files
return toAdd, toDelete return toAdd, toDelete
} }
@ -891,10 +899,11 @@ func fileFromFileInfo(f protocol.FileInfo) scanner.File {
return scanner.File{ return scanner.File{
Name: f.Name, Name: f.Name,
Size: offset, Size: offset,
Flags: f.Flags, Flags: f.Flags &^ protocol.FlagInvalid,
Modified: f.Modified, Modified: f.Modified,
Version: f.Version, Version: f.Version,
Blocks: blocks, Blocks: blocks,
Suppressed: f.Flags&protocol.FlagInvalid != 0,
} }
} }
@ -906,11 +915,15 @@ func fileInfoFromFile(f scanner.File) protocol.FileInfo {
Hash: b.Hash, Hash: b.Hash,
} }
} }
return protocol.FileInfo{ pf := protocol.FileInfo{
Name: f.Name, Name: f.Name,
Flags: f.Flags, Flags: f.Flags,
Modified: f.Modified, Modified: f.Modified,
Version: f.Version, Version: f.Version,
Blocks: blocks, Blocks: blocks,
} }
if f.Suppressed {
pf.Flags |= protocol.FlagInvalid
}
return pf
} }

View File

@ -26,7 +26,7 @@ const (
) )
const ( const (
FlagDeleted = 1 << 12 FlagDeleted uint32 = 1 << 12
FlagInvalid = 1 << 13 FlagInvalid = 1 << 13
) )

View File

@ -9,6 +9,7 @@ type File struct {
Version uint32 Version uint32
Size int64 Size int64
Blocks []Block Blocks []Block
Suppressed bool
} }
func (f File) String() string { func (f File) String() string {

View File

@ -9,8 +9,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"github.com/calmh/syncthing/protocol"
) )
type Walker struct { type Walker struct {
@ -25,10 +23,13 @@ type Walker struct {
IgnoreFile string IgnoreFile string
// If TempNamer is not nil, it is used to ignore tempory files when walking. // If TempNamer is not nil, it is used to ignore tempory files when walking.
TempNamer TempNamer TempNamer TempNamer
// If CurrentFiler is not nil, it is queried for the current file before rescanning.
CurrentFiler CurrentFiler
// If Suppressor is not nil, it is queried for supression of modified files. // If Suppressor is not nil, it is queried for supression of modified files.
// Suppressed files will be returned with empty metadata and the Suppressed flag set.
// Requires CurrentFiler to be set.
Suppressor Suppressor Suppressor Suppressor
previous map[string]File // file name -> last seen file state
suppressed map[string]bool // file name -> suppression status suppressed map[string]bool // file name -> suppression status
} }
@ -44,6 +45,11 @@ type Suppressor interface {
Suppress(name string, fi os.FileInfo) bool Suppress(name string, fi os.FileInfo) bool
} }
type CurrentFiler interface {
// CurrentFile returns the file as seen at last scan.
CurrentFile(name string) File
}
// Walk returns the list of files found in the local repository by scanning the // Walk returns the list of files found in the local repository by scanning the
// file system. Files are blockwise hashed. // file system. Files are blockwise hashed.
func (w *Walker) Walk() (files []File, ignore map[string][]string) { func (w *Walker) Walk() (files []File, ignore map[string][]string) {
@ -95,8 +101,7 @@ func (w *Walker) CleanTempFiles() {
} }
func (w *Walker) lazyInit() { func (w *Walker) lazyInit() {
if w.previous == nil { if w.suppressed == nil {
w.previous = make(map[string]File)
w.suppressed = make(map[string]bool) w.suppressed = make(map[string]bool)
} }
} }
@ -171,21 +176,13 @@ func (w *Walker) walkAndHashFiles(res *[]File, ign map[string][]string) filepath
} }
if info.Mode()&os.ModeType == 0 { if info.Mode()&os.ModeType == 0 {
modified := info.ModTime().Unix() if w.CurrentFiler != nil {
pf := w.previous[rn] cf := w.CurrentFiler.CurrentFile(rn)
if cf.Modified == info.ModTime().Unix() {
if pf.Modified == modified {
if nf := uint32(info.Mode()); nf != pf.Flags {
if debug { if debug {
dlog.Println("new flags:", rn)
}
pf.Flags = nf
pf.Version++
w.previous[rn] = pf
} else if debug {
dlog.Println("unchanged:", rn) dlog.Println("unchanged:", rn)
} }
*res = append(*res, pf) *res = append(*res, cf)
return nil return nil
} }
@ -197,15 +194,13 @@ func (w *Walker) walkAndHashFiles(res *[]File, ign map[string][]string) filepath
w.suppressed[rn] = true w.suppressed[rn] = true
log.Printf("INFO: Changes to %q are being temporarily suppressed because it changes too frequently.", p) log.Printf("INFO: Changes to %q are being temporarily suppressed because it changes too frequently.", p)
} }
f := pf cf.Suppressed = true
f.Flags = protocol.FlagInvalid *res = append(*res, cf)
f.Blocks = nil
*res = append(*res, f)
return nil
} else if w.suppressed[rn] { } else if w.suppressed[rn] {
log.Printf("INFO: Changes to %q are no longer suppressed.", p) log.Printf("INFO: Changes to %q are no longer suppressed.", p)
delete(w.suppressed, rn) delete(w.suppressed, rn)
} }
}
fd, err := os.Open(p) fd, err := os.Open(p)
if err != nil { if err != nil {
@ -232,10 +227,9 @@ func (w *Walker) walkAndHashFiles(res *[]File, ign map[string][]string) filepath
Name: rn, Name: rn,
Size: info.Size(), Size: info.Size(),
Flags: uint32(info.Mode()), Flags: uint32(info.Mode()),
Modified: modified, Modified: info.ModTime().Unix(),
Blocks: blocks, Blocks: blocks,
} }
w.previous[rn] = f
*res = append(*res, f) *res = append(*res, f)
} }