From: Michael Vrable Date: Mon, 7 Mar 2011 00:22:30 +0000 (-0800) Subject: Optimize complete overwrites of file system blocks X-Git-Url: http://git.vrable.net/?p=bluesky.git;a=commitdiff_plain;h=5d183280ac0033ad534af598fea85fd802e14ffe Optimize complete overwrites of file system blocks Do not fetch the old data in this case, since it doesn't matter what it was. --- diff --git a/bluesky/bluesky-private.h b/bluesky/bluesky-private.h index d4ec4cd..117f108 100644 --- a/bluesky/bluesky-private.h +++ b/bluesky/bluesky-private.h @@ -198,7 +198,7 @@ void bluesky_store_add_barrier(BlueSkyStoreAsync *barrier, void bluesky_inode_start_sync(BlueSkyInode *inode); -void bluesky_block_touch(BlueSkyInode *inode, uint64_t i); +void bluesky_block_touch(BlueSkyInode *inode, uint64_t i, gboolean preserve); void bluesky_block_fetch(BlueSkyInode *inode, BlueSkyBlock *block, BlueSkyStoreAsync *barrier); void bluesky_block_flush(BlueSkyInode *inode, BlueSkyBlock *block, diff --git a/bluesky/file.c b/bluesky/file.c index 5c4b157..f10814a 100644 --- a/bluesky/file.c +++ b/bluesky/file.c @@ -16,8 +16,12 @@ /* Core filesystem: handling of regular files and caching of file data. */ /* Mark a given block dirty and make sure that data is faulted in so that it - * can be written to. */ -void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) + * can be written to. + * + * If preserve is set to false, this is a hint that the block is about to be + * entirely overwritten. In this case, a dirty block is made available but any + * prior contents might be lost. A value of preserve = TRUE is always safe. */ +void bluesky_block_touch(BlueSkyInode *inode, uint64_t i, gboolean preserve) { g_return_if_fail(i < inode->blocks->len); BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i); @@ -34,10 +38,14 @@ void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) block->dirty = bluesky_string_new(g_malloc0(block_len), block_len); break; case BLUESKY_BLOCK_REF: - // FIXME: locking on the cloudlog? - bluesky_block_fetch(inode, block, NULL); - bluesky_string_ref(block->ref->data); - block->dirty = bluesky_string_dup(block->ref->data); + if (preserve) { + // FIXME: locking on the cloudlog? + bluesky_block_fetch(inode, block, NULL); + bluesky_string_ref(block->ref->data); + block->dirty = bluesky_string_dup(block->ref->data); + } else { + block->dirty = bluesky_string_new(g_malloc0(block_len), block_len); + } break; case BLUESKY_BLOCK_DIRTY: block->dirty = bluesky_string_dup(block->dirty); @@ -82,7 +90,7 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) if (b->type != BLUESKY_BLOCK_ZERO && (b->type == BLUESKY_BLOCK_REF || b->dirty->len < BLUESKY_BLOCK_SIZE)) { - bluesky_block_touch(inode, inode->blocks->len - 1); + bluesky_block_touch(inode, inode->blocks->len - 1, TRUE); gsize old_size = b->dirty->len; bluesky_string_resize(b->dirty, BLUESKY_BLOCK_SIZE); memset(&b->dirty->data[old_size], 0, @@ -110,7 +118,7 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) blocks - 1); if (b->type != BLUESKY_BLOCK_ZERO) { - bluesky_block_touch(inode, blocks - 1); + bluesky_block_touch(inode, blocks - 1, TRUE); gsize old_size = b->dirty->len; gsize new_size = size - (blocks - 1) * BLUESKY_BLOCK_SIZE; @@ -137,13 +145,18 @@ void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, return; // TODO: Optimization: If we are entirely overwriting a block we don't need - // to fetch it frm storage first. + // to fetch it frm storage first. We don't yet handle the case where the + // partial last block of a file is entirely overwritten. while (len > 0) { uint64_t block_num = offset / BLUESKY_BLOCK_SIZE; gint block_offset = offset % BLUESKY_BLOCK_SIZE; gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len); - bluesky_block_touch(inode, block_num); + gboolean preserve = TRUE; + if (block_offset == 0 && bytes == BLUESKY_BLOCK_SIZE) { + preserve = FALSE; + } + bluesky_block_touch(inode, block_num, preserve); BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, block_num); memcpy(&b->dirty->data[block_offset], data, bytes);