diff --git a/server/jetstream_api.go b/server/jetstream_api.go index 755f3305558..e81c78a41c1 100644 --- a/server/jetstream_api.go +++ b/server/jetstream_api.go @@ -4701,9 +4701,13 @@ func (s *Server) jsConsumerInfoRequest(sub *subscription, c *client, _ *Account, return } + // Since these could wait on the Raft group lock, don't do so under the JS lock. + ourID := cc.meta.ID() + groupLeader := cc.meta.GroupLeader() + groupCreated := cc.meta.Created() + js.mu.RLock() isLeader, sa, ca := cc.isLeader(), js.streamAssignment(acc.Name, streamName), js.consumerAssignment(acc.Name, streamName, consumerName) - ourID := cc.meta.ID() var rg *raftGroup var offline, isMember bool if ca != nil { @@ -4717,7 +4721,7 @@ func (s *Server) jsConsumerInfoRequest(sub *subscription, c *client, _ *Account, // Also capture if we think there is no meta leader. var isLeaderLess bool if !isLeader { - isLeaderLess = cc.meta.GroupLeader() == _EMPTY_ && time.Since(cc.meta.Created()) > lostQuorumIntervalDefault + isLeaderLess = groupLeader == _EMPTY_ && time.Since(groupCreated) > lostQuorumIntervalDefault } js.mu.RUnlock() diff --git a/server/jetstream_cluster.go b/server/jetstream_cluster.go index 59f1d9f9e4b..d0583a202cc 100644 --- a/server/jetstream_cluster.go +++ b/server/jetstream_cluster.go @@ -902,15 +902,17 @@ func (js *jetStream) server() *Server { // Will respond if we do not think we have a metacontroller leader. func (js *jetStream) isLeaderless() bool { js.mu.RLock() - defer js.mu.RUnlock() - cc := js.cluster if cc == nil || cc.meta == nil { + js.mu.RUnlock() return false } + meta := cc.meta + js.mu.RUnlock() + // If we don't have a leader. // Make sure we have been running for enough time. - if cc.meta.GroupLeader() == _EMPTY_ && time.Since(cc.meta.Created()) > lostQuorumIntervalDefault { + if meta.GroupLeader() == _EMPTY_ && time.Since(meta.Created()) > lostQuorumIntervalDefault { return true } return false @@ -922,21 +924,24 @@ func (js *jetStream) isGroupLeaderless(rg *raftGroup) bool { return false } js.mu.RLock() - defer js.mu.RUnlock() - cc := js.cluster + started := js.started // If we are not a member we can not say.. if cc.meta == nil { + js.mu.RUnlock() return false } if !rg.isMember(cc.meta.ID()) { + js.mu.RUnlock() return false } // Single peer groups always have a leader if we are here. if rg.node == nil { + js.mu.RUnlock() return false } + js.mu.RUnlock() // If we don't have a leader. if rg.node.GroupLeader() == _EMPTY_ { // Threshold for jetstream startup. @@ -944,7 +949,7 @@ func (js *jetStream) isGroupLeaderless(rg *raftGroup) bool { if rg.node.HadPreviousLeader() { // Make sure we have been running long enough to intelligently determine this. - if time.Since(js.started) > startupThreshold { + if time.Since(started) > startupThreshold { return true } } @@ -4487,10 +4492,11 @@ func (js *jetStream) processClusterCreateConsumer(ca *consumerAssignment, state } else { // If we are clustered update the known peers. js.mu.RLock() - if node := rg.node; node != nil { + node := rg.node + js.mu.RUnlock() + if node != nil { node.UpdateKnownPeers(ca.Group.Peers) } - js.mu.RUnlock() } // Check if we already have this consumer running. diff --git a/server/raft.go b/server/raft.go index 5a2ce2cdf4e..c1102937bfc 100644 --- a/server/raft.go +++ b/server/raft.go @@ -1674,14 +1674,12 @@ func (n *raft) ID() string { if n == nil { return _EMPTY_ } - n.RLock() - defer n.RUnlock() + // Lock not needed as n.id is never changed after creation. return n.id } func (n *raft) Group() string { - n.RLock() - defer n.RUnlock() + // Lock not needed as n.group is never changed after creation. return n.group } @@ -1741,8 +1739,7 @@ func (n *raft) QuitC() <-chan struct{} { return n.quit } func (n *raft) AppliedFloorC() <-chan struct{} { return n.aflrc } func (n *raft) Created() time.Time { - n.RLock() - defer n.RUnlock() + // Lock not needed as n.created is never changed after creation. return n.created }