Optimize complete overwrites of file system blocks
authorMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 7 Mar 2011 00:22:30 +0000 (16:22 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 7 Mar 2011 00:22:30 +0000 (16:22 -0800)
Do not fetch the old data in this case, since it doesn't matter what it
was.

bluesky/bluesky-private.h
bluesky/file.c

index d4ec4cd..117f108 100644 (file)
@@ -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,
index 5c4b157..f10814a 100644 (file)
 /* 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);