• F
    btrfs: avoid unnecessary COW of leaves when deleting items from a leaf · 7c4063d1
    Filipe Manana 提交于
    When we delete items from a leaf, if we end up with more than two thirds
    of unused leaf space, we try to delete the leaf by moving all its items
    into its left and right neighbour leaves. Sometimes that is not possible
    because there is not enough free space in the left and right leaves, and
    in that case we end up not deleting our leaf.
    
    The way we are doing this is not ideal and can be improved in the
    following ways:
    
    1) When we call push_leaf_left(), we pass a value of 1 byte to the data
       size parameter of push_leaf_left(). This is not realistic value because
       no item can have a size less than 25 bytes, which is the size of struct
       btrfs_item. This means that means that if the left leaf has not enough
       free space to push any item, we end up COWing it even if we end up not
       changing its content at all.
    
       COWing that leaf means allocating a new metadata extent, marking it
       dirty and doing more IO when committing a transaction or when syncing a
       log tree. For a log tree case, it's particularly more important to
       avoid the useless COW operation, as more IO can imply a higher latency
       for an fsync operation.
    
       So instead of passing 1 as the minimum data size for push_leaf_left(),
       pass the size of the first item in our leaf, as we don't want to COW
       the left leaf if we can't at least push the first item of our leaf;
    
    2) When we call push_leaf_right(), we also pass a value of 1 byte as the
       data size parameter of push_leaf_right(). Like the previous case, it
       will also result in COWing the right leaf even if we are not able to
       move any items into it, since there can't be any item with a size
       smaller than 25 bytes (the size of struct btrfs_item).
    
       So instead of passing 1 as the minimum data size to push_leaf_right(),
       pass a size that corresponds to the sum of the size of all the
       remaining items in our leaf. We are not interested in moving less than
       that, because if we do, we are not able to delete our leaf and we have
       COWed the right leaf for nothing. Plus, moving only some of the items
       of our leaf, it means an even less balanced tree.
    
       Just like the previous case, we want to avoid the useless COW of the
       right leaf, this way we don't have to spend time allocating one new
       metadata extent, and doing more IO when committing a transaction or
       syncing a log tree. For the log tree case it's specially more important
       because more IO can result in a higher latency for a fsync operation.
    
    So adjust the minimum data size passed to push_leaf_left() and
    push_leaf_right() as mentioned above.
    
    This change if part of a patchset that is comprised of the following
    patches:
    
      1/6 btrfs: remove unnecessary leaf free space checks when pushing items
      2/6 btrfs: avoid unnecessary COW of leaves when deleting items from a leaf
      3/6 btrfs: avoid unnecessary computation when deleting items from a leaf
      4/6 btrfs: remove constraint on number of visited leaves when replacing extents
      5/6 btrfs: remove useless path release in the fast fsync path
      6/6 btrfs: prepare extents to be logged before locking a log tree path
    
    Not being able to delete a leaf that became less than 1/3 full after
    deleting items from it is actually common. For example, for the fio test
    mentioned in the changelog of patch 6/6, we are only able to delete a
    leaf at btrfs_del_items() about 5.3% of the time, due to its left and
    right neighbour leaves not having enough free space to push all the
    remaining items into them.
    
    The last patch in the series has some performance test result in its
    changelog.
    Signed-off-by: NFilipe Manana <fdmanana@suse.com>
    Signed-off-by: NDavid Sterba <dsterba@suse.com>
    7c4063d1
ctree.c 125.0 KB