@@ -292,6 +292,27 @@ func (a *Account) nextEventID() string {
292292 return id
293293}
294294
295+ // Returns a slice of clients stored in the account, or nil if none is present.
296+ // Lock is held on entry.
297+ func (a * Account ) getClientsLocked () []* client {
298+ if len (a .clients ) == 0 {
299+ return nil
300+ }
301+ clients := make ([]* client , 0 , len (a .clients ))
302+ for c := range a .clients {
303+ clients = append (clients , c )
304+ }
305+ return clients
306+ }
307+
308+ // Returns a slice of clients stored in the account, or nil if none is present.
309+ func (a * Account ) getClients () []* client {
310+ a .mu .RLock ()
311+ clients := a .getClientsLocked ()
312+ a .mu .RUnlock ()
313+ return clients
314+ }
315+
295316// Called to track a remote server and connections and leafnodes it
296317// has for this account.
297318func (a * Account ) updateRemoteServer (m * AccountNumConns ) []* client {
@@ -312,10 +333,7 @@ func (a *Account) updateRemoteServer(m *AccountNumConns) []*client {
312333 // conservative and bit harsh here. Clients will reconnect if we over compensate.
313334 var clients []* client
314335 if mtce {
315- clients = make ([]* client , 0 , len (a .clients ))
316- for c := range a .clients {
317- clients = append (clients , c )
318- }
336+ clients := a .getClientsLocked ()
319337 sort .Slice (clients , func (i , j int ) bool {
320338 return clients [i ].start .After (clients [j ].start )
321339 })
@@ -670,9 +688,13 @@ func (a *Account) AddWeightedMappings(src string, dests ...*MapDest) error {
670688
671689 // If we have connected leafnodes make sure to update.
672690 if len (a .lleafs ) > 0 {
673- for _ , lc := range a .lleafs {
691+ leafs := append ([]* client (nil ), a .lleafs ... )
692+ // Need to release because lock ordering is client -> account
693+ a .mu .Unlock ()
694+ for _ , lc := range leafs {
674695 lc .forceAddToSmap (src )
675696 }
697+ a .mu .Lock ()
676698 }
677699 return nil
678700}
@@ -963,8 +985,6 @@ func (a *Account) addServiceExportWithResponseAndAccountPos(
963985 }
964986
965987 a .mu .Lock ()
966- defer a .mu .Unlock ()
967-
968988 if a .exports .services == nil {
969989 a .exports .services = make (map [string ]* serviceExport )
970990 }
@@ -981,15 +1001,24 @@ func (a *Account) addServiceExportWithResponseAndAccountPos(
9811001
9821002 if accounts != nil || accountPos > 0 {
9831003 if err := setExportAuth (& se .exportAuth , subject , accounts , accountPos ); err != nil {
1004+ a .mu .Unlock ()
9841005 return err
9851006 }
9861007 }
9871008 lrt := a .lowestServiceExportResponseTime ()
9881009 se .acc = a
9891010 se .respThresh = DEFAULT_SERVICE_EXPORT_RESPONSE_THRESHOLD
9901011 a .exports .services [subject ] = se
991- if nlrt := a .lowestServiceExportResponseTime (); nlrt != lrt {
992- a .updateAllClientsServiceExportResponseTime (nlrt )
1012+
1013+ var clients []* client
1014+ nlrt := a .lowestServiceExportResponseTime ()
1015+ if nlrt != lrt && len (a .clients ) > 0 {
1016+ clients = a .getClientsLocked ()
1017+ }
1018+ // Need to release because lock ordering is client -> Account
1019+ a .mu .Unlock ()
1020+ if len (clients ) > 0 {
1021+ updateAllClientsServiceExportResponseTime (clients , nlrt )
9931022 }
9941023 return nil
9951024}
@@ -1353,9 +1382,8 @@ func (a *Account) sendTrackingLatency(si *serviceImport, responder *client) bool
13531382
13541383// This will check to make sure our response lower threshold is set
13551384// properly in any clients doing rrTracking.
1356- // Lock should be held.
1357- func (a * Account ) updateAllClientsServiceExportResponseTime (lrt time.Duration ) {
1358- for c := range a .clients {
1385+ func updateAllClientsServiceExportResponseTime (clients []* client , lrt time.Duration ) {
1386+ for _ , c := range clients {
13591387 c .mu .Lock ()
13601388 if c .rrTracking != nil && lrt != c .rrTracking .lrt {
13611389 c .rrTracking .lrt = lrt
@@ -2234,18 +2262,27 @@ func (a *Account) ServiceExportResponseThreshold(export string) (time.Duration,
22342262// from a service export responder.
22352263func (a * Account ) SetServiceExportResponseThreshold (export string , maxTime time.Duration ) error {
22362264 a .mu .Lock ()
2237- defer a .mu .Unlock ()
22382265 if a .isClaimAccount () {
2266+ a .mu .Unlock ()
22392267 return fmt .Errorf ("claim based accounts can not be updated directly" )
22402268 }
22412269 lrt := a .lowestServiceExportResponseTime ()
22422270 se := a .getServiceExport (export )
22432271 if se == nil {
2272+ a .mu .Unlock ()
22442273 return fmt .Errorf ("no export defined for %q" , export )
22452274 }
22462275 se .respThresh = maxTime
2247- if nlrt := a .lowestServiceExportResponseTime (); nlrt != lrt {
2248- a .updateAllClientsServiceExportResponseTime (nlrt )
2276+
2277+ var clients []* client
2278+ nlrt := a .lowestServiceExportResponseTime ()
2279+ if nlrt != lrt && len (a .clients ) > 0 {
2280+ clients = a .getClientsLocked ()
2281+ }
2282+ // Need to release because lock ordering is client -> Account
2283+ a .mu .Unlock ()
2284+ if len (clients ) > 0 {
2285+ updateAllClientsServiceExportResponseTime (clients , nlrt )
22492286 }
22502287 return nil
22512288}
@@ -2569,10 +2606,7 @@ func (a *Account) streamActivationExpired(exportAcc *Account, subject string) {
25692606
25702607 a .mu .Lock ()
25712608 si .invalid = true
2572- clients := make ([]* client , 0 , len (a .clients ))
2573- for c := range a .clients {
2574- clients = append (clients , c )
2575- }
2609+ clients := a .getClientsLocked ()
25762610 awcsti := map [string ]struct {}{a .Name : {}}
25772611 a .mu .Unlock ()
25782612 for _ , c := range clients {
@@ -2779,13 +2813,7 @@ func (a *Account) expiredTimeout() {
27792813 a .mu .Unlock ()
27802814
27812815 // Collect the clients and expire them.
2782- cs := make ([]* client , 0 , len (a .clients ))
2783- a .mu .RLock ()
2784- for c := range a .clients {
2785- cs = append (cs , c )
2786- }
2787- a .mu .RUnlock ()
2788-
2816+ cs := a .getClients ()
27892817 for _ , c := range cs {
27902818 c .accountAuthExpired ()
27912819 }
@@ -3001,16 +3029,6 @@ func (s *Server) updateAccountClaimsWithRefresh(a *Account, ac *jwt.AccountClaim
30013029 s .registerSystemImports (a )
30023030 }
30033031
3004- gatherClients := func () []* client {
3005- a .mu .RLock ()
3006- clients := make ([]* client , 0 , len (a .clients ))
3007- for c := range a .clients {
3008- clients = append (clients , c )
3009- }
3010- a .mu .RUnlock ()
3011- return clients
3012- }
3013-
30143032 jsEnabled := s .JetStreamEnabled ()
30153033 if jsEnabled && a == s .SystemAccount () {
30163034 s .checkJetStreamExports ()
@@ -3144,7 +3162,7 @@ func (s *Server) updateAccountClaimsWithRefresh(a *Account, ac *jwt.AccountClaim
31443162 // Now let's apply any needed changes from import/export changes.
31453163 if ! a .checkStreamImportsEqual (old ) {
31463164 awcsti := map [string ]struct {}{a .Name : {}}
3147- for _ , c := range gatherClients () {
3165+ for _ , c := range a . getClients () {
31483166 c .processSubsOnConfigReload (awcsti )
31493167 }
31503168 }
@@ -3266,9 +3284,9 @@ func (s *Server) updateAccountClaimsWithRefresh(a *Account, ac *jwt.AccountClaim
32663284 }
32673285
32683286 a .updated = time .Now ().UTC ()
3287+ clients := a .getClientsLocked ()
32693288 a .mu .Unlock ()
32703289
3271- clients := gatherClients ()
32723290 // Sort if we are over the limit.
32733291 if a .MaxTotalConnectionsReached () {
32743292 sort .Slice (clients , func (i , j int ) bool {
0 commit comments