DEBUG=-g
CFLAGS=-O -std=gnu99 -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
$(shell pkg-config --cflags $(PACKAGES))
+CXXFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
+ $(shell pkg-config --cflags $(PACKAGES))
LDFLAGS=$(DEBUG) $(shell pkg-config --libs $(PACKAGES))
SUBDIRS=nfs3
SRCS=dir.c inode.c store.c
-OBJS=$(SRCS:.c=.o)
+OBJS=$(SRCS:.c=.o) s3store.o
all : bluesky
for d in $(SUBDIRS); do $(MAKE) -C $$d; done
ranlib $@
bluesky : main.o bluesky.a
- $(CC) $(LDFLAGS) -o $@ $^ -Wl,-rpath=$(LIBS3_PATH)/lib -L$(LIBS3_PATH)/lib -ls3
+ $(CXX) $(LDFLAGS) -o $@ $^ -Wl,-rpath=$(LIBS3_PATH)/lib -L$(LIBS3_PATH)/lib -ls3
clean :
rm -f $(OBJS) bluesky
#include <stdint.h>
#include <glib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct S3Store;
+
/* Reference-counted blocks of memory, used for passing data in and out of
* storage backends and in other places. */
typedef struct {
gchar *name; /* Descriptive name for the filesystem */
GHashTable *inodes; /* Cached inodes */
uint64_t next_inum; /* Next available inode for allocation */
+
+ struct S3Store *store;
} BlueSkyFS;
/* Inode number of the root directory. */
gint refcnt; /* May be accessed atomically without lock */
GMutex *lock;
+ BlueSkyFS *fs;
+
BlueSkyFileType type;
uint32_t mode;
uint32_t uid, gid;
int64_t bluesky_get_current_time();
void bluesky_inode_update_ctime(BlueSkyInode *inode, gboolean update_mtime);
uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs);
-BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFileType type);
+BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFS *fs, BlueSkyFileType type);
BlueSkyInode *bluesky_get_inode(BlueSkyFS *fs, uint64_t inum);
void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode);
void bluesky_directory_dump(BlueSkyInode *dir);
void bluesky_block_touch(BlueSkyInode *inode, uint64_t i);
-void bluesky_block_flush(BlueSkyBlock *block);
+void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block);
void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size);
void bluesky_file_write(BlueSkyInode *inode, uint64_t offset,
const char *data, gint len);
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
+
#endif
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();
return fs;
}
return inum;
}
-BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFileType type)
+BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFS *fs,
+ BlueSkyFileType type)
{
BlueSkyInode *i = g_new0(BlueSkyInode, 1);
i->lock = g_mutex_new();
i->type = type;
+ i->fs = fs;
i->inum = inum;
switch (type) {
BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
block_num);
memcpy(&b->data[block_offset], data, bytes);
- bluesky_block_flush(b);
+ bluesky_block_flush(inode->fs, b);
offset += bytes;
data += bytes;
}
/* Write the given block to cloud-backed storage and mark it clean. */
-void bluesky_block_flush(BlueSkyBlock *block)
+void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block)
{
if (block->type != BLUESKY_BLOCK_DIRTY)
return;
const gchar *name = g_checksum_get_string(csum);
g_print("Flushing block as %s\n", name);
- //memstore_put(store, name, data);
+ s3store_put(fs->store, name, data);
g_free(block->ref);
block->ref = g_strdup(name);
block->type = BLUESKY_BLOCK_CACHED;
BlueSkyFS *fs = bluesky_new_fs("export");
BlueSkyInode *root;
- root = bluesky_new_inode(BLUESKY_ROOT_INUM, BLUESKY_DIRECTORY);
+ root = bluesky_new_inode(BLUESKY_ROOT_INUM, fs, BLUESKY_DIRECTORY);
root->nlink = 1;
root->mode = 0755;
bluesky_insert_inode(fs, root);
BlueSkyInode *file;
- file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), BLUESKY_REGULAR);
+ file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
file->nlink = 1;
file->mode = 0755;
bluesky_insert_inode(fs, file);
bluesky_directory_insert(root, "foo", file->inum);
- file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), BLUESKY_REGULAR);
+ file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
file->nlink = 1;
file->mode = 0755;
bluesky_insert_inode(fs, file);
bluesky_directory_insert(root, "bar", file->inum);
- file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), BLUESKY_REGULAR);
+ file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
file->nlink = 1;
file->mode = 0755;
bluesky_insert_inode(fs, file);
OBJS=$(SRCS:.c=.o)
nfsproxy : $(OBJS)
- $(CC) $(LDFLAGS) -o $@ $^ ../bluesky.a -Wl,-rpath=$(LIBS3_PATH)/lib -L$(LIBS3_PATH)/lib -ls3
+ $(CXX) $(LDFLAGS) -o $@ $^ ../bluesky.a -Wl,-rpath=$(LIBS3_PATH)/lib -L$(LIBS3_PATH)/lib -ls3
clean :
rm -f $(OBJS) nfsproxy
}
BlueSkyInode *file;
- file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), BLUESKY_REGULAR);
+ file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
file->nlink = 1;
file->mode = 0755;
int64_t time = bluesky_get_current_time();
fs = bluesky_new_fs("export");
BlueSkyInode *root;
- root = bluesky_new_inode(BLUESKY_ROOT_INUM, BLUESKY_DIRECTORY);
+ root = bluesky_new_inode(BLUESKY_ROOT_INUM, fs, BLUESKY_DIRECTORY);
root->nlink = 1;
root->mode = 0755;
bluesky_insert_inode(fs, root);
BlueSkyInode *file;
- file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), BLUESKY_REGULAR);
+ file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
file->nlink = 1;
file->mode = 0755;
bluesky_insert_inode(fs, file);
--- /dev/null
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2009 The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+
+#include "bluesky.h"
+#include "libs3.h"
+
+/* Interface to Amazon S3 storage. */
+
+/* Simple in-memory data store for test purposes. */
+struct S3Store {
+ S3BucketContext bucket;
+};
+
+S3Store *s3store_new()
+{
+ S3Store *store = g_new(S3Store, 1);
+ store->bucket.bucketName = "mvrable-bluesky";
+ store->bucket.protocol = S3ProtocolHTTP;
+ store->bucket.uriStyle = S3UriStylePath;
+ store->bucket.accessKeyId = getenv("AWS_ACCESS_KEY_ID");
+ store->bucket.secretAccessKey = getenv("AWS_SECRET_ACCESS_KEY");
+
+ g_print("Initializing S3 with bucket %s, access key %s\n",
+ store->bucket.bucketName, store->bucket.accessKeyId);
+
+ return store;
+}
+
+BlueSkyRCStr *s3store_get(S3Store *store, const gchar *key)
+{
+ return NULL;
+}
+
+struct put_info {
+ BlueSkyRCStr *val;
+ gint offset;
+};
+
+static int s3store_put_handler(int bufferSize, char *buffer,
+ void *callbackData)
+{
+ struct put_info *info = (struct put_info *)callbackData;
+ gint bytes = MIN(bufferSize, (int)(info->val->len - info->offset));
+ memcpy(buffer, (char *)info->val->data + info->offset, bytes);
+ info->offset += bytes;
+ return bytes;
+}
+
+static S3Status s3store_properties_callback(const S3ResponseProperties *properties,
+ void *callbackData)
+{
+ g_print("(Properties callback)\n");
+ return S3StatusOK;
+}
+
+void s3store_response_callback(S3Status status,
+ const S3ErrorDetails *errorDetails,
+ void *callbackData)
+{
+ g_print("S3 operation complete, status=%s\n",
+ S3_get_status_name(status));
+ if (errorDetails != NULL) {
+ g_print(" Error message: %s\n", errorDetails->message);
+ }
+}
+
+void s3store_put(S3Store *store, const gchar *key, BlueSkyRCStr *val)
+{
+ struct put_info info;
+ info.val = val;
+ info.offset = 0;
+
+ struct S3PutObjectHandler handler;
+ handler.responseHandler.propertiesCallback = s3store_properties_callback;
+ handler.responseHandler.completeCallback = s3store_response_callback;
+ handler.putObjectDataCallback = s3store_put_handler;
+
+ g_print("Starting store of %s to S3...\n", key);
+ S3_put_object(&store->bucket, key, val->len, NULL, NULL,
+ &handler, &info);
+}
--- /dev/null
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2009 The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdint.h>
+#include <glib.h>
+#include <string.h>
+
+#include "bluesky.h"
+
+/* Interaction with cloud storage. We expose very simple GET/PUT style
+ * interface, which different backends can implement. Available backends
+ * (will) include Amazon S3 and a simple local store for testing purposes. */
+
+/* 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
+ * drops to zero. */
+BlueSkyRCStr *bluesky_string_new(gpointer data, gsize len)
+{
+ BlueSkyRCStr *string = g_new(BlueSkyRCStr, 1);
+ string->data = data;
+ string->len = len;
+ g_atomic_int_set(&string->refcount, 1);
+ return string;
+}
+
+void bluesky_string_ref(BlueSkyRCStr *string)
+{
+ g_atomic_int_inc(&string->refcount);
+}
+
+void bluesky_string_unref(BlueSkyRCStr *string)
+{
+ if (g_atomic_int_dec_and_test(&string->refcount)) {
+ g_free(string->data);
+ g_free(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. */
+BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string)
+{
+ 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);
+ return string;
+ } else {
+ return bluesky_string_new(g_memdup(string->data, string->len),
+ string->len);
+ }
+}
+
+/* Simple in-memory data store for test purposes. */
+typedef struct {
+ GMutex *lock;
+
+ /* TODO: A hashtable isn't optimal for list queries... */
+ GHashTable *store;
+} MemStore;
+
+MemStore *memstore_new()
+{
+ MemStore *store = g_new(MemStore, 1);
+ store->lock = g_mutex_new();
+ store->store = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free,
+ (GDestroyNotify)bluesky_string_unref);
+
+ return store;
+}
+
+BlueSkyRCStr *memstore_get(MemStore *store, const gchar *key)
+{
+ 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)
+{
+ bluesky_string_ref(val);
+ g_hash_table_insert(store->store, g_strdup(key), val);
+}