lib: Add util.Service as suture.Service template (fixes #5801) (#5806)

This commit is contained in:
Simon Frei
2019-07-09 11:40:30 +02:00
committed by GitHub
parent d0ab65a178
commit ba056578ec
21 changed files with 340 additions and 420 deletions

View File

@@ -28,6 +28,8 @@ import (
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/watchaggregator"
"github.com/thejerf/suture"
)
// scanLimiter limits the number of concurrent scans. A limit of zero means no limit.
@@ -36,6 +38,7 @@ var scanLimiter = newByteSemaphore(0)
var errWatchNotStarted = errors.New("not started")
type folder struct {
suture.Service
stateTracker
config.FolderConfiguration
*stats.FolderStatisticsReference
@@ -54,7 +57,6 @@ type folder struct {
scanNow chan rescanRequest
scanDelay chan time.Duration
initialScanFinished chan struct{}
stopped chan struct{}
scanErrors []FileError
scanErrorsMut sync.Mutex
@@ -98,7 +100,6 @@ func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg conf
scanNow: make(chan rescanRequest),
scanDelay: make(chan time.Duration),
initialScanFinished: make(chan struct{}),
stopped: make(chan struct{}),
scanErrorsMut: sync.NewMutex(),
pullScheduled: make(chan struct{}, 1), // This needs to be 1-buffered so that we queue a pull if we're busy when it comes.
@@ -109,7 +110,7 @@ func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg conf
}
}
func (f *folder) Serve() {
func (f *folder) serve(_ chan struct{}) {
atomic.AddInt32(&f.model.foldersRunning, 1)
defer atomic.AddInt32(&f.model.foldersRunning, -1)
@@ -119,7 +120,6 @@ func (f *folder) Serve() {
defer func() {
f.scanTimer.Stop()
f.setState(FolderIdle)
close(f.stopped)
}()
pause := f.basePause()
@@ -256,7 +256,7 @@ func (f *folder) Delay(next time.Duration) {
func (f *folder) Stop() {
f.cancel()
<-f.stopped
f.Service.Stop()
}
// CheckHealth checks the folder for common errors, updates the folder state

View File

@@ -12,6 +12,7 @@ import (
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/ignore"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/util"
"github.com/syncthing/syncthing/lib/versioner"
)
@@ -28,6 +29,7 @@ func newSendOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher,
folder: newFolder(model, fset, ignores, cfg),
}
f.folder.puller = f
f.folder.Service = util.AsService(f.serve)
return f
}

View File

@@ -28,6 +28,7 @@ import (
"github.com/syncthing/syncthing/lib/scanner"
"github.com/syncthing/syncthing/lib/sha256"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/syncthing/syncthing/lib/weakhash"
)
@@ -116,6 +117,7 @@ func newSendReceiveFolder(model *model, fset *db.FileSet, ignores *ignore.Matche
pullErrorsMut: sync.NewMutex(),
}
f.folder.puller = f
f.folder.Service = util.AsService(f.serve)
if f.Copiers == 0 {
f.Copiers = defaultCopiers

View File

@@ -11,11 +11,13 @@ import (
"strings"
"time"
"github.com/thejerf/suture"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/thejerf/suture"
"github.com/syncthing/syncthing/lib/util"
)
const minSummaryInterval = time.Minute
@@ -34,7 +36,6 @@ type folderSummaryService struct {
cfg config.Wrapper
model Model
id protocol.DeviceID
stop chan struct{}
immediate chan string
// For keeping track of folders to recalculate for
@@ -54,24 +55,18 @@ func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID)
cfg: cfg,
model: m,
id: id,
stop: make(chan struct{}),
immediate: make(chan string),
folders: make(map[string]struct{}),
foldersMut: sync.NewMutex(),
lastEventReqMut: sync.NewMutex(),
}
service.Add(serviceFunc(service.listenForUpdates))
service.Add(serviceFunc(service.calculateSummaries))
service.Add(util.AsService(service.listenForUpdates))
service.Add(util.AsService(service.calculateSummaries))
return service
}
func (c *folderSummaryService) Stop() {
c.Supervisor.Stop()
close(c.stop)
}
func (c *folderSummaryService) String() string {
return fmt.Sprintf("FolderSummaryService@%p", c)
}
@@ -148,7 +143,7 @@ func (c *folderSummaryService) OnEventRequest() {
// listenForUpdates subscribes to the event bus and makes note of folders that
// need their data recalculated.
func (c *folderSummaryService) listenForUpdates() {
func (c *folderSummaryService) listenForUpdates(stop chan struct{}) {
sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged | events.RemoteDownloadProgress | events.DeviceConnected | events.FolderWatchStateChanged | events.DownloadProgress)
defer events.Default.Unsubscribe(sub)
@@ -158,7 +153,7 @@ func (c *folderSummaryService) listenForUpdates() {
select {
case ev := <-sub.C():
c.processUpdate(ev)
case <-c.stop:
case <-stop:
return
}
}
@@ -237,7 +232,7 @@ func (c *folderSummaryService) processUpdate(ev events.Event) {
// calculateSummaries periodically recalculates folder summaries and
// completion percentage, and sends the results on the event bus.
func (c *folderSummaryService) calculateSummaries() {
func (c *folderSummaryService) calculateSummaries(stop chan struct{}) {
const pumpInterval = 2 * time.Second
pump := time.NewTimer(pumpInterval)
@@ -258,7 +253,7 @@ func (c *folderSummaryService) calculateSummaries() {
case folder := <-c.immediate:
c.sendSummary(folder)
case <-c.stop:
case <-stop:
return
}
}
@@ -319,10 +314,3 @@ func (c *folderSummaryService) sendSummary(folder string) {
events.Default.Log(events.FolderCompletion, comp)
}
}
// serviceFunc wraps a function to create a suture.Service without stop
// functionality.
type serviceFunc func()
func (f serviceFunc) Serve() { f() }
func (f serviceFunc) Stop() {}

View File

@@ -32,6 +32,7 @@ import (
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/util"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/thejerf/suture"
)
@@ -1169,19 +1170,19 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
}
}
// The token isn't tracked as the service stops when the connection
// terminates and is automatically removed from supervisor (by
// implementing suture.IsCompletable).
m.Add(&indexSender{
is := &indexSender{
conn: conn,
connClosed: closed,
folder: folder.ID,
fset: fs,
prevSequence: startSequence,
dropSymlinks: dropSymlinks,
stop: make(chan struct{}),
stopped: make(chan struct{}),
})
}
is.Service = util.AsService(is.serve)
// The token isn't tracked as the service stops when the connection
// terminates and is automatically removed from supervisor (by
// implementing suture.IsCompletable).
m.Add(is)
}
m.pmut.Lock()
@@ -1896,6 +1897,7 @@ func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
}
type indexSender struct {
suture.Service
conn protocol.Connection
folder string
dev string
@@ -1903,13 +1905,9 @@ type indexSender struct {
prevSequence int64
dropSymlinks bool
connClosed chan struct{}
stop chan struct{}
stopped chan struct{}
}
func (s *indexSender) Serve() {
defer close(s.stopped)
func (s *indexSender) serve(stop chan struct{}) {
var err error
l.Debugf("Starting indexSender for %s to %s at %s (slv=%d)", s.folder, s.dev, s.conn, s.prevSequence)
@@ -1930,7 +1928,7 @@ func (s *indexSender) Serve() {
for err == nil {
select {
case <-s.stop:
case <-stop:
return
case <-s.connClosed:
return
@@ -1943,7 +1941,7 @@ func (s *indexSender) Serve() {
// sending for.
if s.fset.Sequence(protocol.LocalDeviceID) <= s.prevSequence {
select {
case <-s.stop:
case <-stop:
return
case <-s.connClosed:
return
@@ -1963,11 +1961,6 @@ func (s *indexSender) Serve() {
}
}
func (s *indexSender) Stop() {
close(s.stop)
<-s.stopped
}
// Complete implements the suture.IsCompletable interface. When Serve terminates
// before Stop is called, the supervisor will check for this method and if it
// returns true removes the service instead of restarting it. Here it always

View File

@@ -10,13 +10,18 @@ import (
"fmt"
"time"
"github.com/thejerf/suture"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
)
type ProgressEmitter struct {
suture.Service
registry map[string]map[string]*sharedPullerState // folder: name: puller
interval time.Duration
minBlocks int
@@ -27,15 +32,12 @@ type ProgressEmitter struct {
mut sync.Mutex
timer *time.Timer
stop chan struct{}
}
// NewProgressEmitter creates a new progress emitter which emits
// DownloadProgress events every interval.
func NewProgressEmitter(cfg config.Wrapper) *ProgressEmitter {
t := &ProgressEmitter{
stop: make(chan struct{}),
registry: make(map[string]map[string]*sharedPullerState),
timer: time.NewTimer(time.Millisecond),
sentDownloadStates: make(map[protocol.DeviceID]*sentDownloadState),
@@ -43,6 +45,7 @@ func NewProgressEmitter(cfg config.Wrapper) *ProgressEmitter {
foldersByConns: make(map[protocol.DeviceID][]string),
mut: sync.NewMutex(),
}
t.Service = util.AsService(t.serve)
t.CommitConfiguration(config.Configuration{}, cfg.RawCopy())
cfg.Subscribe(t)
@@ -50,14 +53,14 @@ func NewProgressEmitter(cfg config.Wrapper) *ProgressEmitter {
return t
}
// Serve starts the progress emitter which starts emitting DownloadProgress
// serve starts the progress emitter which starts emitting DownloadProgress
// events as the progress happens.
func (t *ProgressEmitter) Serve() {
func (t *ProgressEmitter) serve(stop chan struct{}) {
var lastUpdate time.Time
var lastCount, newCount int
for {
select {
case <-t.stop:
case <-stop:
l.Debugln("progress emitter: stopping")
return
case <-t.timer.C:
@@ -212,11 +215,6 @@ func (t *ProgressEmitter) CommitConfiguration(from, to config.Configuration) boo
return true
}
// Stop stops the emitter.
func (t *ProgressEmitter) Stop() {
t.stop <- struct{}{}
}
// Register a puller with the emitter which will start broadcasting pullers
// progress.
func (t *ProgressEmitter) Register(s *sharedPullerState) {