diff --git a/management/server/account.go b/management/server/account.go index 9bb029b51..2ac516db8 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -983,7 +983,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, return nil, status.Errorf(status.InvalidArgument, "peer login expiration can't be smaller than one hour") } - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -1034,7 +1034,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, func (am *DefaultAccountManager) peerLoginExpirationJob(accountID string) func() (time.Duration, bool) { return func() (time.Duration, bool) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -1139,7 +1139,7 @@ func (am *DefaultAccountManager) warmupIDPCache() error { // DeleteAccount deletes an account and all its users from local store and from the remote IDP if the requester is an admin and account owner func (am *DefaultAccountManager) DeleteAccount(accountID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) if err != nil { @@ -1598,7 +1598,7 @@ func (am *DefaultAccountManager) MarkPATUsed(tokenID string) error { return err } - unlock := am.Store.AcquireAccountLock(account.Id) + unlock := am.Store.AcquireAccountWriteLock(account.Id) defer unlock() account, err = am.Store.GetAccountByUser(user.Id) @@ -1681,7 +1681,7 @@ func (am *DefaultAccountManager) GetAccountFromToken(claims jwtclaims.Authorizat if err != nil { return nil, nil, err } - unlock := am.Store.AcquireAccountLock(newAcc.Id) + unlock := am.Store.AcquireAccountWriteLock(newAcc.Id) alreadyUnlocked := false defer func() { if !alreadyUnlocked { @@ -1832,7 +1832,7 @@ func (am *DefaultAccountManager) getAccountWithAuthorizationClaims(claims jwtcla account, err := am.Store.GetAccountByUser(claims.UserId) if err == nil { - unlockAccount := am.Store.AcquireAccountLock(account.Id) + unlockAccount := am.Store.AcquireAccountWriteLock(account.Id) defer unlockAccount() account, err = am.Store.GetAccountByUser(claims.UserId) if err != nil { @@ -1852,7 +1852,7 @@ func (am *DefaultAccountManager) getAccountWithAuthorizationClaims(claims jwtcla return account, nil } else if s, ok := status.FromError(err); ok && s.Type() == status.NotFound { if domainAccount != nil { - unlockAccount := am.Store.AcquireAccountLock(domainAccount.Id) + unlockAccount := am.Store.AcquireAccountWriteLock(domainAccount.Id) defer unlockAccount() domainAccount, err = am.Store.GetAccountByPrivateDomain(claims.Domain) if err != nil { @@ -1878,7 +1878,7 @@ func (am *DefaultAccountManager) SyncAndMarkPeer(peerPubKey string, realIP net.I return nil, nil, err } - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountReadLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -1905,7 +1905,7 @@ func (am *DefaultAccountManager) CancelPeerRoutines(peer *nbpeer.Peer) error { return err } - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/dns.go b/management/server/dns.go index f6e3531ec..5e2febf55 100644 --- a/management/server/dns.go +++ b/management/server/dns.go @@ -35,7 +35,7 @@ func (d DNSSettings) Copy() DNSSettings { // GetDNSSettings validates a user role and returns the DNS settings for the provided account ID func (am *DefaultAccountManager) GetDNSSettings(accountID string, userID string) (*DNSSettings, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -57,7 +57,7 @@ func (am *DefaultAccountManager) GetDNSSettings(accountID string, userID string) // SaveDNSSettings validates a user role and updates the account's DNS settings func (am *DefaultAccountManager) SaveDNSSettings(accountID string, userID string, dnsSettingsToSave *DNSSettings) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/event.go b/management/server/event.go index dd253717a..303f88a79 100644 --- a/management/server/event.go +++ b/management/server/event.go @@ -12,7 +12,7 @@ import ( // GetEvents returns a list of activity events of an account func (am *DefaultAccountManager) GetEvents(accountID, userID string) ([]*activity.Event, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/file_store.go b/management/server/file_store.go index ebc96f4be..d75dbb07b 100644 --- a/management/server/file_store.go +++ b/management/server/file_store.go @@ -280,8 +280,8 @@ func (s *FileStore) AcquireGlobalLock() (unlock func()) { return unlock } -// AcquireAccountLock acquires account lock and returns a function that releases the lock -func (s *FileStore) AcquireAccountLock(accountID string) (unlock func()) { +// AcquireAccountWriteLock acquires account lock for writing to a resource and returns a function that releases the lock +func (s *FileStore) AcquireAccountWriteLock(accountID string) (unlock func()) { log.Debugf("acquiring lock for account %s", accountID) start := time.Now() value, _ := s.accountLocks.LoadOrStore(accountID, &sync.Mutex{}) @@ -296,6 +296,12 @@ func (s *FileStore) AcquireAccountLock(accountID string) (unlock func()) { return unlock } +// AcquireAccountReadLock AcquireAccountWriteLock acquires account lock for reading a resource and returns a function that releases the lock +// This method is still returns a write lock as file store can't handle read locks +func (s *FileStore) AcquireAccountReadLock(accountID string) (unlock func()) { + return s.AcquireAccountWriteLock(accountID) +} + func (s *FileStore) SaveAccount(account *Account) error { s.mux.Lock() defer s.mux.Unlock() diff --git a/management/server/group.go b/management/server/group.go index 0fc952cdb..9669820cd 100644 --- a/management/server/group.go +++ b/management/server/group.go @@ -22,7 +22,7 @@ func (e *GroupLinkError) Error() string { // GetGroup object of the peers func (am *DefaultAccountManager) GetGroup(accountID, groupID, userID string) (*nbgroup.Group, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -49,7 +49,7 @@ func (am *DefaultAccountManager) GetGroup(accountID, groupID, userID string) (*n // GetAllGroups returns all groups in an account func (am *DefaultAccountManager) GetAllGroups(accountID string, userID string) ([]*nbgroup.Group, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -76,7 +76,7 @@ func (am *DefaultAccountManager) GetAllGroups(accountID string, userID string) ( // GetGroupByName filters all groups in an account by name and returns the one with the most peers func (am *DefaultAccountManager) GetGroupByName(groupName, accountID string) (*nbgroup.Group, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -109,7 +109,7 @@ func (am *DefaultAccountManager) GetGroupByName(groupName, accountID string) (*n // SaveGroup object of the peers func (am *DefaultAccountManager) SaveGroup(accountID, userID string, newGroup *nbgroup.Group) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -214,7 +214,7 @@ func difference(a, b []string) []string { // DeleteGroup object of the peers func (am *DefaultAccountManager) DeleteGroup(accountId, userId, groupID string) error { - unlock := am.Store.AcquireAccountLock(accountId) + unlock := am.Store.AcquireAccountWriteLock(accountId) defer unlock() account, err := am.Store.GetAccount(accountId) @@ -323,7 +323,7 @@ func (am *DefaultAccountManager) DeleteGroup(accountId, userId, groupID string) // ListGroups objects of the peers func (am *DefaultAccountManager) ListGroups(accountID string) ([]*nbgroup.Group, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -341,7 +341,7 @@ func (am *DefaultAccountManager) ListGroups(accountID string) ([]*nbgroup.Group, // GroupAddPeer appends peer to the group func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -377,7 +377,7 @@ func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerID string) // GroupDeletePeer removes peer from the group func (am *DefaultAccountManager) GroupDeletePeer(accountID, groupID, peerID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/integrated_validator.go b/management/server/integrated_validator.go index a47dc5bf3..6bafd45f4 100644 --- a/management/server/integrated_validator.go +++ b/management/server/integrated_validator.go @@ -32,7 +32,7 @@ func (am *DefaultAccountManager) UpdateIntegratedValidatorGroups(accountID strin return errors.New("invalid groups") } - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() a, err := am.Store.GetAccountByUser(userID) diff --git a/management/server/nameserver.go b/management/server/nameserver.go index fa7793602..44d231c3e 100644 --- a/management/server/nameserver.go +++ b/management/server/nameserver.go @@ -19,7 +19,7 @@ const domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$` // GetNameServerGroup gets a nameserver group object from account and nameserver group IDs func (am *DefaultAccountManager) GetNameServerGroup(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -47,7 +47,7 @@ func (am *DefaultAccountManager) GetNameServerGroup(accountID, userID, nsGroupID // CreateNameServerGroup creates and saves a new nameserver group func (am *DefaultAccountManager) CreateNameServerGroup(accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainEnabled bool) (*nbdns.NameServerGroup, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -94,7 +94,7 @@ func (am *DefaultAccountManager) CreateNameServerGroup(accountID string, name, d // SaveNameServerGroup saves nameserver group func (am *DefaultAccountManager) SaveNameServerGroup(accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if nsGroupToSave == nil { @@ -129,7 +129,7 @@ func (am *DefaultAccountManager) SaveNameServerGroup(accountID, userID string, n // DeleteNameServerGroup deletes nameserver group with nsGroupID func (am *DefaultAccountManager) DeleteNameServerGroup(accountID, nsGroupID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -159,7 +159,7 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(accountID, nsGroupID, use // ListNameServerGroups returns a list of nameserver groups from account func (am *DefaultAccountManager) ListNameServerGroups(accountID string, userID string) ([]*nbdns.NameServerGroup, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/peer.go b/management/server/peer.go index 5140620ea..c12eed7cd 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -148,7 +148,7 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerPubKey string, connected // UpdatePeer updates peer. Only Peer.Name, Peer.SSHEnabled, and Peer.LoginExpirationEnabled can be updated. func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *nbpeer.Peer) (*nbpeer.Peer, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -270,7 +270,7 @@ func (am *DefaultAccountManager) deletePeers(account *Account, peerIDs []string, // DeletePeer removes peer from the account by its IP func (am *DefaultAccountManager) DeletePeer(accountID, peerID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -354,7 +354,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P return nil, nil, status.Errorf(status.NotFound, "failed adding new peer: account not found") } - unlock := am.Store.AcquireAccountLock(account.Id) + unlock := am.Store.AcquireAccountWriteLock(account.Id) defer unlock() // ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account) @@ -373,7 +373,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P } // This is a handling for the case when the same machine (with the same WireGuard pub key) tries to register twice. - // Such case is possible when AddPeer function takes long time to finish after AcquireAccountLock (e.g., database is slow) + // Such case is possible when AddPeer function takes long time to finish after AcquireAccountWriteLock (e.g., database is slow) // and the peer disconnects with a timeout and tries to register again. // We just check if this machine has been registered before and reject the second registration. // The connecting peer should be able to recover with a retry. @@ -589,7 +589,7 @@ func (am *DefaultAccountManager) LoginPeer(login PeerLogin) (*nbpeer.Peer, *Netw } // we found the peer, and we follow a normal login flow - unlock := am.Store.AcquireAccountLock(account.Id) + unlock := am.Store.AcquireAccountWriteLock(account.Id) defer unlock() // fetch the account from the store once more after acquiring lock to avoid concurrent updates inconsistencies @@ -758,7 +758,7 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) return err } - unlock := am.Store.AcquireAccountLock(account.Id) + unlock := am.Store.AcquireAccountWriteLock(account.Id) defer unlock() // ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account) @@ -793,7 +793,7 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) // GetPeer for a given accountID, peerID and userID error if not found. func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*nbpeer.Peer, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/policy.go b/management/server/policy.go index e162d2b3b..704825cae 100644 --- a/management/server/policy.go +++ b/management/server/policy.go @@ -314,7 +314,7 @@ func (a *Account) connResourcesGenerator() (func(*PolicyRule, []*nbpeer.Peer, in // GetPolicy from the store func (am *DefaultAccountManager) GetPolicy(accountID, policyID, userID string) (*Policy, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -342,7 +342,7 @@ func (am *DefaultAccountManager) GetPolicy(accountID, policyID, userID string) ( // SavePolicy in the store func (am *DefaultAccountManager) SavePolicy(accountID, userID string, policy *Policy) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -370,7 +370,7 @@ func (am *DefaultAccountManager) SavePolicy(accountID, userID string, policy *Po // DeletePolicy from the store func (am *DefaultAccountManager) DeletePolicy(accountID, policyID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -397,7 +397,7 @@ func (am *DefaultAccountManager) DeletePolicy(accountID, policyID, userID string // ListPolicies from the store func (am *DefaultAccountManager) ListPolicies(accountID, userID string) ([]*Policy, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/posture_checks.go b/management/server/posture_checks.go index 7e654b5fb..fb904c10f 100644 --- a/management/server/posture_checks.go +++ b/management/server/posture_checks.go @@ -7,7 +7,7 @@ import ( ) func (am *DefaultAccountManager) GetPostureChecks(accountID, postureChecksID, userID string) (*posture.Checks, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -34,7 +34,7 @@ func (am *DefaultAccountManager) GetPostureChecks(accountID, postureChecksID, us } func (am *DefaultAccountManager) SavePostureChecks(accountID, userID string, postureChecks *posture.Checks) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -81,7 +81,7 @@ func (am *DefaultAccountManager) SavePostureChecks(accountID, userID string, pos } func (am *DefaultAccountManager) DeletePostureChecks(accountID, postureChecksID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -113,7 +113,7 @@ func (am *DefaultAccountManager) DeletePostureChecks(accountID, postureChecksID, } func (am *DefaultAccountManager) ListPostureChecks(accountID, userID string) ([]*posture.Checks, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/route.go b/management/server/route.go index 4de552a2d..65be723da 100644 --- a/management/server/route.go +++ b/management/server/route.go @@ -14,7 +14,7 @@ import ( // GetRoute gets a route object from account and route IDs func (am *DefaultAccountManager) GetRoute(accountID, routeID, userID string) (*route.Route, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -115,7 +115,7 @@ func (am *DefaultAccountManager) checkRoutePrefixExistsForPeers(account *Account // CreateRoute creates and saves a new route func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, peerGroupIDs []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -194,7 +194,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, // SaveRoute saves route func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave *route.Route) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if routeToSave == nil { @@ -255,7 +255,7 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave // DeleteRoute deletes route with routeID func (am *DefaultAccountManager) DeleteRoute(accountID, routeID, userID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -283,7 +283,7 @@ func (am *DefaultAccountManager) DeleteRoute(accountID, routeID, userID string) // ListRoutes returns a list of routes from account func (am *DefaultAccountManager) ListRoutes(accountID, userID string) ([]*route.Route, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/setupkey.go b/management/server/setupkey.go index ff6fb3204..40b8ac457 100644 --- a/management/server/setupkey.go +++ b/management/server/setupkey.go @@ -209,7 +209,7 @@ func Hash(s string) uint32 { // and adds it to the specified account. A list of autoGroups IDs can be empty. func (am *DefaultAccountManager) CreateSetupKey(accountID string, keyName string, keyType SetupKeyType, expiresIn time.Duration, autoGroups []string, usageLimit int, userID string, ephemeral bool) (*SetupKey, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() keyDuration := DefaultSetupKeyDuration @@ -255,7 +255,7 @@ func (am *DefaultAccountManager) CreateSetupKey(accountID string, keyName string // (e.g. the key itself, creation date, ID, etc). // These properties are overwritten: Name, AutoGroups, Revoked. The rest is copied from the existing key. func (am *DefaultAccountManager) SaveSetupKey(accountID string, keyToSave *SetupKey, userID string) (*SetupKey, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if keyToSave == nil { @@ -327,7 +327,7 @@ func (am *DefaultAccountManager) SaveSetupKey(accountID string, keyToSave *Setup // ListSetupKeys returns a list of all setup keys of the account func (am *DefaultAccountManager) ListSetupKeys(accountID, userID string) ([]*SetupKey, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) if err != nil { @@ -359,7 +359,7 @@ func (am *DefaultAccountManager) ListSetupKeys(accountID, userID string) ([]*Set // GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found. func (am *DefaultAccountManager) GetSetupKey(accountID, userID, keyID string) (*SetupKey, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) diff --git a/management/server/sqlite_store.go b/management/server/sqlite_store.go index 2ed7066ed..63b5be047 100644 --- a/management/server/sqlite_store.go +++ b/management/server/sqlite_store.go @@ -127,23 +127,45 @@ func (s *SqliteStore) AcquireGlobalLock() (unlock func()) { return unlock } -func (s *SqliteStore) AcquireAccountLock(accountID string) (unlock func()) { +func (s *SqliteStore) AcquireAccountWriteLock(accountID string) (unlock func()) { startTime := time.Now() defer func() { duration := time.Since(startTime) - log.Debugf("AcquireAccountLock took %s", duration) + log.Debugf("AcquireAccountWriteLock took %s", duration) }() - log.Tracef("acquiring lock for account %s", accountID) + log.Tracef("acquiring write lock for account %s", accountID) start := time.Now() - value, _ := s.accountLocks.LoadOrStore(accountID, &sync.Mutex{}) - mtx := value.(*sync.Mutex) + value, _ := s.accountLocks.LoadOrStore(accountID, &sync.RWMutex{}) + mtx := value.(*sync.RWMutex) mtx.Lock() unlock = func() { mtx.Unlock() - log.Tracef("released lock for account %s in %v", accountID, time.Since(start)) + log.Tracef("released write lock for account %s in %v", accountID, time.Since(start)) + } + + return unlock +} + +func (s *SqliteStore) AcquireAccountReadLock(accountID string) (unlock func()) { + startTime := time.Now() + defer func() { + duration := time.Since(startTime) + log.Debugf("AcquireAccountReadLock took %s", duration) + }() + + log.Tracef("acquiring read lock for account %s", accountID) + + start := time.Now() + value, _ := s.accountLocks.LoadOrStore(accountID, &sync.RWMutex{}) + mtx := value.(*sync.RWMutex) + mtx.RLock() + + unlock = func() { + mtx.RUnlock() + log.Tracef("released read lock for account %s in %v", accountID, time.Since(start)) } return unlock diff --git a/management/server/store.go b/management/server/store.go index 26a1b8a7e..8674f1cf2 100644 --- a/management/server/store.go +++ b/management/server/store.go @@ -30,8 +30,10 @@ type Store interface { DeleteTokenID2UserIDIndex(tokenID string) error GetInstallationID() string SaveInstallationID(ID string) error - // AcquireAccountLock should attempt to acquire account lock and return a function that releases the lock - AcquireAccountLock(accountID string) func() + // AcquireAccountWriteLock should attempt to acquire account lock for write purposes and return a function that releases the lock + AcquireAccountWriteLock(accountID string) func() + // AcquireAccountReadLock should attempt to acquire account lock for read purposes and return a function that releases the lock + AcquireAccountReadLock(accountID string) func() // AcquireGlobalLock should attempt to acquire a global lock and return a function that releases the lock AcquireGlobalLock() func() SavePeerStatus(accountID, peerID string, status nbpeer.PeerStatus) error diff --git a/management/server/user.go b/management/server/user.go index 4ae13d101..6d1879285 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -210,7 +210,7 @@ func NewOwnerUser(id string) *User { // createServiceUser creates a new service user under the given account. func (am *DefaultAccountManager) createServiceUser(accountID string, initiatorUserID string, role UserRole, serviceUserName string, nonDeletable bool, autoGroups []string) (*UserInfo, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -266,7 +266,7 @@ func (am *DefaultAccountManager) CreateUser(accountID, userID string, user *User // inviteNewUser Invites a USer to a given account and creates reference in datastore func (am *DefaultAccountManager) inviteNewUser(accountID, userID string, invite *UserInfo) (*UserInfo, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if am.idpManager == nil { @@ -367,7 +367,7 @@ func (am *DefaultAccountManager) GetUser(claims jwtclaims.AuthorizationClaims) ( return nil, fmt.Errorf("failed to get account with token claims %v", err) } - unlock := am.Store.AcquireAccountLock(account.Id) + unlock := am.Store.AcquireAccountWriteLock(account.Id) defer unlock() account, err = am.Store.GetAccount(account.Id) @@ -400,7 +400,7 @@ func (am *DefaultAccountManager) GetUser(claims jwtclaims.AuthorizationClaims) ( // ListUsers returns lists of all users under the account. // It doesn't populate user information such as email or name. func (am *DefaultAccountManager) ListUsers(accountID string) ([]*User, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -427,7 +427,7 @@ func (am *DefaultAccountManager) DeleteUser(accountID, initiatorUserID string, t if initiatorUserID == targetUserID { return status.Errorf(status.InvalidArgument, "self deletion is not allowed") } - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -537,7 +537,7 @@ func (am *DefaultAccountManager) deleteUserPeers(initiatorUserID string, targetU // InviteUser resend invitations to users who haven't activated their accounts prior to the expiration period. func (am *DefaultAccountManager) InviteUser(accountID string, initiatorUserID string, targetUserID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if am.idpManager == nil { @@ -577,7 +577,7 @@ func (am *DefaultAccountManager) InviteUser(accountID string, initiatorUserID st // CreatePAT creates a new PAT for the given user func (am *DefaultAccountManager) CreatePAT(accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if tokenName == "" { @@ -627,7 +627,7 @@ func (am *DefaultAccountManager) CreatePAT(accountID string, initiatorUserID str // DeletePAT deletes a specific PAT from a user func (am *DefaultAccountManager) DeletePAT(accountID string, initiatorUserID string, targetUserID string, tokenID string) error { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -677,7 +677,7 @@ func (am *DefaultAccountManager) DeletePAT(accountID string, initiatorUserID str // GetPAT returns a specific PAT from a user func (am *DefaultAccountManager) GetPAT(accountID string, initiatorUserID string, targetUserID string, tokenID string) (*PersonalAccessToken, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -709,7 +709,7 @@ func (am *DefaultAccountManager) GetPAT(accountID string, initiatorUserID string // GetAllPATs returns all PATs for a user func (am *DefaultAccountManager) GetAllPATs(accountID string, initiatorUserID string, targetUserID string) ([]*PersonalAccessToken, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() account, err := am.Store.GetAccount(accountID) @@ -747,7 +747,7 @@ func (am *DefaultAccountManager) SaveUser(accountID, initiatorUserID string, upd // SaveOrAddUser updates the given user. If addIfNotExists is set to true it will add user when no exist // Only User.AutoGroups, User.Role, and User.Blocked fields are allowed to be updated for now. func (am *DefaultAccountManager) SaveOrAddUser(accountID, initiatorUserID string, update *User, addIfNotExists bool) (*UserInfo, error) { - unlock := am.Store.AcquireAccountLock(accountID) + unlock := am.Store.AcquireAccountWriteLock(accountID) defer unlock() if update == nil {