Add a CURL connection pool to the Azure backend.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 25 Feb 2011 00:52:46 +0000 (16:52 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 25 Feb 2011 00:52:46 +0000 (16:52 -0800)
This will allow HTTP connections to be re-used.

bluesky/store-azure.c

index 176d38b..00ff481 100644 (file)
@@ -29,13 +29,46 @@ static const char *signature_headers[] = {
 /* Prototype Windows Azure backend for BlueSky.  This is intended to be
  * minimally functional, but could use additional work for production use. */
 
+#define MAX_IDLE_CONNECTIONS 8
+
 typedef struct {
     GThreadPool *thread_pool;
     char *account, *container;
     uint8_t *key;
     size_t key_len;
+
+    /* A pool of available idle connections that could be used. */
+    GQueue *curl_pool;
+    GMutex *curl_pool_lock;
 } AzureStore;
 
+static CURL *get_connection(AzureStore *store)
+{
+    CURL *curl = NULL;
+
+    g_mutex_lock(store->curl_pool_lock);
+    if (!g_queue_is_empty(store->curl_pool)) {
+        curl = (CURL *)(g_queue_pop_head(store->curl_pool));
+    }
+    g_mutex_unlock(store->curl_pool_lock);
+
+    if (curl == NULL)
+        curl = curl_easy_init();
+
+    return curl;
+}
+
+static void put_connection(AzureStore *store, CURL *curl)
+{
+    g_mutex_lock(store->curl_pool_lock);
+    g_queue_push_head(store->curl_pool, curl);
+    while (g_queue_get_length(store->curl_pool) > MAX_IDLE_CONNECTIONS) {
+        curl = (CURL *)(g_queue_pop_tail(store->curl_pool));
+        curl_easy_cleanup(curl);
+    }
+    g_mutex_unlock(store->curl_pool_lock);
+}
+
 static void get_extra_headers(gchar *key, gchar *value, GList **headers)
 {
     key = g_ascii_strdown(key, strlen(key));
@@ -151,6 +184,7 @@ static void azure_compute_signature(AzureStore *store,
  * sent.  This will compute an Azure authentication signature before sending
  * the request. */
 static BlueSkyRCStr *submit_request(AzureStore *store,
+                                    CURL *curl,
                                     const char *method,
                                     const char *path,
                                     GHashTable *headers,
@@ -177,7 +211,6 @@ static BlueSkyRCStr *submit_request(AzureStore *store,
     azure_compute_signature(store, headers, method, path);
 
     CURLcode status;
-    CURL *curl = curl_easy_init();
 
 #define curl_easy_setopt_safe(opt, val)                                     \
     if ((status = curl_easy_setopt(curl, (opt), (val))) != CURLE_OK) {      \
@@ -247,7 +280,7 @@ static BlueSkyRCStr *submit_request(AzureStore *store,
 cleanup:
     if (result != NULL && result_body != NULL)
         g_string_free(result_body, TRUE);
-    curl_easy_cleanup(curl);
+    curl_easy_reset(curl);
     curl_slist_free_all(curl_headers);
     g_free(uri);
 
@@ -266,6 +299,7 @@ static void azurestore_task(gpointer a, gpointer s)
                                                 g_free, g_free);
 
     BlueSkyRCStr *result = NULL;
+    CURL *curl = get_connection(store);
 
     if (async->op == STORE_OP_GET) {
         /* FIXME: We ought to check that the response returned the requested
@@ -282,7 +316,7 @@ static void azurestore_task(gpointer a, gpointer s)
                                 g_strdup_printf("%zd-", async->start));
             async->range_done = TRUE;
         }
-        result = submit_request(store, "GET", async->key, headers, NULL);
+        result = submit_request(store, curl, "GET", async->key, headers, NULL);
         if (result != NULL) {
             async->data = result;
             async->result = 0;
@@ -294,7 +328,7 @@ static void azurestore_task(gpointer a, gpointer s)
         g_hash_table_insert(headers,
                             g_strdup("Transfer-Encoding"),
                             g_strdup(""));
-        result = submit_request(store, "PUT", async->key,
+        result = submit_request(store, curl, "PUT", async->key,
                                 headers, async->data);
         if (result != NULL) {
             async->result = 0;
@@ -305,6 +339,7 @@ static void azurestore_task(gpointer a, gpointer s)
     bluesky_store_async_mark_complete(async);
     bluesky_store_async_unref(async);
     g_hash_table_unref(headers);
+    put_connection(store, curl);
 }
 
 static gpointer azurestore_new(const gchar *path)
@@ -325,6 +360,9 @@ static gpointer azurestore_new(const gchar *path)
     g_print("Initializing Azure with account %s, container %s\n",
             store->account, store->container);
 
+    store->curl_pool = g_queue_new();
+    store->curl_pool_lock = g_mutex_new();
+
     return store;
 }