From: Michael Vrable Date: Fri, 4 Sep 2009 22:10:22 +0000 (-0700) Subject: Add pluggable support for multiple storage backends. X-Git-Url: http://git.vrable.net/?p=bluesky.git;a=commitdiff_plain;h=a5a9eca66728d271a442125ac52098378c70cf42 Add pluggable support for multiple storage backends. --- diff --git a/bluesky/CMakeLists.txt b/bluesky/CMakeLists.txt index c4fe011..b21f468 100644 --- a/bluesky/CMakeLists.txt +++ b/bluesky/CMakeLists.txt @@ -1,6 +1,7 @@ link_directories(/home/mvrable/scratch/libs3-1.4/build/lib) -add_library(bluesky SHARED crypto.c dir.c file.c inode.c serialize.c store.c s3store.c) +add_library(bluesky SHARED + crypto.c dir.c file.c init.c inode.c serialize.c store.c s3store.c) add_executable(bluesky-test main.c) set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") diff --git a/bluesky/bluesky.h b/bluesky/bluesky.h index b250206..8980c98 100644 --- a/bluesky/bluesky.h +++ b/bluesky/bluesky.h @@ -16,7 +16,7 @@ extern "C" { #endif -struct S3Store; +void bluesky_init(void); /* Reference-counted blocks of memory, used for passing data in and out of * storage backends and in other places. */ @@ -40,6 +40,35 @@ void bluesky_crypt_random_bytes(guchar *buf, gint len); BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key); BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key); +/* Storage interface. This presents a key-value store abstraction, and can + * have multiple implementations: in-memory, on-disk, in-cloud. */ +typedef struct { + /* Create a new store instance and return a handle to it. */ + gpointer (*create)(); + + /* Clean up any resources used by this store. */ + void (*destroy)(gpointer store); + + /* Fetch an item with the given name, or return NULL if not found. */ + BlueSkyRCStr * (*get)(gpointer store, const gchar *key); + + /* Store an item to the given key name. */ + void (*put)(gpointer store, const gchar *key, BlueSkyRCStr *val); +} BlueSkyStoreImplementation; + +void bluesky_store_register(const BlueSkyStoreImplementation *impl, + const gchar *name); + +struct _BlueSkyStore; +typedef struct _BlueSkyStore BlueSkyStore; + +void bluesky_store_init(); +BlueSkyStore *bluesky_store_new(const gchar *type); +void bluesky_store_free(BlueSkyStore *store); +BlueSkyRCStr *bluesky_store_get(BlueSkyStore *store, const gchar *key); +void bluesky_store_put(BlueSkyStore *store, + const gchar *key, BlueSkyRCStr *val); + /* File types. The numeric values are chosen to match with those used in * NFSv3. */ typedef enum { @@ -61,7 +90,7 @@ typedef struct { GHashTable *inodes; /* Cached inodes */ uint64_t next_inum; /* Next available inode for allocation */ - struct S3Store *store; + BlueSkyStore *store; uint8_t *encryption_key; } BlueSkyFS; @@ -170,10 +199,6 @@ void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, void bluesky_file_read(BlueSkyInode *inode, uint64_t offset, char *buf, gint len); -struct S3Store *s3store_new(); -BlueSkyRCStr *s3store_get(struct S3Store *store, const gchar *key); -void s3store_put(struct S3Store *store, const gchar *key, BlueSkyRCStr *val); - #ifdef __cplusplus } #endif diff --git a/bluesky/file.c b/bluesky/file.c index 5a4fe9b..4badc75 100644 --- a/bluesky/file.c +++ b/bluesky/file.c @@ -154,7 +154,7 @@ void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block) return; g_print("Fetching block from %s\n", block->ref); - BlueSkyRCStr *string = s3store_get(fs->store, block->ref); + BlueSkyRCStr *string = bluesky_store_get(fs->store, block->ref); bluesky_string_unref(block->data); block->data = bluesky_crypt_decrypt(string, fs->encryption_key); @@ -176,7 +176,7 @@ void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) gchar *name = g_strdup(g_checksum_get_string(csum)); g_print("Flushing block as %s\n", name); - s3store_put(fs->store, name, data); + bluesky_store_put(fs->store, name, data); g_free(block->ref); block->ref = name; diff --git a/bluesky/init.c b/bluesky/init.c new file mode 100644 index 0000000..f12aae4 --- /dev/null +++ b/bluesky/init.c @@ -0,0 +1,28 @@ +/* Blue Sky: File Systems in the Cloud + * + * Copyright (C) 2009 The Regents of the University of California + * Written by Michael Vrable + * + * TODO: Licensing + */ + +#include +#include +#include +#include + +#include "bluesky.h" + +/* BlueSky library initialization. */ + +void bluesky_store_init_s3(void); + +/* Initialize the BlueSky library and dependent libraries. */ +void bluesky_init(void) +{ + g_thread_init(NULL); + bluesky_crypt_init(); + + bluesky_store_init(); + bluesky_store_init_s3(); +} diff --git a/bluesky/inode.c b/bluesky/inode.c index d7d6c92..d8b80cf 100644 --- a/bluesky/inode.c +++ b/bluesky/inode.c @@ -114,7 +114,7 @@ BlueSkyFS *bluesky_new_fs(gchar *name) fs->inodes = g_hash_table_new(bluesky_fs_key_hash_func, bluesky_fs_key_equal_func); fs->next_inum = BLUESKY_ROOT_INUM + 1; - fs->store = s3store_new(); + fs->store = bluesky_store_new("file"); return fs; } diff --git a/bluesky/s3store.c b/bluesky/s3store.c index 47a8f60..4602136 100644 --- a/bluesky/s3store.c +++ b/bluesky/s3store.c @@ -17,13 +17,13 @@ /* Interface to Amazon S3 storage. */ /* Simple in-memory data store for test purposes. */ -struct S3Store { +typedef struct { S3BucketContext bucket; -}; +} S3Store; -struct S3Store *s3store_new() +static gpointer s3store_new() { - struct S3Store *store = g_new(struct S3Store, 1); + S3Store *store = g_new(S3Store, 1); store->bucket.bucketName = "mvrable-bluesky"; store->bucket.protocol = S3ProtocolHTTP; store->bucket.uriStyle = S3UriStylePath; @@ -36,6 +36,11 @@ struct S3Store *s3store_new() return store; } +static void s3store_destroy(gpointer store) +{ + g_free(store); +} + struct get_info { gchar *buf; gint offset; @@ -73,7 +78,7 @@ static S3Status s3store_properties_callback(const S3ResponseProperties *properti return S3StatusOK; } -void s3store_response_callback(S3Status status, +static void s3store_response_callback(S3Status status, const S3ErrorDetails *errorDetails, void *callbackData) { @@ -84,8 +89,10 @@ void s3store_response_callback(S3Status status, } } -BlueSkyRCStr *s3store_get(struct S3Store *store, const gchar *key) +static BlueSkyRCStr *s3store_get(gpointer s, const gchar *key) { + S3Store *store = (S3Store *)s; + struct get_info info; info.buf = (char *)g_malloc0(BLUESKY_BLOCK_SIZE); info.offset = 0; @@ -102,8 +109,10 @@ BlueSkyRCStr *s3store_get(struct S3Store *store, const gchar *key) return bluesky_string_new(info.buf, BLUESKY_BLOCK_SIZE); } -void s3store_put(struct S3Store *store, const gchar *key, BlueSkyRCStr *val) +static void s3store_put(gpointer s, const gchar *key, BlueSkyRCStr *val) { + S3Store *store = (S3Store *)s; + struct put_info info; info.val = val; info.offset = 0; @@ -117,3 +126,16 @@ void s3store_put(struct S3Store *store, const gchar *key, BlueSkyRCStr *val) S3_put_object(&store->bucket, key, val->len, NULL, NULL, &handler, &info); } + +static BlueSkyStoreImplementation store_impl = { + .create = s3store_new, + .destroy = s3store_destroy, + .get = s3store_get, + .put = s3store_put, +}; + +void bluesky_store_init_s3(void) +{ + S3_initialize(NULL, S3_INIT_ALL); + bluesky_store_register(&store_impl, "s3"); +} diff --git a/bluesky/store.c b/bluesky/store.c index 9b509e6..abe7020 100644 --- a/bluesky/store.c +++ b/bluesky/store.c @@ -16,6 +16,54 @@ * interface, which different backends can implement. Available backends * (will) include Amazon S3 and a simple local store for testing purposes. */ +struct _BlueSkyStore { + const BlueSkyStoreImplementation *impl; + gpointer handle; +}; + +GHashTable *store_implementations; + +void bluesky_store_register(const BlueSkyStoreImplementation *impl, + const gchar *name) +{ + g_hash_table_insert(store_implementations, g_strdup(name), (gpointer)impl); +} + +BlueSkyStore *bluesky_store_new(const gchar *type) +{ + const BlueSkyStoreImplementation *impl; + + impl = g_hash_table_lookup(store_implementations, type); + if (impl == NULL) + return NULL; + + gpointer handle = impl->create(); + if (handle == NULL) + return NULL; + + BlueSkyStore *store = g_new(BlueSkyStore, 1); + store->impl = impl; + store->handle = handle; + return store; +} + +void bluesky_store_free(BlueSkyStore *store) +{ + store->impl->destroy(store->handle); + g_free(store); +} + +BlueSkyRCStr *bluesky_store_get(BlueSkyStore *store, const gchar *key) +{ + return store->impl->get(store->handle, key); +} + +void bluesky_store_put(BlueSkyStore *store, + const gchar *key, BlueSkyRCStr *val) +{ + store->impl->put(store->handle, key, val); +} + /* Create and return a new reference-counted string. The reference count is * initially one. The newly-returned string takes ownership of the memory * pointed at by data, and will call g_free on it when the reference count @@ -77,7 +125,7 @@ typedef struct { GHashTable *store; } MemStore; -MemStore *memstore_new() +static gpointer memstore_create() { MemStore *store = g_new(MemStore, 1); store->lock = g_mutex_new(); @@ -85,19 +133,75 @@ MemStore *memstore_new() g_free, (GDestroyNotify)bluesky_string_unref); - return store; + return (gpointer)store; } -BlueSkyRCStr *memstore_get(MemStore *store, const gchar *key) +static void memstore_destroy(gpointer store) { + /* TODO */ +} + +static BlueSkyRCStr *memstore_get(gpointer st, const gchar *key) +{ + MemStore *store = (MemStore *)st; BlueSkyRCStr *s = g_hash_table_lookup(store->store, key); if (s != NULL) bluesky_string_ref(s); return s; } -void memstore_put(MemStore *store, const gchar *key, BlueSkyRCStr *val) +static void memstore_put(gpointer s, const gchar *key, BlueSkyRCStr *val) { + MemStore *store = (MemStore *)s; bluesky_string_ref(val); g_hash_table_insert(store->store, g_strdup(key), val); } + +static BlueSkyStoreImplementation memstore_impl = { + .create = memstore_create, + .destroy = memstore_destroy, + .get = memstore_get, + .put = memstore_put, +}; + +/* Store implementation which writes data as files to disk. */ +static gpointer filestore_create() +{ + return GINT_TO_POINTER(1); +} + +static void filestore_destroy() +{ +} + +static BlueSkyRCStr *filestore_get(gpointer s, const gchar *key) +{ + gchar *contents = NULL; + gsize length; + GError *error; + + g_file_get_contents(key, &contents, &length, &error); + if (contents == NULL) + return NULL; + + return bluesky_string_new(contents, length); +} + +static void filestore_put(gpointer s, const gchar *key, BlueSkyRCStr *val) +{ + g_file_set_contents(key, val->data, val->len, NULL); +} + +static BlueSkyStoreImplementation filestore_impl = { + .create = filestore_create, + .destroy = filestore_destroy, + .get = filestore_get, + .put = filestore_put, +}; + +void bluesky_store_init() +{ + store_implementations = g_hash_table_new(g_str_hash, g_str_equal); + bluesky_store_register(&memstore_impl, "mem"); + bluesky_store_register(&filestore_impl, "file"); +} diff --git a/nfs3/nfsd.c b/nfs3/nfsd.c index f80b01a..8ba3ef0 100644 --- a/nfs3/nfsd.c +++ b/nfs3/nfsd.c @@ -30,8 +30,7 @@ static uint8_t filesystem_key[16]; int main(int argc, char *argv[]) { int i; - g_thread_init(NULL); - bluesky_crypt_init(); + bluesky_init(); register_rpc(); bluesky_crypt_random_bytes(filesystem_key, sizeof(filesystem_key)); @@ -41,8 +40,6 @@ int main(int argc, char *argv[]) } printf("\n"); - S3_initialize(NULL, S3_INIT_ALL); - fs = bluesky_new_fs("export"); fs->encryption_key = filesystem_key;