|
@@ -644,9 +644,11 @@ func (m *model) ConnectionStats() map[string]interface{} {
|
|
|
|
|
|
|
|
// DeviceStatistics returns statistics about each device
|
|
// DeviceStatistics returns statistics about each device
|
|
|
func (m *model) DeviceStatistics() map[string]stats.DeviceStatistics {
|
|
func (m *model) DeviceStatistics() map[string]stats.DeviceStatistics {
|
|
|
- res := make(map[string]stats.DeviceStatistics)
|
|
|
|
|
- for id := range m.cfg.Devices() {
|
|
|
|
|
- res[id.String()] = m.deviceStatRef(id).GetStatistics()
|
|
|
|
|
|
|
+ m.fmut.RLock()
|
|
|
|
|
+ defer m.fmut.RUnlock()
|
|
|
|
|
+ res := make(map[string]stats.DeviceStatistics, len(m.deviceStatRefs))
|
|
|
|
|
+ for id, sr := range m.deviceStatRefs {
|
|
|
|
|
+ res[id.String()] = sr.GetStatistics()
|
|
|
}
|
|
}
|
|
|
return res
|
|
return res
|
|
|
}
|
|
}
|
|
@@ -1449,14 +1451,14 @@ func (m *model) Closed(conn protocol.Connection, err error) {
|
|
|
func (m *model) closeConns(devs []protocol.DeviceID, err error) config.Waiter {
|
|
func (m *model) closeConns(devs []protocol.DeviceID, err error) config.Waiter {
|
|
|
conns := make([]connections.Connection, 0, len(devs))
|
|
conns := make([]connections.Connection, 0, len(devs))
|
|
|
closed := make([]chan struct{}, 0, len(devs))
|
|
closed := make([]chan struct{}, 0, len(devs))
|
|
|
- m.pmut.Lock()
|
|
|
|
|
|
|
+ m.pmut.RLock()
|
|
|
for _, dev := range devs {
|
|
for _, dev := range devs {
|
|
|
if conn, ok := m.conn[dev]; ok {
|
|
if conn, ok := m.conn[dev]; ok {
|
|
|
conns = append(conns, conn)
|
|
conns = append(conns, conn)
|
|
|
closed = append(closed, m.closed[dev])
|
|
closed = append(closed, m.closed[dev])
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- m.pmut.Unlock()
|
|
|
|
|
|
|
+ m.pmut.RUnlock()
|
|
|
for _, conn := range conns {
|
|
for _, conn := range conns {
|
|
|
conn.Close(err)
|
|
conn.Close(err)
|
|
|
}
|
|
}
|
|
@@ -1906,21 +1908,13 @@ func (m *model) DownloadProgress(device protocol.DeviceID, folder string, update
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (m *model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
|
|
|
|
|
- m.fmut.Lock()
|
|
|
|
|
- defer m.fmut.Unlock()
|
|
|
|
|
-
|
|
|
|
|
- if sr, ok := m.deviceStatRefs[deviceID]; ok {
|
|
|
|
|
- return sr
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- sr := stats.NewDeviceStatisticsReference(m.db, deviceID.String())
|
|
|
|
|
- m.deviceStatRefs[deviceID] = sr
|
|
|
|
|
- return sr
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
|
|
func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
|
|
|
- m.deviceStatRef(deviceID).WasSeen()
|
|
|
|
|
|
|
+ m.fmut.RLock()
|
|
|
|
|
+ sr, ok := m.deviceStatRefs[deviceID]
|
|
|
|
|
+ m.fmut.RUnlock()
|
|
|
|
|
+ if ok {
|
|
|
|
|
+ sr.WasSeen()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type indexSender struct {
|
|
type indexSender struct {
|
|
@@ -2125,9 +2119,9 @@ func (m *model) ScanFolderSubdirs(folder string, subs []string) error {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (m *model) DelayScan(folder string, next time.Duration) {
|
|
func (m *model) DelayScan(folder string, next time.Duration) {
|
|
|
- m.fmut.Lock()
|
|
|
|
|
|
|
+ m.fmut.RLock()
|
|
|
runner, ok := m.folderRunners[folder]
|
|
runner, ok := m.folderRunners[folder]
|
|
|
- m.fmut.Unlock()
|
|
|
|
|
|
|
+ m.fmut.RUnlock()
|
|
|
if !ok {
|
|
if !ok {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
@@ -2137,10 +2131,10 @@ func (m *model) DelayScan(folder string, next time.Duration) {
|
|
|
// numHashers returns the number of hasher routines to use for a given folder,
|
|
// numHashers returns the number of hasher routines to use for a given folder,
|
|
|
// taking into account configuration and available CPU cores.
|
|
// taking into account configuration and available CPU cores.
|
|
|
func (m *model) numHashers(folder string) int {
|
|
func (m *model) numHashers(folder string) int {
|
|
|
- m.fmut.Lock()
|
|
|
|
|
|
|
+ m.fmut.RLock()
|
|
|
folderCfg := m.folderCfgs[folder]
|
|
folderCfg := m.folderCfgs[folder]
|
|
|
numFolders := len(m.folderCfgs)
|
|
numFolders := len(m.folderCfgs)
|
|
|
- m.fmut.Unlock()
|
|
|
|
|
|
|
+ m.fmut.RUnlock()
|
|
|
|
|
|
|
|
if folderCfg.Hashers > 0 {
|
|
if folderCfg.Hashers > 0 {
|
|
|
// Specific value set in the config, use that.
|
|
// Specific value set in the config, use that.
|
|
@@ -2553,7 +2547,15 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
|
|
toDevices := to.DeviceMap()
|
|
toDevices := to.DeviceMap()
|
|
|
for deviceID, toCfg := range toDevices {
|
|
for deviceID, toCfg := range toDevices {
|
|
|
fromCfg, ok := fromDevices[deviceID]
|
|
fromCfg, ok := fromDevices[deviceID]
|
|
|
- if !ok || fromCfg.Paused == toCfg.Paused {
|
|
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ sr := stats.NewDeviceStatisticsReference(m.db, deviceID.String())
|
|
|
|
|
+ m.fmut.Lock()
|
|
|
|
|
+ m.deviceStatRefs[deviceID] = sr
|
|
|
|
|
+ m.fmut.Unlock()
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ delete(fromDevices, deviceID)
|
|
|
|
|
+ if fromCfg.Paused == toCfg.Paused {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2570,6 +2572,11 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
|
|
m.evLogger.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
|
|
m.evLogger.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ m.fmut.Lock()
|
|
|
|
|
+ for deviceID := range fromDevices {
|
|
|
|
|
+ delete(m.deviceStatRefs, deviceID)
|
|
|
|
|
+ }
|
|
|
|
|
+ m.fmut.Unlock()
|
|
|
|
|
|
|
|
scanLimiter.setCapacity(to.Options.MaxConcurrentScans)
|
|
scanLimiter.setCapacity(to.Options.MaxConcurrentScans)
|
|
|
|
|
|