Switch to refcounted strings for storing cached file blocks.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Tue, 1 Sep 2009 03:13:52 +0000 (20:13 -0700)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Tue, 1 Sep 2009 03:13:52 +0000 (20:13 -0700)
bluesky.h
inode.c
store.c

index c4bad9e..856dd75 100644 (file)
--- a/bluesky.h
+++ b/bluesky.h
@@ -22,7 +22,7 @@ struct S3Store;
  * storage backends and in other places. */
 typedef struct {
     gint refcount;
-    gpointer data;
+    gchar *data;
     gsize len;
 } BlueSkyRCStr;
 
@@ -123,7 +123,7 @@ typedef enum {
 typedef struct {
     BlueSkyBlockType type;
     gchar *ref;                 /* Name of data block in the backing store */
-    gchar *data;                /* Pointer to data in memory */
+    BlueSkyRCStr *data;         /* Pointer to data in memory if cached */
 } BlueSkyBlock;
 
 BlueSkyFS *bluesky_new_fs(gchar *name);
diff --git a/inode.c b/inode.c
index df3883b..7ea8dbf 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -193,14 +193,16 @@ void bluesky_block_touch(BlueSkyInode *inode, uint64_t i)
 
     switch (block->type) {
     case BLUESKY_BLOCK_ZERO:
-        block->data = g_malloc0(BLUESKY_BLOCK_SIZE);
+        block->data = bluesky_string_new(g_malloc0(BLUESKY_BLOCK_SIZE),
+                                         BLUESKY_BLOCK_SIZE);
         break;
     case BLUESKY_BLOCK_REF:
-        /* TODO: Pull in data first */
-        block->data = g_malloc0(BLUESKY_BLOCK_SIZE);
-        break;
+        bluesky_block_fetch(inode->fs, block);
+        g_assert(block->type == BLUESKY_BLOCK_CACHED);
+        /* Fall through */
     case BLUESKY_BLOCK_CACHED:
     case BLUESKY_BLOCK_DIRTY:
+        block->data = bluesky_string_dup(block->data);
         break;
     }
 
@@ -228,7 +230,7 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
         for (guint i = inode->blocks->len; i < blocks; i++) {
             BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
             g_free(b->ref);
-            g_free(b->data);
+            bluesky_string_unref(b->data);
         }
         g_array_set_size(inode->blocks, blocks);
     }
@@ -242,7 +244,7 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
             bluesky_block_touch(inode, blocks - 1);
             int end_offset = size % BLUESKY_BLOCK_SIZE;
             if (end_offset > 0) {
-                memset(&b->data[end_offset], 0,
+                memset(&b->data->data[end_offset], 0,
                        BLUESKY_BLOCK_SIZE - end_offset);
             }
         }
@@ -270,7 +272,7 @@ void bluesky_file_write(BlueSkyInode *inode, uint64_t offset,
         bluesky_block_touch(inode, block_num);
         BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
                                          block_num);
-        memcpy(&b->data[block_offset], data, bytes);
+        memcpy(&b->data->data[block_offset], data, bytes);
         bluesky_block_flush(inode->fs, b);
 
         offset += bytes;
@@ -304,7 +306,7 @@ void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
             /* Fall through */
         case BLUESKY_BLOCK_CACHED:
         case BLUESKY_BLOCK_DIRTY:
-            memcpy(buf, &b->data[block_offset], bytes);
+            memcpy(buf, &b->data->data[block_offset], bytes);
             break;
         }
 
@@ -324,10 +326,9 @@ void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block)
     g_print("Fetching block from %s\n", block->ref);
     BlueSkyRCStr *string = s3store_get(fs->store, block->ref);
 
-    g_free(block->data);
-    block->data = g_memdup(string->data, BLUESKY_BLOCK_SIZE);
+    bluesky_string_unref(block->data);
+    block->data = string;
     block->type = BLUESKY_BLOCK_CACHED;
-    bluesky_string_unref(string);
 }
 
 /* Write the given block to cloud-backed storage and mark it clean. */
@@ -336,24 +337,19 @@ void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block)
     if (block->type != BLUESKY_BLOCK_DIRTY)
         return;
 
-    BlueSkyRCStr *data = bluesky_string_new(g_memdup(block->data,
-                                                     BLUESKY_BLOCK_SIZE),
-                                            BLUESKY_BLOCK_SIZE);
-
     GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256);
-    g_checksum_update(csum, data->data, data->len);
-    const gchar *name = g_checksum_get_string(csum);
+    g_checksum_update(csum, block->data->data, block->data->len);
+    gchar *name = g_strdup(g_checksum_get_string(csum));
 
     g_print("Flushing block as %s\n", name);
-    s3store_put(fs->store, name, data);
+    s3store_put(fs->store, name, block->data);
     g_free(block->ref);
-    block->ref = g_strdup(name);
+    block->ref = name;
 
     /* block->type = BLUESKY_BLOCK_CACHED; */
-    g_free(block->data);
+    bluesky_string_unref(block->data);
     block->data = NULL;
     block->type = BLUESKY_BLOCK_REF;
 
     g_checksum_free(csum);
-    bluesky_string_unref(data);
 }
diff --git a/store.c b/store.c
index 63228b2..9b509e6 100644 (file)
--- a/store.c
+++ b/store.c
@@ -31,11 +31,17 @@ BlueSkyRCStr *bluesky_string_new(gpointer data, gsize len)
 
 void bluesky_string_ref(BlueSkyRCStr *string)
 {
+    if (string == NULL)
+        return;
+
     g_atomic_int_inc(&string->refcount);
 }
 
 void bluesky_string_unref(BlueSkyRCStr *string)
 {
+    if (string == NULL)
+        return;
+
     if (g_atomic_int_dec_and_test(&string->refcount)) {
         g_free(string->data);
         g_free(string);
@@ -45,9 +51,14 @@ void bluesky_string_unref(BlueSkyRCStr *string)
 /* Duplicate and return a new reference-counted string, containing a copy of
  * the original data, with a reference count of 1.  As an optimization, if the
  * passed-in string already has a reference count of 1, the original is
- * returned.   Can be used to make a mutable copy of a shared string. */
+ * returned.   Can be used to make a mutable copy of a shared string.  For this
+ * to truly be safe, it is probably needed that there be some type of lock
+ * protecting access to the string. */
 BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string)
 {
+    if (string == NULL)
+        return NULL;
+
     if (g_atomic_int_dec_and_test(&string->refcount)) {
         /* There are no other shared copies, so return this one. */
         g_atomic_int_inc(&string->refcount);