Commit a450a4af authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

btrfs: don't log unnecessary boundary keys when logging directory

Before we start to log dir index keys from a leaf, we check if there is a
previous index key, which normally is at the end of a leaf that was not
changed in the current transaction. Then we log that key and set the start
of logged range (item of type BTRFS_DIR_LOG_INDEX_KEY) to the offset of
that key. This is to ensure that if there were deleted index keys between
that key and the first key we are going to log, those deletions are
replayed in case we need to replay to the log after a power failure.
However we really don't need to log that previous key, we can just set the
start of the logged range to that key's offset plus 1. This achieves the
same and avoids logging one dir index key.

The same logic is performed when we finish logging the index keys of a
leaf and we find that the next leaf has index keys and was not changed in
the current transaction. We are logging the first key of that next leaf
and use its offset as the end of range we log. This is just to ensure that
if there were deleted index keys between the last index key we logged and
the first key of that next leaf, those index keys are deleted if we end
up replaying the log. However that is not necessary, we can avoid logging
that first index key of the next leaf and instead set the end of the
logged range to match the offset of that index key minus 1.

So avoid logging those index keys at the boundaries and adjust the start
and end offsets of the logged ranges as described above.

This patch is part of a patchset comprised of the following patches:

  1/4 btrfs: don't log unnecessary boundary keys when logging directory
  2/4 btrfs: put initial index value of a directory in a constant
  3/4 btrfs: stop copying old dir items when logging a directory
  4/4 btrfs: stop trying to log subdirectories created in past transactions

Performance test results are listed in the changelog of patch 3/4.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent dc408ccd
...@@ -3906,17 +3906,18 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -3906,17 +3906,18 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
ret = btrfs_previous_item(root, path, ino, BTRFS_DIR_INDEX_KEY); ret = btrfs_previous_item(root, path, ino, BTRFS_DIR_INDEX_KEY);
if (ret == 0) { if (ret == 0) {
struct btrfs_key tmp; struct btrfs_key tmp;
btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
if (tmp.type == BTRFS_DIR_INDEX_KEY) { /*
first_offset = tmp.offset; * The dir index key before the first one we found that needs to
ret = overwrite_item(trans, log, dst_path, * be logged might be in a previous leaf, and there might be a
path->nodes[0], path->slots[0], * gap between these keys, meaning that we had deletions that
&tmp); * happened. So the key range item we log (key type
if (ret) { * BTRFS_DIR_LOG_INDEX_KEY) must cover a range that starts at the
err = ret; * previous key's offset plus 1, so that those deletes are replayed.
goto done; */
} if (tmp.type == BTRFS_DIR_INDEX_KEY)
} first_offset = tmp.offset + 1;
} }
btrfs_release_path(path); btrfs_release_path(path);
...@@ -3964,14 +3965,16 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -3964,14 +3965,16 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
goto done; goto done;
} }
if (btrfs_header_generation(path->nodes[0]) != trans->transid) { if (btrfs_header_generation(path->nodes[0]) != trans->transid) {
ctx->last_dir_item_offset = min_key.offset; /*
ret = overwrite_item(trans, log, dst_path, * The next leaf was not changed in the current transaction
path->nodes[0], path->slots[0], * and has at least one dir index key.
&min_key); * We check for the next key because there might have been
if (ret) * one or more deletions between the last key we logged and
err = ret; * that next key. So the key range item we log (key type
else * BTRFS_DIR_LOG_INDEX_KEY) must end at the next key's
last_offset = min_key.offset; * offset minus 1, so that those deletes are replayed.
*/
last_offset = min_key.offset - 1;
goto done; goto done;
} }
if (need_resched()) { if (need_resched()) {
......
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