From 0fe9af2d15c4bc8dcd3413ace0c8e3f6dbe4b487 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 3 Apr 2008 23:58:38 +0000 Subject: [PATCH] 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. svn path=/trunk/; revision=1119 --- ChangeLog | 13 +++++++++ libsoup/soup-session-async.c | 47 ++++++++++++++++--------------- libsoup/soup-session.c | 66 +++++++++++++++++--------------------------- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 02f450a..47f78e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-04-03 Dan Winship + + 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 * libsoup/soup-message.h (SoupMessage): de-constify diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c index 2317cec..060b4cf 100644 --- a/libsoup/soup-session-async.c +++ b/libsoup/soup-session-async.c @@ -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 diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index d200b3c..c689900 100644 --- a/libsoup/soup-session.c +++ b/libsoup/soup-session.c @@ -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 -- 2.7.4