Hello

Since my colleague Frank Meier is on vacations I continue the conversation
he startet 19th June 2014 (dead connections are not cleaned up on new
requests).
I just joined the mailing list, this is why I am not replying to the
original thread.

Frank sent a patch to fix the issue. Daniel Stenberg would like to merge
the patch but suggests to make sure the clean-up isn't done too often.

I am sending a second patch which makes sure that the clean-up is done
at most once per second.

I am also sending Frank's patch with the fixed code formatting issues.

diff --git a/lib/url.c b/lib/url.c
index 770b0cc..3630ac6 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2910,6 +2910,66 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
 }
 
 /*
+ * This function checks if given connection is dead and removes it from the
+ * connection cache if this is the case.
+ *
+ * Returns TRUE if the connection was dead and removed
+ */
+static bool RemoveConnectionIfDead(struct connectdata *check,
+    struct SessionHandle *data) {
+
+  size_t pipeLen = check->send_pipe->size + check->recv_pipe->size;
+  if(!pipeLen && !check->inuse) {
+    /* The check for a dead socket makes sense only if there are no
+     handles in pipeline and the connection isn't already marked in
+     use */
+    bool dead;
+    if(check->handler->protocol & CURLPROTO_RTSP)
+      /* RTSP is a special case due to RTP interleaving */
+      dead = Curl_rtsp_connisdead(check);
+    else
+      dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+
+    if(dead) {
+      check->data = data;
+      infof(data, "Connection %ld seems to be dead!\n", check->connection_id);
+
+      /* disconnect resources */
+      Curl_disconnect(check, /* dead_connection */TRUE);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/*
+ * Wrapper to use RemoveConnectionIfDead() function in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int RemoveConnectionIfDeadWrapper(struct connectdata *check,
+    void *param) {
+
+  struct SessionHandle* data = (struct SessionHandle*)param;
+
+  RemoveConnectionIfDead(check, data);
+
+  return 0; /* continue iteration */
+}
+
+
+/*
+ * This function scans the connection cache for half-open/dead connections,
+ * closes and removes them.
+ */
+static void CleanupDeadConnections(struct SessionHandle *data) {
+
+  Curl_conncache_foreach(data->state.conn_cache, data,
+                          RemoveConnectionIfDeadWrapper);
+}
+
+/*
  * Given one filled in connection struct (named needle), this function should
  * detect if there already is one that has all the significant details
  * exactly the same and thus should be used instead.
@@ -2973,29 +3033,10 @@ ConnectionExists(struct SessionHandle *data,
       check = curr->ptr;
       curr = curr->next;
 
-      pipeLen = check->send_pipe->size + check->recv_pipe->size;
-
-      if(!pipeLen && !check->inuse) {
-        /* The check for a dead socket makes sense only if there are no
-           handles in pipeline and the connection isn't already marked in
-           use */
-        bool dead;
-        if(check->handler->protocol & CURLPROTO_RTSP)
-          /* RTSP is a special case due to RTP interleaving */
-          dead = Curl_rtsp_connisdead(check);
-        else
-          dead = SocketIsDead(check->sock[FIRSTSOCKET]);
-
-        if(dead) {
-          check->data = data;
-          infof(data, "Connection %ld seems to be dead!\n",
-                check->connection_id);
+      if(RemoveConnectionIfDead(check, data))
+        continue;
 
-          /* disconnect resources */
-          Curl_disconnect(check, /* dead_connection */ TRUE);
-          continue;
-        }
-      }
+      pipeLen = check->send_pipe->size + check->recv_pipe->size;
 
       if(canPipeline) {
         /* Make sure the pipe has only GET requests */
@@ -5456,6 +5497,10 @@ static CURLcode create_conn(struct SessionHandle *data,
     goto out;
   }
 
+
+  CleanupDeadConnections(data);
+
+
   /*************************************************************
    * Check the current list of connections to see if we can
    * re-use an already existing one or if we have to create a
diff --git a/lib/conncache.h b/lib/conncache.h
index 691f061..96a0be0 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -26,6 +26,7 @@ struct conncache {
   struct curl_hash *hash;
   size_t num_connections;
   size_t next_connection_id;
+  struct timeval last_cleanup;
 };
 
 struct conncache *Curl_conncache_init(int size);
diff --git a/lib/url.c b/lib/url.c
index 3630ac6..8fdcf29 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2962,11 +2962,18 @@ static int RemoveConnectionIfDeadWrapper(struct connectdata *check,
 /*
  * This function scans the connection cache for half-open/dead connections,
  * closes and removes them.
+ * The cleanup is done at most once per second.
  */
 static void CleanupDeadConnections(struct SessionHandle *data) {
 
-  Curl_conncache_foreach(data->state.conn_cache, data,
-                          RemoveConnectionIfDeadWrapper);
+  struct timeval now = Curl_tvnow();
+  long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
+
+  if(elapsed >= 1000L) {
+    Curl_conncache_foreach(data->state.conn_cache, data,
+                            RemoveConnectionIfDeadWrapper);
+    data->state.conn_cache->last_cleanup = now;
+  }
 }
 
 /*
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to