mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 18:41:59 -07:00
Trigger pull check on remote index updates (fixes #1765)
Without this, when an index update comes in we only do a new pull if the remote `localVersion` was increased. But it may not be, because the index is sent alphabetically and the file with the highest local version may come first. In that case we'll never do a new pull when the rest of the index comes in, and we'll be stuck in idle but with lots of out of sync data.
This commit is contained in:
parent
03506db76c
commit
245bd1eb17
@ -50,6 +50,7 @@ type service interface {
|
|||||||
Jobs() ([]string, []string) // In progress, Queued
|
Jobs() ([]string, []string) // In progress, Queued
|
||||||
BringToFront(string)
|
BringToFront(string)
|
||||||
DelayScan(d time.Duration)
|
DelayScan(d time.Duration)
|
||||||
|
IndexUpdated() // Remote index was updated notification
|
||||||
|
|
||||||
setState(state folderState)
|
setState(state folderState)
|
||||||
setError(err error)
|
setError(err error)
|
||||||
@ -469,8 +470,15 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F
|
|||||||
|
|
||||||
m.fmut.RLock()
|
m.fmut.RLock()
|
||||||
files, ok := m.folderFiles[folder]
|
files, ok := m.folderFiles[folder]
|
||||||
|
runner := m.folderRunners[folder]
|
||||||
m.fmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
|
if runner != nil {
|
||||||
|
// Runner may legitimately not be set if this is the "cleanup" Index
|
||||||
|
// message at startup.
|
||||||
|
defer runner.IndexUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
l.Fatalf("Index for nonexistant folder %q", folder)
|
l.Fatalf("Index for nonexistant folder %q", folder)
|
||||||
}
|
}
|
||||||
@ -521,7 +529,8 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.fmut.RLock()
|
m.fmut.RLock()
|
||||||
files, ok := m.folderFiles[folder]
|
files := m.folderFiles[folder]
|
||||||
|
runner, ok := m.folderRunners[folder]
|
||||||
m.fmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -554,6 +563,8 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot
|
|||||||
"items": len(fs),
|
"items": len(fs),
|
||||||
"version": files.LocalVersion(deviceID),
|
"version": files.LocalVersion(deviceID),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
runner.IndexUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) folderSharedWith(folder string, deviceID protocol.DeviceID) bool {
|
func (m *Model) folderSharedWith(folder string, deviceID protocol.DeviceID) bool {
|
||||||
|
@ -104,6 +104,9 @@ func (s *roFolder) Stop() {
|
|||||||
close(s.stop)
|
close(s.stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *roFolder) IndexUpdated() {
|
||||||
|
}
|
||||||
|
|
||||||
func (s *roFolder) String() string {
|
func (s *roFolder) String() string {
|
||||||
return fmt.Sprintf("roFolder/%s@%p", s.folder, s)
|
return fmt.Sprintf("roFolder/%s@%p", s.folder, s)
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
pauseIntv = 60 * time.Second
|
pauseIntv = 60 * time.Second
|
||||||
nextPullIntv = 10 * time.Second
|
nextPullIntv = 10 * time.Second
|
||||||
checkPullIntv = 1 * time.Second
|
shortPullIntv = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// A pullBlockState is passed to the puller routine for each block that needs
|
// A pullBlockState is passed to the puller routine for each block that needs
|
||||||
@ -71,12 +71,13 @@ type rwFolder struct {
|
|||||||
shortID uint64
|
shortID uint64
|
||||||
order config.PullOrder
|
order config.PullOrder
|
||||||
|
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
queue *jobQueue
|
queue *jobQueue
|
||||||
dbUpdates chan protocol.FileInfo
|
dbUpdates chan protocol.FileInfo
|
||||||
scanTimer *time.Timer
|
scanTimer *time.Timer
|
||||||
pullTimer *time.Timer
|
pullTimer *time.Timer
|
||||||
delayScan chan time.Duration
|
delayScan chan time.Duration
|
||||||
|
remoteIndex chan struct{} // An index update was received, we should re-evaluate needs
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFolder {
|
func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFolder {
|
||||||
@ -99,11 +100,12 @@ func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFo
|
|||||||
shortID: shortID,
|
shortID: shortID,
|
||||||
order: cfg.Order,
|
order: cfg.Order,
|
||||||
|
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
queue: newJobQueue(),
|
queue: newJobQueue(),
|
||||||
pullTimer: time.NewTimer(checkPullIntv),
|
pullTimer: time.NewTimer(shortPullIntv),
|
||||||
scanTimer: time.NewTimer(time.Millisecond), // The first scan should be done immediately.
|
scanTimer: time.NewTimer(time.Millisecond), // The first scan should be done immediately.
|
||||||
delayScan: make(chan time.Duration),
|
delayScan: make(chan time.Duration),
|
||||||
|
remoteIndex: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a notification if we're busy doing a pull when it comes.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,11 +151,13 @@ func (p *rwFolder) Serve() {
|
|||||||
case <-p.stop:
|
case <-p.stop:
|
||||||
return
|
return
|
||||||
|
|
||||||
// TODO: We could easily add a channel here for notifications from
|
case <-p.remoteIndex:
|
||||||
// Index(), so that we immediately start a pull when new index
|
prevVer = 0
|
||||||
// information is available. Before that though, I'd like to build a
|
p.pullTimer.Reset(shortPullIntv)
|
||||||
// repeatable benchmark of how long it takes to sync a change from
|
if debug {
|
||||||
// device A to device B, so we have something to work against.
|
l.Debugln(p, "remote index updated, rescheduling pull")
|
||||||
|
}
|
||||||
|
|
||||||
case <-p.pullTimer.C:
|
case <-p.pullTimer.C:
|
||||||
if !initialScanCompleted {
|
if !initialScanCompleted {
|
||||||
if debug {
|
if debug {
|
||||||
@ -183,7 +187,7 @@ func (p *rwFolder) Serve() {
|
|||||||
if debug {
|
if debug {
|
||||||
l.Debugln(p, "skip (curVer == prevVer)", prevVer)
|
l.Debugln(p, "skip (curVer == prevVer)", prevVer)
|
||||||
}
|
}
|
||||||
p.pullTimer.Reset(checkPullIntv)
|
p.pullTimer.Reset(nextPullIntv)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +286,17 @@ func (p *rwFolder) Stop() {
|
|||||||
close(p.stop)
|
close(p.stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *rwFolder) IndexUpdated() {
|
||||||
|
select {
|
||||||
|
case p.remoteIndex <- struct{}{}:
|
||||||
|
default:
|
||||||
|
// We might be busy doing a pull and thus not reading from this
|
||||||
|
// channel. The channel is 1-buffered, so one notification will be
|
||||||
|
// queued to ensure we recheck after the pull, but beyond that we must
|
||||||
|
// make sure to not block index receiving.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *rwFolder) String() string {
|
func (p *rwFolder) String() string {
|
||||||
return fmt.Sprintf("rwFolder/%s@%p", p.folder, p)
|
return fmt.Sprintf("rwFolder/%s@%p", p.folder, p)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user