Commit eb653de1 authored by Filipe David Borba Manana's avatar Filipe David Borba Manana Committed by Chris Mason

Btrfs: reduce btree node locking duration on item update

If we do a btree search with the goal of updating an existing item
without changing its size (ins_len == 0 and cow == 1), then we never
need to hold locks on upper level nodes (even when slot == 0) after we
COW their child nodes/leaves, as we won't have node splits or merges
in this scenario (that is, no key additions, removals or shifts on any
nodes or leaves).

Therefore release the locks immediately after COWing the child nodes/leaves
while navigating the btree, even if their parent slot is 0, instead of
returning a path to the caller with those nodes locked, which would get
released only when the caller releases or frees the path (or if it calls
btrfs_unlock_up_safe).

This is a common scenario, for example when updating inode items in fs
trees and block group items in the extent tree.

The following benchmarks were performed on a quad core machine with 32Gb
of ram, using a leaf/node size of 4Kb (to generate deeper fs trees more
quickly).

  sysbench --test=fileio --file-num=131072 --file-total-size=8G \
    --file-test-mode=seqwr --num-threads=512 --file-block-size=8192 \
    --max-requests=100000 --file-io-mode=sync [prepare|run]

Before this change:  49.85Mb/s (average of 5 runs)
After this change:   50.38Mb/s (average of 5 runs)
Signed-off-by: default avatarFilipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fb.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent eb8052e0
...@@ -2731,6 +2731,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2731,6 +2731,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
lowest_level = p->lowest_level; lowest_level = p->lowest_level;
WARN_ON(lowest_level && ins_len > 0); WARN_ON(lowest_level && ins_len > 0);
WARN_ON(p->nodes[0] != NULL); WARN_ON(p->nodes[0] != NULL);
BUG_ON(!cow && ins_len);
if (ins_len < 0) { if (ins_len < 0) {
lowest_unlock = 2; lowest_unlock = 2;
...@@ -2839,8 +2840,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2839,8 +2840,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
} }
} }
cow_done: cow_done:
BUG_ON(!cow && ins_len);
p->nodes[level] = b; p->nodes[level] = b;
btrfs_clear_path_blocking(p, NULL, 0); btrfs_clear_path_blocking(p, NULL, 0);
...@@ -2850,13 +2849,19 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2850,13 +2849,19 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
* It is safe to drop the lock on our parent before we * It is safe to drop the lock on our parent before we
* go through the expensive btree search on b. * go through the expensive btree search on b.
* *
* If cow is true, then we might be changing slot zero, * If we're inserting or deleting (ins_len != 0), then we might
* which may require changing the parent. So, we can't * be changing slot zero, which may require changing the parent.
* drop the lock until after we know which slot we're * So, we can't drop the lock until after we know which slot
* operating on. * we're operating on.
*/ */
if (!cow) if (!ins_len && !p->keep_locks) {
btrfs_unlock_up_safe(p, level + 1); int u = level + 1;
if (u < BTRFS_MAX_LEVEL && p->locks[u]) {
btrfs_tree_unlock_rw(p->nodes[u], p->locks[u]);
p->locks[u] = 0;
}
}
ret = key_search(b, key, level, &prev_cmp, &slot); ret = key_search(b, key, level, &prev_cmp, &slot);
...@@ -2884,7 +2889,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2884,7 +2889,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
* which means we must have a write lock * which means we must have a write lock
* on the parent * on the parent
*/ */
if (slot == 0 && cow && if (slot == 0 && ins_len &&
write_lock_level < level + 1) { write_lock_level < level + 1) {
write_lock_level = level + 1; write_lock_level = level + 1;
btrfs_release_path(p); btrfs_release_path(p);
......
...@@ -3515,7 +3515,6 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans, ...@@ -3515,7 +3515,6 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
goto failed; goto failed;
} }
btrfs_unlock_up_safe(path, 1);
leaf = path->nodes[0]; leaf = path->nodes[0];
inode_item = btrfs_item_ptr(leaf, path->slots[0], inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item); struct btrfs_inode_item);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment