|
|
@@ -40,6 +40,7 @@ import (
|
|
|
"github.com/syncthing/syncthing/lib/svcutil"
|
|
|
"github.com/syncthing/syncthing/lib/sync"
|
|
|
"github.com/syncthing/syncthing/lib/ur/contract"
|
|
|
+ "github.com/syncthing/syncthing/lib/util"
|
|
|
"github.com/syncthing/syncthing/lib/versioner"
|
|
|
)
|
|
|
|
|
|
@@ -132,10 +133,10 @@ type model struct {
|
|
|
shortID protocol.ShortID
|
|
|
// globalRequestLimiter limits the amount of data in concurrent incoming
|
|
|
// requests
|
|
|
- globalRequestLimiter *byteSemaphore
|
|
|
+ globalRequestLimiter *util.Semaphore
|
|
|
// folderIOLimiter limits the number of concurrent I/O heavy operations,
|
|
|
// such as scans and pulls.
|
|
|
- folderIOLimiter *byteSemaphore
|
|
|
+ folderIOLimiter *util.Semaphore
|
|
|
fatalChan chan error
|
|
|
started chan struct{}
|
|
|
|
|
|
@@ -155,7 +156,7 @@ type model struct {
|
|
|
// fields protected by pmut
|
|
|
pmut sync.RWMutex
|
|
|
conn map[protocol.DeviceID]protocol.Connection
|
|
|
- connRequestLimiters map[protocol.DeviceID]*byteSemaphore
|
|
|
+ connRequestLimiters map[protocol.DeviceID]*util.Semaphore
|
|
|
closed map[protocol.DeviceID]chan struct{}
|
|
|
helloMessages map[protocol.DeviceID]protocol.Hello
|
|
|
deviceDownloads map[protocol.DeviceID]*deviceDownloadState
|
|
|
@@ -166,7 +167,7 @@ type model struct {
|
|
|
foldersRunning int32
|
|
|
}
|
|
|
|
|
|
-type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, events.Logger, *byteSemaphore) service
|
|
|
+type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, events.Logger, *util.Semaphore) service
|
|
|
|
|
|
var (
|
|
|
folderFactories = make(map[config.FolderType]folderFactory)
|
|
|
@@ -220,8 +221,8 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
|
|
finder: db.NewBlockFinder(ldb),
|
|
|
progressEmitter: NewProgressEmitter(cfg, evLogger),
|
|
|
shortID: id.Short(),
|
|
|
- globalRequestLimiter: newByteSemaphore(1024 * cfg.Options().MaxConcurrentIncomingRequestKiB()),
|
|
|
- folderIOLimiter: newByteSemaphore(cfg.Options().MaxFolderConcurrency()),
|
|
|
+ globalRequestLimiter: util.NewSemaphore(1024 * cfg.Options().MaxConcurrentIncomingRequestKiB()),
|
|
|
+ folderIOLimiter: util.NewSemaphore(cfg.Options().MaxFolderConcurrency()),
|
|
|
fatalChan: make(chan error),
|
|
|
started: make(chan struct{}),
|
|
|
|
|
|
@@ -240,7 +241,7 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
|
|
// fields protected by pmut
|
|
|
pmut: sync.NewRWMutex(),
|
|
|
conn: make(map[protocol.DeviceID]protocol.Connection),
|
|
|
- connRequestLimiters: make(map[protocol.DeviceID]*byteSemaphore),
|
|
|
+ connRequestLimiters: make(map[protocol.DeviceID]*util.Semaphore),
|
|
|
closed: make(map[protocol.DeviceID]chan struct{}),
|
|
|
helloMessages: make(map[protocol.DeviceID]protocol.Hello),
|
|
|
deviceDownloads: make(map[protocol.DeviceID]*deviceDownloadState),
|
|
|
@@ -1906,23 +1907,15 @@ func (m *model) Request(deviceID protocol.DeviceID, folder, name string, blockNo
|
|
|
// skipping nil limiters, then returns a requestResponse of the given size.
|
|
|
// When the requestResponse is closed the limiters are given back the bytes,
|
|
|
// in reverse order.
|
|
|
-func newLimitedRequestResponse(size int, limiters ...*byteSemaphore) *requestResponse {
|
|
|
- for _, limiter := range limiters {
|
|
|
- if limiter != nil {
|
|
|
- limiter.take(size)
|
|
|
- }
|
|
|
- }
|
|
|
+func newLimitedRequestResponse(size int, limiters ...*util.Semaphore) *requestResponse {
|
|
|
+ multi := util.MultiSemaphore(limiters)
|
|
|
+ multi.Take(size)
|
|
|
|
|
|
res := newRequestResponse(size)
|
|
|
|
|
|
go func() {
|
|
|
res.Wait()
|
|
|
- for i := range limiters {
|
|
|
- limiter := limiters[len(limiters)-1-i]
|
|
|
- if limiter != nil {
|
|
|
- limiter.give(size)
|
|
|
- }
|
|
|
- }
|
|
|
+ multi.Give(size)
|
|
|
}()
|
|
|
|
|
|
return res
|
|
|
@@ -2230,9 +2223,9 @@ func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
|
|
|
// 0: default, <0: no limiting
|
|
|
switch {
|
|
|
case device.MaxRequestKiB > 0:
|
|
|
- m.connRequestLimiters[deviceID] = newByteSemaphore(1024 * device.MaxRequestKiB)
|
|
|
+ m.connRequestLimiters[deviceID] = util.NewSemaphore(1024 * device.MaxRequestKiB)
|
|
|
case device.MaxRequestKiB == 0:
|
|
|
- m.connRequestLimiters[deviceID] = newByteSemaphore(1024 * defaultPullerPendingKiB)
|
|
|
+ m.connRequestLimiters[deviceID] = util.NewSemaphore(1024 * defaultPullerPendingKiB)
|
|
|
}
|
|
|
|
|
|
m.helloMessages[deviceID] = hello
|
|
|
@@ -2927,8 +2920,8 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
|
|
ignoredDevices := observedDeviceSet(to.IgnoredDevices)
|
|
|
m.cleanPending(toDevices, toFolders, ignoredDevices, removedFolders)
|
|
|
|
|
|
- m.globalRequestLimiter.setCapacity(1024 * to.Options.MaxConcurrentIncomingRequestKiB())
|
|
|
- m.folderIOLimiter.setCapacity(to.Options.MaxFolderConcurrency())
|
|
|
+ m.globalRequestLimiter.SetCapacity(1024 * to.Options.MaxConcurrentIncomingRequestKiB())
|
|
|
+ m.folderIOLimiter.SetCapacity(to.Options.MaxFolderConcurrency())
|
|
|
|
|
|
// Some options don't require restart as those components handle it fine
|
|
|
// by themselves. Compare the options structs containing only the
|