Browse Source

Fix race condition in Client.mCleaner

This could result in HostClients being removed that were still in use.
Erik Dubbelboer 2 months ago
parent
commit
f7c354c760
1 changed files with 10 additions and 4 deletions
  1. 10 4
      client.go

+ 10 - 4
client.go

@@ -515,6 +515,10 @@ func (c *Client) Do(req *Request, resp *Response) error {
 			startCleaner = true
 		}
 	}
+
+	atomic.AddInt32(&hc.pendingClientRequests, 1)
+	defer atomic.AddInt32(&hc.pendingClientRequests, -1)
+
 	c.mLock.Unlock()
 
 	if startCleaner {
@@ -553,12 +557,10 @@ func (c *Client) mCleaner(m map[string]*HostClient) {
 		c.mLock.Lock()
 		for k, v := range m {
 			v.connsLock.Lock()
-			shouldRemove := v.connsCount == 0
-			v.connsLock.Unlock()
-
-			if shouldRemove {
+			if v.connsCount == 0 && atomic.LoadInt32(&v.pendingClientRequests) == 0 {
 				delete(m, k)
 			}
+			v.connsLock.Unlock()
 		}
 		if len(m) == 0 {
 			mustStop = true
@@ -783,6 +785,10 @@ type HostClient struct {
 
 	pendingRequests int32
 
+	// pendingClientRequests counts the number of requests that a Client is currently running using this HostClient.
+	// It will be incremented ealier than pendingRequests and will be used by Client to see if the HostClient is still in use.
+	pendingClientRequests int32
+
 	connsCleanerRun bool
 }