Avoid race by using conditional deep copy

Signed-off-by: Derek Collison <derek@nats.io>
This commit is contained in:
Derek Collison
2018-06-21 18:22:06 -07:00
parent 3f39c244e4
commit b7ece91825
3 changed files with 15 additions and 3 deletions

View File

@@ -908,7 +908,7 @@ func (c *client) processPing() {
// If there was a cluster update since this client was created,
// send an updated INFO protocol now.
if srv.lastCURLsUpdate >= c.start.UnixNano() {
c.sendInfo(c.generateClientInfoJSON(srv.info))
c.sendInfo(c.generateClientInfoJSON(srv.copyInfo()))
}
c.mu.Unlock()
srv.mu.Unlock()

View File

@@ -389,7 +389,7 @@ func (s *Server) sendAsyncInfoToClients() {
if c.opts.Protocol >= ClientProtoInfo && c.flags.isSet(firstPongSent) {
// sendInfo takes care of checking if the connection is still
// valid or not, so don't duplicate tests here.
c.sendInfo(c.generateClientInfoJSON(s.info))
c.sendInfo(c.generateClientInfoJSON(s.copyInfo()))
}
c.mu.Unlock()
}

View File

@@ -708,6 +708,18 @@ func (s *Server) HTTPHandler() http.Handler {
return s.httpHandler
}
// Perform a conditional deep copy due to reference nature of ClientConnectURLs.
// If updates are made to Info, this function should be consulted and updated.
// Assume lock is held.
func (s *Server) copyInfo() Info {
info := s.info
if info.ClientConnectURLs != nil {
info.ClientConnectURLs = make([]string, len(s.info.ClientConnectURLs))
copy(info.ClientConnectURLs, s.info.ClientConnectURLs)
}
return info
}
func (s *Server) createClient(conn net.Conn) *client {
// Snapshot server options.
opts := s.getOpts()
@@ -716,7 +728,7 @@ func (s *Server) createClient(conn net.Conn) *client {
// Grab JSON info string
s.mu.Lock()
info := s.info
info := s.copyInfo()
s.totalClients++
s.mu.Unlock()