From: Michael Vrable Date: Tue, 1 Sep 2009 03:13:52 +0000 (-0700) Subject: Switch to refcounted strings for storing cached file blocks. X-Git-Url: http://git.vrable.net/?a=commitdiff_plain;h=d32328c00f54c2f6f4e6eeb8993d33d062e9477c;p=bluesky.git Switch to refcounted strings for storing cached file blocks. --- diff --git a/bluesky.h b/bluesky.h index c4bad9e..856dd75 100644 --- 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 --- 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 --- 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);