Add support for byterange requests in the storage layer.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Tue, 26 Oct 2010 16:27:56 +0000 (09:27 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Tue, 26 Oct 2010 16:27:56 +0000 (09:27 -0700)
bluesky/bluesky-private.h
bluesky/store-s3.c
bluesky/store.c

index 2598772..1574a54 100644 (file)
@@ -116,6 +116,14 @@ struct BlueSkyStoreAsync {
     gchar *key;                 /* Key to read/write */
     BlueSkyRCStr *data;         /* Data read/to write */
 
+    /* For range requests on reads: starting byte offset and length; len 0
+     * implies reading to the end of the object.  At completion, the backend
+     * should set range_done if a range read was made; if not set the entire
+     * object was read and the storage layer will select out just the
+     * appropriate bytes. */
+    size_t start, len;
+    gboolean range_done;
+
     int result;                 /* Result code; 0 for success. */
     struct BlueSkyNotifierList *notifiers;
     gint notifier_count;
index 4735de4..03f497b 100644 (file)
@@ -102,8 +102,9 @@ static void s3store_task(gpointer a, gpointer s)
         handler.responseHandler.completeCallback = s3store_response_callback;
         handler.getObjectDataCallback = s3store_get_handler;
 
-        S3_get_object(&store->bucket, async->key, NULL, 0, 0, NULL,
-                      &handler, &info);
+        S3_get_object(&store->bucket, async->key, NULL,
+                      async->start, async->len, NULL, &handler, &info);
+        async->range_done = TRUE;
 
         if (info.success) {
             async->data = bluesky_string_new_from_gstring(info.buf);
index c2bb95e..5d9dc43 100644 (file)
@@ -105,6 +105,8 @@ BlueSkyStoreAsync *bluesky_store_async_new(BlueSkyStore *store)
     async->op = STORE_OP_NONE;
     async->key = NULL;
     async->data = NULL;
+    async->start = async->len = 0;
+    async->range_done = FALSE;
     async->result = -1;
     async->notifiers = NULL;
     async->notifier_count = 0;
@@ -218,6 +220,29 @@ void bluesky_store_async_mark_complete(BlueSkyStoreAsync *async)
         g_mutex_unlock(async->store->lock);
     }
 
+    /* If the request was a range request but the backend read the entire
+     * object, select out the appropriate bytes. */
+    if (async->op == STORE_OP_GET
+            && !async->range_done
+            && async->result == 0
+            && async->data != NULL) {
+        if (async->start != 0 || async->len != 0) {
+            /* If the caller requesteda read outside the object, return an
+             * error. */
+            if (async->start + async->len > async->data->len) {
+                g_warning("Range request outside object boundaries!\n");
+                async->result = -1;
+            } else {
+                if (async->len == 0)
+                    async->len = async->data->len - async->start;
+                BlueSkyRCStr *newstr = bluesky_string_new(g_memdup(&async->data->data[async->start], async->len), async->len);
+                bluesky_string_unref(async->data);
+                async->data = newstr;
+                async->range_done = TRUE;
+            }
+        }
+    }
+
     async->status = ASYNC_COMPLETE;
     g_cond_broadcast(async->completion_cond);