lib/model: Move stale scan check info finisher (ref #4305, fix #3742)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4317
This commit is contained in:
Audrius Butkevicius 2017-08-22 06:42:09 +00:00 committed by Jakob Borg
parent e8ba6d4771
commit b8c249cddc
2 changed files with 36 additions and 25 deletions

View File

@ -1002,27 +1002,6 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
tempName := ignore.TempName(file.Name)
if hasCurFile && !curFile.IsDirectory() && !curFile.IsSymlink() {
// Check that the file on disk is what we expect it to be according to
// the database. If there's a mismatch here, there might be local
// changes that we don't know about yet and we should scan before
// touching the file. If we can't stat the file we'll just pull it.
if info, err := f.fs.Lstat(file.Name); err == nil {
if !info.ModTime().Equal(curFile.ModTime()) || info.Size() != curFile.Size {
l.Debugln("file modified but not rescanned; not pulling:", file.Name)
// Scan() is synchronous (i.e. blocks until the scan is
// completed and returns an error), but a scan can't happen
// while we're in the puller routine. Request the scan in the
// background and it'll be handled when the current pulling
// sweep is complete. As we do retries, we'll queue the scan
// for this file up to ten times, but the last nine of those
// scans will be cheap...
go f.Scan([]string{file.Name})
return
}
}
}
scanner.PopulateOffsets(file.Blocks)
var blocks []protocol.BlockInfo
@ -1101,7 +1080,8 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
available: reused,
availableUpdated: time.Now(),
ignorePerms: f.ignorePermissions(file),
version: curFile.Version,
hasCurFile: hasCurFile,
curFile: curFile,
mut: sync.NewRWMutex(),
sparse: !f.DisableSparseFiles,
created: time.Now(),
@ -1386,6 +1366,36 @@ func (f *sendReceiveFolder) performFinish(state *sharedPullerState) error {
// There is an old file or directory already in place. We need to
// handle that.
curMode := uint32(stat.Mode())
if runtime.GOOS == "windows" && osutil.IsWindowsExecutable(state.file.Name) {
curMode |= 0111
}
// Check that the file on disk is what we expect it to be according to
// the database. If there's a mismatch here, there might be local
// changes that we don't know about yet and we should scan before
// touching the file.
// There is also a case where we think the file should be there, but
// it was removed, which is a conflict, yet creations always wins when
// competing with a deletion, so no need to handle that specially.
switch {
// The file reappeared from nowhere, or mtime/size has changed, fallthrough -> rescan.
case !state.hasCurFile || !stat.ModTime().Equal(state.curFile.ModTime()) || stat.Size() != state.curFile.Size:
fallthrough
// Permissions have changed, means the file has changed, rescan.
case !f.ignorePermissions(state.curFile) && state.curFile.HasPermissionBits() && !scanner.PermsEqual(state.curFile.Permissions, curMode):
l.Debugln("file modified but not rescanned; not finishing:", state.curFile.Name)
// Scan() is synchronous (i.e. blocks until the scan is
// completed and returns an error), but a scan can't happen
// while we're in the puller routine. Request the scan in the
// background and it'll be handled when the current pulling
// sweep is complete. As we do retries, we'll queue the scan
// for this file up to ten times, but the last nine of those
// scans will be cheap...
go f.Scan([]string{state.curFile.Name})
return nil
}
switch {
case stat.IsDir() || stat.IsSymlink():
// It's a directory or a symlink. These are not versioned or
@ -1400,13 +1410,13 @@ func (f *sendReceiveFolder) performFinish(state *sharedPullerState) error {
return err
}
case f.inConflict(state.version, state.file.Version):
case f.inConflict(state.curFile.Version, state.file.Version):
// The new file has been changed in conflict with the existing one. We
// should file it away as a conflict instead of just removing or
// archiving. Also merge with the version vector we had, to indicate
// we have resolved the conflict.
state.file.Version = state.file.Version.Merge(state.version)
state.file.Version = state.file.Version.Merge(state.curFile.Version)
err = osutil.InWritableDir(func(name string) error {
return f.moveForConflict(name, state.file.ModifiedBy.String())
}, f.fs, state.file.Name)

View File

@ -27,7 +27,8 @@ type sharedPullerState struct {
realName string
reused int // Number of blocks reused from temporary file
ignorePerms bool
version protocol.Vector // The current (old) version
hasCurFile bool // Whether curFile is set
curFile protocol.FileInfo // The file as it exists now in our database
sparse bool
created time.Time