Be more aggressive about closing unused persistent connections
authorDan Winship <danw@src.gnome.org>
Thu, 3 Apr 2008 23:58:38 +0000 (23:58 +0000)
committerDan Winship <danw@src.gnome.org>
Thu, 3 Apr 2008 23:58:38 +0000 (23:58 +0000)
when needed, to avoid slow load times in WebKit.

* libsoup/soup-session-async.c (run_queue): Remove the
"try_pruning" flag from here and from all the callers, and
*always* try pruning idle connections if it would help.

* libsoup/soup-session.c (soup_session_try_prune_connection):
Rather than only closing a single connection, close all idle
connections.

svn path=/trunk/; revision=1119

ChangeLog
libsoup/soup-session-async.c
libsoup/soup-session.c

index 02f450a..47f78e7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2008-04-03  Dan Winship  <danw@gnome.org>
+
+       Be more aggressive about closing unused persistent connections
+       when needed, to avoid slow load times in WebKit.
+
+       * libsoup/soup-session-async.c (run_queue): Remove the
+       "try_pruning" flag from here and from all the callers, and
+       *always* try pruning idle connections if it would help.
+
+       * libsoup/soup-session.c (soup_session_try_prune_connection):
+       Rather than only closing a single connection, close all idle
+       connections.
+
 2008-03-29  Dan Winship  <danw@gnome.org>
 
        * libsoup/soup-message.h (SoupMessage): de-constify
index 2317cec..060b4cf 100644 (file)
@@ -23,7 +23,8 @@
  * single-threaded programs.
  **/
 
-static gboolean run_queue (SoupSessionAsync *sa, gboolean try_pruning);
+static gboolean run_queue (SoupSessionAsync *sa);
+static void do_idle_run_queue (SoupSession *session);
 
 static void  queue_message   (SoupSession *session, SoupMessage *req,
                              SoupSessionCallback callback, gpointer user_data);
@@ -85,12 +86,12 @@ soup_session_async_new_with_options (const char *optname1, ...)
 
 
 static void
-connection_closed (SoupConnection *conn, SoupSessionAsync *sa)
+connection_closed (SoupConnection *conn, gpointer session)
 {
        /* Run the queue in case anyone was waiting for a connection
         * to be closed.
         */
-       run_queue (sa, FALSE);
+       do_idle_run_queue (session);
 }
 
 static void
@@ -109,7 +110,7 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
                 * queue that were waiting for the connection count
                 * to go down, so run the queue now.
                 */
-               run_queue (sa, FALSE);
+               run_queue (sa);
                return;
        }
 
@@ -125,24 +126,25 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
         * idle pool and then just run the queue and see what happens.
         */
        soup_connection_release (conn);
-       run_queue (sa, FALSE);
+       run_queue (sa);
 }
 
 static gboolean
-run_queue (SoupSessionAsync *sa, gboolean try_pruning)
+run_queue (SoupSessionAsync *sa)
 {
        SoupSession *session = SOUP_SESSION (sa);
        SoupMessageQueue *queue = soup_session_get_queue (session);
        SoupMessageQueueIter iter;
        SoupMessage *msg;
        SoupConnection *conn;
-       gboolean should_prune = FALSE, started_any = FALSE, is_new;
+       gboolean try_pruning = TRUE, should_prune = FALSE;
+       gboolean started_any = FALSE, is_new;
 
        /* FIXME: prefer CONNECTING messages */
 
  try_again:
        for (msg = soup_message_queue_first (queue, &iter);
-            msg;
+            msg && !should_prune;
             msg = soup_message_queue_next (queue, &iter)) {
 
                if (!SOUP_MESSAGE_IS_STARTING (msg) ||
@@ -159,15 +161,12 @@ run_queue (SoupSessionAsync *sa, gboolean try_pruning)
                                                       session);
                } else
                        soup_connection_send_request (conn, msg);
-
-               started_any = TRUE;
        }
 
-       if (try_pruning && should_prune && !started_any) {
-               /* We didn't manage to start any message, but there is
-                * at least one message in the queue that could be
-                * sent if we pruned an idle connection from some
-                * other server.
+       if (try_pruning && should_prune) {
+               /* There is at least one message in the queue that
+                * could be sent if we pruned an idle connection from
+                * some other server.
                 */
                if (soup_session_try_prune_connection (session)) {
                        try_pruning = FALSE;
@@ -181,7 +180,7 @@ run_queue (SoupSessionAsync *sa, gboolean try_pruning)
 static void
 request_restarted (SoupMessage *req, gpointer sa)
 {
-       run_queue (sa, FALSE);
+       run_queue (sa);
 }
 
 typedef struct {
@@ -212,7 +211,7 @@ final_finished (SoupMessage *req, gpointer user_data)
 
        if (sa) {
                g_object_remove_weak_pointer (G_OBJECT (sa), (gpointer)&sa);
-               run_queue (sa, FALSE);
+               run_queue (sa);
        }
 }
 
@@ -226,12 +225,19 @@ idle_run_queue (gpointer user_data)
 
        if (sa) {
                g_object_remove_weak_pointer (G_OBJECT (sa), (gpointer)&sa);
-               run_queue (sa, TRUE);
+               run_queue (sa);
        }
        return FALSE;
 }
 
 static void
+do_idle_run_queue (SoupSession *session)
+{
+       soup_add_idle (soup_session_get_async_context (session),
+                      idle_run_queue, g_object_ref (session));
+}
+
+static void
 queue_message (SoupSession *session, SoupMessage *req,
               SoupSessionCallback callback, gpointer user_data)
 {
@@ -249,10 +255,7 @@ queue_message (SoupSession *session, SoupMessage *req,
                                G_CALLBACK (final_finished), saqd);
 
        SOUP_SESSION_CLASS (soup_session_async_parent_class)->queue_message (session, req, callback, user_data);
-
-       g_object_ref (sa);
-       soup_add_idle (soup_session_get_async_context (session),
-                      idle_run_queue, sa);
+       do_idle_run_queue (session);
 }
 
 static guint
index d200b3c..c689900 100644 (file)
@@ -808,55 +808,41 @@ connection_started_request (SoupConnection *conn, SoupMessage *msg,
                       msg, soup_connection_get_socket (conn));
 }
 
-static void
-find_oldest_connection (gpointer key, gpointer host, gpointer data)
-{
-       SoupConnection *conn = key, **oldest = data;
-
-       /* Don't prune a connection that is currently in use, or
-        * hasn't been used yet.
-        */
-       if (soup_connection_is_in_use (conn) ||
-           soup_connection_last_used (conn) == 0)
-               return;
-
-       if (!*oldest || (soup_connection_last_used (conn) <
-                        soup_connection_last_used (*oldest)))
-               *oldest = conn;
-}
-
-/**
- * soup_session_try_prune_connection:
- * @session: a #SoupSession
- *
- * Finds the least-recently-used idle connection in @session and closes
- * it.
- *
- * Return value: %TRUE if a connection was closed, %FALSE if there are
- * no idle connections.
- **/
 gboolean
 soup_session_try_prune_connection (SoupSession *session)
 {
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-       SoupConnection *oldest = NULL;
+       GPtrArray *conns;
+       GHashTableIter iter;
+       gpointer conn, host;
+       int i;
+
+       conns = g_ptr_array_new ();
 
        g_mutex_lock (priv->host_lock);
-       g_hash_table_foreach (priv->conns, find_oldest_connection,
-                             &oldest);
-       if (oldest) {
-               /* Ref the connection before unlocking the mutex in
-                * case someone else tries to prune it too.
+       g_hash_table_iter_init (&iter, priv->conns);
+       while (g_hash_table_iter_next (&iter, &conn, &host)) {
+               /* Don't prune a connection that is currently in use,
+                * or hasn't been used yet.
                 */
-               g_object_ref (oldest);
-               g_mutex_unlock (priv->host_lock);
-               soup_connection_disconnect (oldest);
-               g_object_unref (oldest);
-               return TRUE;
-       } else {
-               g_mutex_unlock (priv->host_lock);
+               if (!soup_connection_is_in_use (conn) &&
+                   soup_connection_last_used (conn) > 0)
+                       g_ptr_array_add (conns, g_object_ref (conn));
+       }
+       g_mutex_unlock (priv->host_lock);
+
+       if (!conns->len) {
+               g_ptr_array_free (conns, TRUE);
                return FALSE;
        }
+
+       for (i = 0; i < conns->len; i++) {
+               soup_connection_disconnect (conns->pdata[i]);
+               g_object_unref (conns->pdata[i]);
+       }
+       g_ptr_array_free (conns, TRUE);
+
+       return TRUE;
 }
 
 static void