X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Ffile.c;h=09e4805547a229d5b4884b54e2de21951e578405;hb=cb5c460ba6a31c27ac0d6803c33e9e6c5a140acd;hp=14de3724930c4535e6734558adb4a32babeb6678;hpb=54641cabe724241dc1a04b769e92a33ac99d640a;p=bluesky.git diff --git a/bluesky/file.c b/bluesky/file.c index 14de372..09e4805 100644 --- a/bluesky/file.c +++ b/bluesky/file.c @@ -9,8 +9,9 @@ #include #include #include +#include -#include "bluesky.h" +#include "bluesky-private.h" /* Core filesystem: handling of regular files and caching of file data. */ @@ -21,10 +22,17 @@ void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) g_return_if_fail(i < inode->blocks->len); BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i); + gsize block_len; + if (i < inode->blocks->len - 1) { + block_len = BLUESKY_BLOCK_SIZE; + } else { + block_len = inode->size - i * BLUESKY_BLOCK_SIZE; + } + switch (block->type) { case BLUESKY_BLOCK_ZERO: - block->data = bluesky_string_new(g_malloc0(BLUESKY_BLOCK_SIZE), - BLUESKY_BLOCK_SIZE); + g_print("Allocating zero block of size %zd\n", block_len); + block->data = bluesky_string_new(g_malloc0(block_len), block_len); break; case BLUESKY_BLOCK_REF: bluesky_block_fetch(inode->fs, block); @@ -48,12 +56,30 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) if (size == inode->size) return; + g_print("Truncating file to %"PRIi64" bytes\n", size); + uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE; if (blocks > inode->blocks->len) { /* Need to add new blocks to the end of a file. New block structures * are automatically zeroed, which initializes them to be pointers to - * zero blocks so we don't need to do any more work. */ + * zero blocks so we don't need to do any more work. If the + * previously-last block in the file is smaller than + * BLUESKY_BLOCK_SIZE, extend it to full size. */ + if (inode->blocks->len > 0) { + BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, + inode->blocks->len - 1); + + if (b->type != BLUESKY_BLOCK_ZERO + && b->data->len < BLUESKY_BLOCK_SIZE) { + bluesky_block_touch(inode, inode->blocks->len - 1); + gsize old_size = b->data->len; + bluesky_string_resize(b->data, BLUESKY_BLOCK_SIZE); + memset(&b->data->data[old_size], 0, + BLUESKY_BLOCK_SIZE - old_size); + } + } + g_array_set_size(inode->blocks, blocks); } else if (blocks < inode->blocks->len) { /* Delete blocks from a file. Must reclaim memory. */ @@ -65,17 +91,21 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) g_array_set_size(inode->blocks, blocks); } - /* If the file size is being decreased, ensure that any trailing data in - * the last block is zeroed. */ - if (size < inode->size) { + /* Ensure the new last block of the file is properly sized. If the block + * is extended, newly-added bytes must be zeroed. */ + if (blocks > 0) { BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, blocks - 1); + if (b->type != BLUESKY_BLOCK_ZERO) { bluesky_block_touch(inode, blocks - 1); - int end_offset = size % BLUESKY_BLOCK_SIZE; - if (end_offset > 0) { - memset(&b->data->data[end_offset], 0, - BLUESKY_BLOCK_SIZE - end_offset); + gsize old_size = b->data->len; + gsize new_size = size - (blocks - 1) * BLUESKY_BLOCK_SIZE; + + bluesky_string_resize(b->data, new_size); + + if (new_size > old_size) { + memset(&b->data->data[old_size], 0, new_size - old_size); } } } @@ -87,7 +117,8 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, const char *data, gint len) { - g_print("Start write: %ld\n", bluesky_now_hires()); + g_print("Write %d bytes at offset %"PRIi64"\n", len, offset); + g_return_if_fail(inode->type == BLUESKY_REGULAR); g_return_if_fail(offset < inode->size); g_return_if_fail(len <= inode->size - offset); @@ -104,7 +135,6 @@ void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, block_num); memcpy(&b->data->data[block_offset], data, bytes); - bluesky_block_flush(inode->fs, b); offset += bytes; data += bytes; @@ -112,13 +142,16 @@ void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, } bluesky_inode_update_ctime(inode, 1); - bluesky_inode_flush(inode->fs, inode); - g_print("End write: %ld\n", bluesky_now_hires()); } void bluesky_file_read(BlueSkyInode *inode, uint64_t offset, char *buf, gint len) { + g_print("Read %d bytes at offset %"PRIi64"\n", len, offset); + + if (len == 0 && offset <= inode->size) + return; + g_return_if_fail(inode->type == BLUESKY_REGULAR); g_return_if_fail(offset < inode->size); g_return_if_fail(len <= inode->size - offset); @@ -156,30 +189,38 @@ void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block) if (block->type != BLUESKY_BLOCK_REF) return; - g_print("Fetching block from %s\n", 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); + block->data = string; block->type = BLUESKY_BLOCK_CACHED; - bluesky_string_unref(string); } /* Write the given block to cloud-backed storage and mark it clean. */ -void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) +void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block, + BlueSkyStoreAsync *barrier) { if (block->type != BLUESKY_BLOCK_DIRTY) return; BlueSkyRCStr *data = block->data; - data = bluesky_crypt_encrypt(data, fs->encryption_key); GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256); - g_checksum_update(csum, data->data, data->len); + g_checksum_update(csum, (const guchar *)data->data, data->len); gchar *name = g_strdup(g_checksum_get_string(csum)); - g_print("Flushing block as %s\n", name); - bluesky_store_put(fs->store, name, data); + /* Store the file data asynchronously, and don't bother waiting for a + * response. */ + BlueSkyStoreAsync *async = bluesky_store_async_new(fs->store); + async->op = STORE_OP_PUT; + async->key = g_strdup(name); + bluesky_string_ref(data); + async->data = data; + bluesky_store_async_submit(async); + if (barrier != NULL) + bluesky_store_add_barrier(barrier, async); + bluesky_store_async_unref(async); + g_free(block->ref); block->ref = name; @@ -189,5 +230,16 @@ void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) block->type = BLUESKY_BLOCK_REF; g_checksum_free(csum); - bluesky_string_unref(data); + //bluesky_string_unref(data); +} + +/* Flush all blocks in a file to stable storage. */ +void bluesky_file_flush(BlueSkyInode *inode, BlueSkyStoreAsync *barrier) +{ + g_return_if_fail(inode->type == BLUESKY_REGULAR); + + for (int i = 0; i < inode->blocks->len; i++) { + BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i); + bluesky_block_flush(inode->fs, b, barrier); + } }