lib/model: Use a single lock (#9275)
I'm tired of the fmut/pmut shenanigans. This consolidates both under one lock; I'm not convinced there are any significant performance differences with this approach since we're literally just protecting map juggling... - The locking goes away when we were already under an appropriate fmut lock. - Where we had fmut.RLock()+pmut.Lock() it gets upgraded to an fmut.Lock(). - Otherwise s/pmut/fmut/. In order to avoid diff noise for an important change I did not do the following cleanups, which will be filed in a PR after this one, if accepted: - Renaming fmut to just mut - Renaming methods that refer to being "PRLocked" and stuff like that - Removing the no longer relevant deadlock detector - Comments referring to pmut and locking sequences...
This commit is contained in:
parent
c53a1f210c
commit
6f1023665c
|
@ -157,8 +157,7 @@ type model struct {
|
||||||
folderEncryptionPasswordTokens map[string][]byte // folder -> encryption token (may be missing, and only for encryption type folders)
|
folderEncryptionPasswordTokens map[string][]byte // folder -> encryption token (may be missing, and only for encryption type folders)
|
||||||
folderEncryptionFailures map[string]map[protocol.DeviceID]error // folder -> device -> error regarding encryption consistency (may be missing)
|
folderEncryptionFailures map[string]map[protocol.DeviceID]error // folder -> device -> error regarding encryption consistency (may be missing)
|
||||||
|
|
||||||
// fields protected by pmut
|
// fields also protected by fmut
|
||||||
pmut sync.RWMutex
|
|
||||||
connections map[string]protocol.Connection // connection ID -> connection
|
connections map[string]protocol.Connection // connection ID -> connection
|
||||||
deviceConnIDs map[protocol.DeviceID][]string // device -> connection IDs (invariant: if the key exists, the value is len >= 1, with the primary connection at the start of the slice)
|
deviceConnIDs map[protocol.DeviceID][]string // device -> connection IDs (invariant: if the key exists, the value is len >= 1, with the primary connection at the start of the slice)
|
||||||
promotedConnID map[protocol.DeviceID]string // device -> latest promoted connection ID
|
promotedConnID map[protocol.DeviceID]string // device -> latest promoted connection ID
|
||||||
|
@ -238,8 +237,7 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, ldb *db.Lowlevel, protec
|
||||||
folderEncryptionPasswordTokens: make(map[string][]byte),
|
folderEncryptionPasswordTokens: make(map[string][]byte),
|
||||||
folderEncryptionFailures: make(map[string]map[protocol.DeviceID]error),
|
folderEncryptionFailures: make(map[string]map[protocol.DeviceID]error),
|
||||||
|
|
||||||
// fields protected by pmut
|
// ditto
|
||||||
pmut: sync.NewRWMutex(),
|
|
||||||
connections: make(map[string]protocol.Connection),
|
connections: make(map[string]protocol.Connection),
|
||||||
deviceConnIDs: make(map[protocol.DeviceID][]string),
|
deviceConnIDs: make(map[protocol.DeviceID][]string),
|
||||||
promotedConnID: make(map[protocol.DeviceID]string),
|
promotedConnID: make(map[protocol.DeviceID]string),
|
||||||
|
@ -312,13 +310,13 @@ func (m *model) initFolders(cfg config.Configuration) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) closeAllConnectionsAndWait() {
|
func (m *model) closeAllConnectionsAndWait() {
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
closed := make([]chan struct{}, 0, len(m.connections))
|
closed := make([]chan struct{}, 0, len(m.connections))
|
||||||
for connID, conn := range m.connections {
|
for connID, conn := range m.connections {
|
||||||
closed = append(closed, m.closed[connID])
|
closed = append(closed, m.closed[connID])
|
||||||
go conn.Close(errStopped)
|
go conn.Close(errStopped)
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
for _, c := range closed {
|
for _, c := range closed {
|
||||||
<-c
|
<-c
|
||||||
}
|
}
|
||||||
|
@ -338,7 +336,6 @@ func (m *model) StartDeadlockDetector(timeout time.Duration) {
|
||||||
l.Infof("Starting deadlock detector with %v timeout", timeout)
|
l.Infof("Starting deadlock detector with %v timeout", timeout)
|
||||||
detector := newDeadlockDetector(timeout, m.evLogger, m.fatal)
|
detector := newDeadlockDetector(timeout, m.evLogger, m.fatal)
|
||||||
detector.Watch("fmut", m.fmut)
|
detector.Watch("fmut", m.fmut)
|
||||||
detector.Watch("pmut", m.pmut)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to hold lock on m.fmut when calling this.
|
// Need to hold lock on m.fmut when calling this.
|
||||||
|
@ -472,7 +469,6 @@ func (m *model) removeFolder(cfg config.FolderConfiguration) {
|
||||||
// We need to hold both fmut and pmut and must acquire locks in the same
|
// We need to hold both fmut and pmut and must acquire locks in the same
|
||||||
// order always. (The locks can be *released* in any order.)
|
// order always. (The locks can be *released* in any order.)
|
||||||
m.fmut.Lock()
|
m.fmut.Lock()
|
||||||
m.pmut.RLock()
|
|
||||||
|
|
||||||
isPathUnique := true
|
isPathUnique := true
|
||||||
for folderID, folderCfg := range m.folderCfgs {
|
for folderID, folderCfg := range m.folderCfgs {
|
||||||
|
@ -498,7 +494,6 @@ func (m *model) removeFolder(cfg config.FolderConfiguration) {
|
||||||
})
|
})
|
||||||
|
|
||||||
m.fmut.Unlock()
|
m.fmut.Unlock()
|
||||||
m.pmut.RUnlock()
|
|
||||||
|
|
||||||
// Remove it from the database
|
// Remove it from the database
|
||||||
db.DropFolder(m.db, cfg.ID)
|
db.DropFolder(m.db, cfg.ID)
|
||||||
|
@ -563,15 +558,11 @@ func (m *model) restartFolder(from, to config.FolderConfiguration, cacheIgnoredF
|
||||||
m.addAndStartFolderLocked(to, fset, cacheIgnoredFiles)
|
m.addAndStartFolderLocked(to, fset, cacheIgnoredFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Care needs to be taken because we already hold fmut and the lock order
|
|
||||||
// must be the same everywhere. As fmut is acquired first, this is fine.
|
|
||||||
m.pmut.RLock()
|
|
||||||
runner, _ := m.folderRunners.Get(to.ID)
|
runner, _ := m.folderRunners.Get(to.ID)
|
||||||
m.indexHandlers.Each(func(_ protocol.DeviceID, r *indexHandlerRegistry) error {
|
m.indexHandlers.Each(func(_ protocol.DeviceID, r *indexHandlerRegistry) error {
|
||||||
r.RegisterFolderState(to, fset, runner)
|
r.RegisterFolderState(to, fset, runner)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
m.pmut.RUnlock()
|
|
||||||
|
|
||||||
var infoMsg string
|
var infoMsg string
|
||||||
switch {
|
switch {
|
||||||
|
@ -603,15 +594,11 @@ func (m *model) newFolder(cfg config.FolderConfiguration, cacheIgnoredFiles bool
|
||||||
// Cluster configs might be received and processed before reaching this
|
// Cluster configs might be received and processed before reaching this
|
||||||
// point, i.e. before the folder is started. If that's the case, start
|
// point, i.e. before the folder is started. If that's the case, start
|
||||||
// index senders here.
|
// index senders here.
|
||||||
// Care needs to be taken because we already hold fmut and the lock order
|
|
||||||
// must be the same everywhere. As fmut is acquired first, this is fine.
|
|
||||||
m.pmut.RLock()
|
|
||||||
m.indexHandlers.Each(func(_ protocol.DeviceID, r *indexHandlerRegistry) error {
|
m.indexHandlers.Each(func(_ protocol.DeviceID, r *indexHandlerRegistry) error {
|
||||||
runner, _ := m.folderRunners.Get(cfg.ID)
|
runner, _ := m.folderRunners.Get(cfg.ID)
|
||||||
r.RegisterFolderState(cfg, fset, runner)
|
r.RegisterFolderState(cfg, fset, runner)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
m.pmut.RUnlock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -645,11 +632,11 @@ func (m *model) UsageReportingStats(report *contract.Report, version int, previe
|
||||||
blockStatsMut.Unlock()
|
blockStatsMut.Unlock()
|
||||||
|
|
||||||
// Transport stats
|
// Transport stats
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, conn := range m.connections {
|
for _, conn := range m.connections {
|
||||||
report.TransportStats[conn.Transport()]++
|
report.TransportStats[conn.Transport()]++
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
// Ignore stats
|
// Ignore stats
|
||||||
var seenPrefix [3]bool
|
var seenPrefix [3]bool
|
||||||
|
@ -736,8 +723,8 @@ type ConnectionInfo struct {
|
||||||
|
|
||||||
// ConnectionStats returns a map with connection statistics for each device.
|
// ConnectionStats returns a map with connection statistics for each device.
|
||||||
func (m *model) ConnectionStats() map[string]interface{} {
|
func (m *model) ConnectionStats() map[string]interface{} {
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.pmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
|
|
||||||
res := make(map[string]interface{})
|
res := make(map[string]interface{})
|
||||||
devs := m.cfg.Devices()
|
devs := m.cfg.Devices()
|
||||||
|
@ -812,8 +799,6 @@ func (m *model) ConnectionStats() map[string]interface{} {
|
||||||
func (m *model) DeviceStatistics() (map[protocol.DeviceID]stats.DeviceStatistics, error) {
|
func (m *model) DeviceStatistics() (map[protocol.DeviceID]stats.DeviceStatistics, error) {
|
||||||
m.fmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.fmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
m.pmut.RLock()
|
|
||||||
defer m.pmut.RUnlock()
|
|
||||||
res := make(map[protocol.DeviceID]stats.DeviceStatistics, len(m.deviceStatRefs))
|
res := make(map[protocol.DeviceID]stats.DeviceStatistics, len(m.deviceStatRefs))
|
||||||
for id, sr := range m.deviceStatRefs {
|
for id, sr := range m.deviceStatRefs {
|
||||||
stats, err := sr.GetStatistics()
|
stats, err := sr.GetStatistics()
|
||||||
|
@ -965,10 +950,10 @@ func (m *model) folderCompletion(device protocol.DeviceID, folder string) (Folde
|
||||||
}
|
}
|
||||||
defer snap.Release()
|
defer snap.Release()
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
state := m.remoteFolderStates[device][folder]
|
state := m.remoteFolderStates[device][folder]
|
||||||
downloaded := m.deviceDownloads[device].BytesDownloaded(folder)
|
downloaded := m.deviceDownloads[device].BytesDownloaded(folder)
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
need := snap.NeedSize(device)
|
need := snap.NeedSize(device)
|
||||||
need.Bytes -= downloaded
|
need.Bytes -= downloaded
|
||||||
|
@ -1191,9 +1176,9 @@ func (m *model) handleIndex(conn protocol.Connection, folder string, fs []protoc
|
||||||
return fmt.Errorf("%s: %w", folder, ErrFolderPaused)
|
return fmt.Errorf("%s: %w", folder, ErrFolderPaused)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
indexHandler, ok := m.getIndexHandlerPRLocked(conn)
|
indexHandler, ok := m.getIndexHandlerPRLocked(conn)
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
// This should be impossible, as an index handler is registered when
|
// This should be impossible, as an index handler is registered when
|
||||||
// we send a cluster config, and that is what triggers index
|
// we send a cluster config, and that is what triggers index
|
||||||
|
@ -1306,9 +1291,9 @@ func (m *model) ClusterConfig(conn protocol.Connection, cm protocol.ClusterConfi
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.Lock()
|
m.fmut.Lock()
|
||||||
m.remoteFolderStates[deviceID] = states
|
m.remoteFolderStates[deviceID] = states
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
|
|
||||||
m.evLogger.Log(events.ClusterConfigReceived, ClusterConfigReceivedEventData{
|
m.evLogger.Log(events.ClusterConfigReceived, ClusterConfigReceivedEventData{
|
||||||
Device: deviceID,
|
Device: deviceID,
|
||||||
|
@ -1317,11 +1302,11 @@ func (m *model) ClusterConfig(conn protocol.Connection, cm protocol.ClusterConfi
|
||||||
if len(tempIndexFolders) > 0 {
|
if len(tempIndexFolders) > 0 {
|
||||||
var connOK bool
|
var connOK bool
|
||||||
var conn protocol.Connection
|
var conn protocol.Connection
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
if connIDs, connIDOK := m.deviceConnIDs[deviceID]; connIDOK {
|
if connIDs, connIDOK := m.deviceConnIDs[deviceID]; connIDOK {
|
||||||
conn, connOK = m.connections[connIDs[0]]
|
conn, connOK = m.connections[connIDs[0]]
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
// In case we've got ClusterConfig, and the connection disappeared
|
// In case we've got ClusterConfig, and the connection disappeared
|
||||||
// from infront of our nose.
|
// from infront of our nose.
|
||||||
if connOK {
|
if connOK {
|
||||||
|
@ -1354,11 +1339,8 @@ func (m *model) ensureIndexHandler(conn protocol.Connection) *indexHandlerRegist
|
||||||
deviceID := conn.DeviceID()
|
deviceID := conn.DeviceID()
|
||||||
connID := conn.ConnectionID()
|
connID := conn.ConnectionID()
|
||||||
|
|
||||||
// We must acquire fmut first when acquiring both locks.
|
m.fmut.Lock()
|
||||||
m.fmut.RLock()
|
defer m.fmut.Unlock()
|
||||||
defer m.fmut.RUnlock()
|
|
||||||
m.pmut.Lock()
|
|
||||||
defer m.pmut.Unlock()
|
|
||||||
|
|
||||||
indexHandlerRegistry, ok := m.indexHandlers.Get(deviceID)
|
indexHandlerRegistry, ok := m.indexHandlers.Get(deviceID)
|
||||||
if ok && indexHandlerRegistry.conn.ConnectionID() == connID {
|
if ok && indexHandlerRegistry.conn.ConnectionID() == connID {
|
||||||
|
@ -1650,13 +1632,13 @@ func (m *model) sendClusterConfig(ids []protocol.DeviceID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ccConns := make([]protocol.Connection, 0, len(ids))
|
ccConns := make([]protocol.Connection, 0, len(ids))
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
if connIDs, ok := m.deviceConnIDs[id]; ok {
|
if connIDs, ok := m.deviceConnIDs[id]; ok {
|
||||||
ccConns = append(ccConns, m.connections[connIDs[0]])
|
ccConns = append(ccConns, m.connections[connIDs[0]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
||||||
for _, conn := range ccConns {
|
for _, conn := range ccConns {
|
||||||
cm, passwords := m.generateClusterConfig(conn.DeviceID())
|
cm, passwords := m.generateClusterConfig(conn.DeviceID())
|
||||||
|
@ -1893,10 +1875,10 @@ func (m *model) Closed(conn protocol.Connection, err error) {
|
||||||
connID := conn.ConnectionID()
|
connID := conn.ConnectionID()
|
||||||
deviceID := conn.DeviceID()
|
deviceID := conn.DeviceID()
|
||||||
|
|
||||||
m.pmut.Lock()
|
m.fmut.Lock()
|
||||||
conn, ok := m.connections[connID]
|
conn, ok := m.connections[connID]
|
||||||
if !ok {
|
if !ok {
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,7 +1909,7 @@ func (m *model) Closed(conn protocol.Connection, err error) {
|
||||||
m.deviceConnIDs[deviceID] = remainingConns
|
m.deviceConnIDs[deviceID] = remainingConns
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
if wait != nil {
|
if wait != nil {
|
||||||
<-wait
|
<-wait
|
||||||
}
|
}
|
||||||
|
@ -2029,9 +2011,9 @@ func (m *model) Request(conn protocol.Connection, folder, name string, _, size i
|
||||||
|
|
||||||
// Restrict parallel requests by connection/device
|
// Restrict parallel requests by connection/device
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
limiter := m.connRequestLimiters[deviceID]
|
limiter := m.connRequestLimiters[deviceID]
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
// The requestResponse releases the bytes to the buffer pool and the
|
// The requestResponse releases the bytes to the buffer pool and the
|
||||||
// limiters when its Close method is called.
|
// limiters when its Close method is called.
|
||||||
|
@ -2218,9 +2200,9 @@ func (m *model) GetMtimeMapping(folder string, file string) (fs.MtimeMapping, er
|
||||||
|
|
||||||
// Connection returns if we are connected to the given device.
|
// Connection returns if we are connected to the given device.
|
||||||
func (m *model) ConnectedTo(deviceID protocol.DeviceID) bool {
|
func (m *model) ConnectedTo(deviceID protocol.DeviceID) bool {
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
_, ok := m.deviceConnIDs[deviceID]
|
_, ok := m.deviceConnIDs[deviceID]
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2353,7 +2335,7 @@ func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
|
||||||
connID := conn.ConnectionID()
|
connID := conn.ConnectionID()
|
||||||
closed := make(chan struct{})
|
closed := make(chan struct{})
|
||||||
|
|
||||||
m.pmut.Lock()
|
m.fmut.Lock()
|
||||||
|
|
||||||
m.connections[connID] = conn
|
m.connections[connID] = conn
|
||||||
m.closed[connID] = closed
|
m.closed[connID] = closed
|
||||||
|
@ -2384,7 +2366,7 @@ func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
|
||||||
l.Infof(`Additional connection (+%d) for device %s at %s`, len(m.deviceConnIDs[deviceID])-1, deviceID.Short(), conn)
|
l.Infof(`Additional connection (+%d) for device %s at %s`, len(m.deviceConnIDs[deviceID])-1, deviceID.Short(), conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
|
|
||||||
if (deviceCfg.Name == "" || m.cfg.Options().OverwriteRemoteDevNames) && hello.DeviceName != "" {
|
if (deviceCfg.Name == "" || m.cfg.Options().OverwriteRemoteDevNames) && hello.DeviceName != "" {
|
||||||
m.cfg.Modify(func(cfg *config.Configuration) {
|
m.cfg.Modify(func(cfg *config.Configuration) {
|
||||||
|
@ -2415,11 +2397,8 @@ func (m *model) scheduleConnectionPromotion() {
|
||||||
// be called after adding new connections, and after closing a primary
|
// be called after adding new connections, and after closing a primary
|
||||||
// device connection.
|
// device connection.
|
||||||
func (m *model) promoteConnections() {
|
func (m *model) promoteConnections() {
|
||||||
m.fmut.RLock() // for generateClusterConfigFRLocked
|
m.fmut.Lock()
|
||||||
defer m.fmut.RUnlock()
|
defer m.fmut.Unlock()
|
||||||
|
|
||||||
m.pmut.Lock() // for most other things
|
|
||||||
defer m.pmut.Unlock()
|
|
||||||
|
|
||||||
for deviceID, connIDs := range m.deviceConnIDs {
|
for deviceID, connIDs := range m.deviceConnIDs {
|
||||||
cm, passwords := m.generateClusterConfigFRLocked(deviceID)
|
cm, passwords := m.generateClusterConfigFRLocked(deviceID)
|
||||||
|
@ -2464,9 +2443,9 @@ func (m *model) DownloadProgress(conn protocol.Connection, folder string, update
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
downloads := m.deviceDownloads[deviceID]
|
downloads := m.deviceDownloads[deviceID]
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
downloads.Update(folder, updates)
|
downloads.Update(folder, updates)
|
||||||
state := downloads.GetBlockCounts(folder)
|
state := downloads.GetBlockCounts(folder)
|
||||||
|
|
||||||
|
@ -2511,8 +2490,8 @@ func (m *model) requestGlobal(ctx context.Context, deviceID protocol.DeviceID, f
|
||||||
// ("primary") connection, which is dedicated to index data, and pick a
|
// ("primary") connection, which is dedicated to index data, and pick a
|
||||||
// random one of the others.
|
// random one of the others.
|
||||||
func (m *model) requestConnectionForDevice(deviceID protocol.DeviceID) (protocol.Connection, bool) {
|
func (m *model) requestConnectionForDevice(deviceID protocol.DeviceID) (protocol.Connection, bool) {
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.pmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
|
|
||||||
connIDs, ok := m.deviceConnIDs[deviceID]
|
connIDs, ok := m.deviceConnIDs[deviceID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -2903,12 +2882,10 @@ func (m *model) Availability(folder string, file protocol.FileInfo, block protoc
|
||||||
// get heavily modified on Close()), but also must acquire fmut before
|
// get heavily modified on Close()), but also must acquire fmut before
|
||||||
// pmut. (The locks can be *released* in any order.)
|
// pmut. (The locks can be *released* in any order.)
|
||||||
m.fmut.RLock()
|
m.fmut.RLock()
|
||||||
m.pmut.RLock()
|
defer m.fmut.RUnlock()
|
||||||
defer m.pmut.RUnlock()
|
|
||||||
|
|
||||||
fs, ok := m.folderFiles[folder]
|
fs, ok := m.folderFiles[folder]
|
||||||
cfg := m.folderCfgs[folder]
|
cfg := m.folderCfgs[folder]
|
||||||
m.fmut.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrFolderMissing
|
return nil, ErrFolderMissing
|
||||||
|
@ -2924,8 +2901,8 @@ func (m *model) Availability(folder string, file protocol.FileInfo, block protoc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) availabilityInSnapshot(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
func (m *model) availabilityInSnapshot(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
defer m.pmut.RUnlock()
|
defer m.fmut.RUnlock()
|
||||||
return m.availabilityInSnapshotPRlocked(cfg, snap, file, block)
|
return m.availabilityInSnapshotPRlocked(cfg, snap, file, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3113,9 +3090,9 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if toCfg.MaxRequestKiB != fromCfg.MaxRequestKiB {
|
if toCfg.MaxRequestKiB != fromCfg.MaxRequestKiB {
|
||||||
m.pmut.Lock()
|
m.fmut.Lock()
|
||||||
m.setConnRequestLimitersPLocked(toCfg)
|
m.setConnRequestLimitersPLocked(toCfg)
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3129,7 +3106,7 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||||
}
|
}
|
||||||
m.fmut.Unlock()
|
m.fmut.Unlock()
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
for _, id := range closeDevices {
|
for _, id := range closeDevices {
|
||||||
delete(clusterConfigDevices, id)
|
delete(clusterConfigDevices, id)
|
||||||
if conns, ok := m.deviceConnIDs[id]; ok {
|
if conns, ok := m.deviceConnIDs[id]; ok {
|
||||||
|
@ -3146,7 +3123,7 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
||||||
m.sendClusterConfig(clusterConfigDevices.AsSlice())
|
m.sendClusterConfig(clusterConfigDevices.AsSlice())
|
||||||
|
|
||||||
|
|
|
@ -902,13 +902,13 @@ func TestIssue5063(t *testing.T) {
|
||||||
defer cleanupModel(m)
|
defer cleanupModel(m)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
m.pmut.Lock()
|
m.fmut.Lock()
|
||||||
for _, c := range m.connections {
|
for _, c := range m.connections {
|
||||||
conn := c.(*fakeConnection)
|
conn := c.(*fakeConnection)
|
||||||
conn.CloseCalls(func(_ error) {})
|
conn.CloseCalls(func(_ error) {})
|
||||||
defer m.Closed(c, errStopped) // to unblock deferred m.Stop()
|
defer m.Closed(c, errStopped) // to unblock deferred m.Stop()
|
||||||
}
|
}
|
||||||
m.pmut.Unlock()
|
m.fmut.Unlock()
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
|
@ -2973,7 +2973,7 @@ func TestConnCloseOnRestart(t *testing.T) {
|
||||||
ci := &protocolmocks.ConnectionInfo{}
|
ci := &protocolmocks.ConnectionInfo{}
|
||||||
ci.ConnectionIDReturns(srand.String(16))
|
ci.ConnectionIDReturns(srand.String(16))
|
||||||
m.AddConnection(protocol.NewConnection(device1, br, nw, testutil.NoopCloser{}, m, ci, protocol.CompressionNever, nil, m.keyGen), protocol.Hello{})
|
m.AddConnection(protocol.NewConnection(device1, br, nw, testutil.NoopCloser{}, m, ci, protocol.CompressionNever, nil, m.keyGen), protocol.Hello{})
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
if len(m.closed) != 1 {
|
if len(m.closed) != 1 {
|
||||||
t.Fatalf("Expected just one conn (len(m.closed) == %v)", len(m.closed))
|
t.Fatalf("Expected just one conn (len(m.closed) == %v)", len(m.closed))
|
||||||
}
|
}
|
||||||
|
@ -2981,7 +2981,7 @@ func TestConnCloseOnRestart(t *testing.T) {
|
||||||
for _, c := range m.closed {
|
for _, c := range m.closed {
|
||||||
closed = c
|
closed = c
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
waiter, err := w.RemoveDevice(device1)
|
waiter, err := w.RemoveDevice(device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3074,12 +3074,12 @@ func TestDevicePause(t *testing.T) {
|
||||||
sub := m.evLogger.Subscribe(events.DevicePaused)
|
sub := m.evLogger.Subscribe(events.DevicePaused)
|
||||||
defer sub.Unsubscribe()
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.fmut.RLock()
|
||||||
var closed chan struct{}
|
var closed chan struct{}
|
||||||
for _, c := range m.closed {
|
for _, c := range m.closed {
|
||||||
closed = c
|
closed = c
|
||||||
}
|
}
|
||||||
m.pmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
pauseDevice(t, m.cfg, device1, true)
|
pauseDevice(t, m.cfg, device1, true)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue