[PATCH 06/12 v3] Btrfs: improve log with sub transaction

2011-06-21 Thread Liu Bo
When logging an inode _A_, current btrfs will
a) clear all items belonged to _A_ in log,
b) copy all items belonged to _A_ from fs/file tree to log tree,
and this just wastes a lot of time, especially when logging big files.

So we want to use a smarter approach, i.e. find and merge.
The amount of file extent items is the largest, so we focus on it.
Thanks to sub transaction, now we can find those file extent items which
are changed after last _transaction commit_ or last _log commit_, and
then merge them with the existed ones in log tree.

It will be great helpful on fsync performance, cause the common case is
make changes on a _part_ of inode.

Signed-off-by: Liu Bo liubo2...@cn.fujitsu.com
---
 fs/btrfs/tree-log.c |  179 ---
 1 files changed, 127 insertions(+), 52 deletions(-)

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index b91fe8b..6193e27 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -2581,61 +2581,106 @@ again:
 }
 
 /*
- * a helper function to drop items from the log before we relog an
- * inode.  max_key_type indicates the highest item type to remove.
- * This cannot be run for file data extents because it does not
- * free the extents they point to.
+ * a helper function to drop items from the log before we merge
+ * the uptodate items into the log tree.
  */
-static int drop_objectid_items(struct btrfs_trans_handle *trans,
- struct btrfs_root *log,
- struct btrfs_path *path,
- u64 objectid, int max_key_type)
+static  int prepare_for_merge_items(struct btrfs_trans_handle *trans,
+   struct inode *inode,
+   struct extent_buffer *eb,
+   int slot, int nr)
 {
-   int ret;
-   struct btrfs_key key;
+   struct btrfs_root *log = BTRFS_I(inode)-root-log_root;
+   struct btrfs_path *path;
struct btrfs_key found_key;
+   struct btrfs_key key;
+   int i;
+   int ret;
 
-   key.objectid = objectid;
-   key.type = max_key_type;
-   key.offset = (u64)-1;
+   /* There are no relative items of the inode in log. */
+   if (BTRFS_I(inode)-logged_trans  trans-transaction-transid)
+   return 0;
 
-   while (1) {
+   path = btrfs_alloc_path();
+   if (!path)
+   return -ENOMEM;
+
+   for (i = 0; i  nr; i++) {
+   btrfs_item_key_to_cpu(eb, key, i + slot);
+
+   if (btrfs_key_type(key) == BTRFS_EXTENT_DATA_KEY) {
+   struct btrfs_file_extent_item *fi;
+   int found_type;
+   u64 mask = BTRFS_I(inode)-root-sectorsize - 1;
+   u64 start = key.offset;
+   u64 extent_end;
+   u64 hint;
+   unsigned long size;
+
+   fi = btrfs_item_ptr(eb, slot + i,
+   struct btrfs_file_extent_item);
+   found_type = btrfs_file_extent_type(eb, fi);
+
+   if (found_type == BTRFS_FILE_EXTENT_REG ||
+   found_type == BTRFS_FILE_EXTENT_PREALLOC)
+   extent_end = start +
+   btrfs_file_extent_num_bytes(eb, fi);
+   else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
+   size = btrfs_file_extent_inline_len(eb, fi);
+   extent_end = (start + size + mask)  ~mask;
+   } else
+   BUG_ON(1);
+
+   /* drop any overlapping extents */
+   ret = btrfs_drop_extents(trans, inode, start,
+extent_end, hint, 0, 1);
+   BUG_ON(ret);
+
+   continue;
+   }
+
+   /* non file extent */
ret = btrfs_search_slot(trans, log, key, path, -1, 1);
-   BUG_ON(ret == 0);
if (ret  0)
break;
 
-   if (path-slots[0] == 0)
+   /* empty log! */
+   if (ret  0  path-slots[0] == 0)
break;
 
-   path-slots[0]--;
+   if (ret  0) {
+   btrfs_release_path(path);
+   continue;
+   }
+
btrfs_item_key_to_cpu(path-nodes[0], found_key,
  path-slots[0]);
 
-   if (found_key.objectid != objectid)
-   break;
+   if (btrfs_comp_cpu_keys(found_key, key))
+   BUG_ON(1);
 
ret = btrfs_del_item(trans, log, path);
-   if (ret)
-   break;
+   

Re: [PATCH 06/12 v3] Btrfs: improve log with sub transaction

2011-06-21 Thread Josef Bacik

On 06/21/2011 04:49 AM, Liu Bo wrote:

When logging an inode _A_, current btrfs will
a) clear all items belonged to _A_ in log,
b) copy all items belonged to _A_ from fs/file tree to log tree,
and this just wastes a lot of time, especially when logging big files.

So we want to use a smarter approach, i.e. find and merge.
The amount of file extent items is the largest, so we focus on it.
Thanks to sub transaction, now we can find those file extent items which
are changed after last _transaction commit_ or last _log commit_, and
then merge them with the existed ones in log tree.

It will be great helpful on fsync performance, cause the common case is
make changes on a _part_ of inode.

Signed-off-by: Liu Boliubo2...@cn.fujitsu.com
---
  fs/btrfs/tree-log.c |  179 ---
  1 files changed, 127 insertions(+), 52 deletions(-)

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index b91fe8b..6193e27 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -2581,61 +2581,106 @@ again:
  }

  /*
- * a helper function to drop items from the log before we relog an
- * inode.  max_key_type indicates the highest item type to remove.
- * This cannot be run for file data extents because it does not
- * free the extents they point to.
+ * a helper function to drop items from the log before we merge
+ * the uptodate items into the log tree.
   */
-static int drop_objectid_items(struct btrfs_trans_handle *trans,
- struct btrfs_root *log,
- struct btrfs_path *path,
- u64 objectid, int max_key_type)
+static  int prepare_for_merge_items(struct btrfs_trans_handle *trans,
+   struct inode *inode,
+   struct extent_buffer *eb,
+   int slot, int nr)
  {
-   int ret;
-   struct btrfs_key key;
+   struct btrfs_root *log = BTRFS_I(inode)-root-log_root;
+   struct btrfs_path *path;
struct btrfs_key found_key;
+   struct btrfs_key key;
+   int i;
+   int ret;

-   key.objectid = objectid;
-   key.type = max_key_type;
-   key.offset = (u64)-1;
+   /* There are no relative items of the inode in log. */
+   if (BTRFS_I(inode)-logged_trans  trans-transaction-transid)
+   return 0;

-   while (1) {
+   path = btrfs_alloc_path();
+   if (!path)
+   return -ENOMEM;
+
+   for (i = 0; i  nr; i++) {
+   btrfs_item_key_to_cpu(eb,key, i + slot);
+


Just a nit, but it would be less of a pain to do

for (i = slot; i  slot+nr; i++)

that way you don't have a bunch of getter(eb, slot + i) things scattered 
around.



+   if (btrfs_key_type(key) == BTRFS_EXTENT_DATA_KEY) {
+   struct btrfs_file_extent_item *fi;
+   int found_type;
+   u64 mask = BTRFS_I(inode)-root-sectorsize - 1;
+   u64 start = key.offset;
+   u64 extent_end;
+   u64 hint;
+   unsigned long size;
+
+   fi = btrfs_item_ptr(eb, slot + i,
+   struct btrfs_file_extent_item);
+   found_type = btrfs_file_extent_type(eb, fi);
+
+   if (found_type == BTRFS_FILE_EXTENT_REG ||
+   found_type == BTRFS_FILE_EXTENT_PREALLOC)
+   extent_end = start +
+   btrfs_file_extent_num_bytes(eb, fi);
+   else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
+   size = btrfs_file_extent_inline_len(eb, fi);
+   extent_end = (start + size + mask)  ~mask;
+   } else
+   BUG_ON(1);
+


Style screw up, if one chunk of an if/else block has braces, they all 
need it.



+   /* drop any overlapping extents */
+   ret = btrfs_drop_extents(trans, inode, start,
+extent_end,hint, 0, 1);


There are lot's of places where you've missed a space, like here where 
you have extent_end,hint



+   BUG_ON(ret);
+
+   continue;
+   }
+
+   /* non file extent */
ret = btrfs_search_slot(trans, log,key, path, -1, 1);
-   BUG_ON(ret == 0);
if (ret  0)
break;

-   if (path-slots[0] == 0)
+   /* empty log! */
+   if (ret  0  path-slots[0] == 0)


Here too.


break;

-   path-slots[0]--;
+   if (ret  0) {


Here.


+   btrfs_release_path(path);
+   continue;
+   }
+