speedup btrfs send/receive
Subsystems (2)
cover speedup btrfs send/receive
This commit changes the btrfs send/receive commands to use the UUID tree to map UUIDs to subvolumes, and to use the root tree to map subvolume IDs to paths. Now these tools start fast and are independent on the number of subvolumes/snapshots that exist.
Before this commit, mapping UUIDs to subvolume IDs was an operation with a high effort. The algorithm even had quadratic effort (based on the number of existing subvolumes). E.g. with 15,000 subvolumes it took much more than 5 minutes on a state of the art XEON CPU to start btrfs send or receive before these tools were able to send or receive the first byte).
Even linear effort instead of the current quadratic effort would be too much since it would be a waste. And these data structures to allow mapping UUIDs to subvolume IDs had been created every time a btrfs send/receive instance was started.
It is much more efficient to maintain a searchable persistent data structure in the filesystem, one that is updated whenever a subvolume/snapshot is created and deleted, and when the received subvolume UUID is set by the btrfs-receive tool. The user mode tools can then just use the tree-search ioctl to quickly retrieve all information.
With a recent commit, kernel code was added that is able to maintain data structures in the filesystem that allow to quickly search for a given UUID and to retrieve data that is assigned to this UUID, like which subvolume ID is related to this UUID.
This commit series adds support for the UUID tree to Btrfs-progs and changes the send/receive tools to use it.
Stefan Behrens (3):
Btrfs-progs: Support UUID tree and UUID items in btrfs-debug-tree
Btrfs-progs: add uuid-tree lookup methods
Btrfs-progs: use UUID tree for send/receive
Makefile | 2 +- cmds-receive.c | 23 ++- cmds-send.c | 53 +++++-- ctree.h | 34 ++++ print-tree.c | 91 ++++++++++- send-utils.c | 477 +++++++++++++++++++++++---------------------------------- send-utils.h | 9 +- uuid-tree.c | 196 ++++++++++++++++++++++++ 8 files changed, 572 insertions(+), 313 deletions(-) create mode 100644 uuid-tree.c
Signature · 1 line
1.8.2.1
PATCH 1/3 Btrfs-progs: Support UUID tree and UUID items in btrfs-debug-tree
Support printing these things.
--- ctree.h | 29 +++++++++++++++++++ print-tree.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 3 deletions(-)
ctree.h +29 -0
@@ -71,6 +71,8 @@ struct btrfs_free_space_ctl;#define BTRFS_CSUM_TREE_OBJECTID 7ULL#define BTRFS_QUOTA_TREE_OBJECTID 8ULL +/* for storing items that use the BTRFS_UUID_KEY */ +#define BTRFS_UUID_TREE_OBJECTID 9ULL/* for storing balance parameters in the root tree */ #define BTRFS_BALANCE_OBJECTID -4ULL
@@ -811,6 +813,16 @@ struct btrfs_csum_item {u8 csum; } __attribute__ ((__packed__)); +/* for items that use the BTRFS_UUID_KEY */ +#define BTRFS_UUID_ITEM_TYPE_SUBVOL 0/* for UUIDs assigned to subvols */ +#define BTRFS_UUID_ITEM_TYPE_RECEIVED_SUBVOL 1/* for UUIDs assigned to +* received subvols */ +struct btrfs_uuid_item { +__le64 type;/* refer to BTRFS_UUID_ITEM_TYPE* defines above */ +__le64 len;/* number of following 64bit values */ +__le64 data[0 ];/* data aligned to 64bit */ +} __attribute__ ((__packed__ )); +/* tag for the radix tree of block groups in ram */ #define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
@@ -1107,6 +1119,17 @@ struct btrfs_root {#define BTRFS_DEV_REPLACE_KEY 250/* +* Stores items that allow to quickly map UUIDs to something else. +* These items are part of the filesystem UUID tree. +* The key is built like this: +* (UUID_upper_64_bits, BTRFS_UUID_KEY, UUID_lower_64_bits). +*/ +#if BTRFS_UUID_SIZE !=16 +#error "UUID items require BTRFS_UUID_SIZE == 16!" +#endif +#define BTRFS_UUID_KEY 251 + +/* * string items are for debugging. They just store a short string of * data in the FS */
@@ -2046,6 +2069,12 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,return btrfs_item_size (eb, e) - offset; } +/* btrfs_uuid_item */ +BTRFS_SETGET_FUNCS(uuid_type, struct btrfs_uuid_item, type, 64); +BTRFS_SETGET_FUNCS(uuid_len, struct btrfs_uuid_item, len, 64); +BTRFS_SETGET_STACK_FUNCS(stack_uuid_type, struct btrfs_uuid_item, type, 64); +BTRFS_SETGET_STACK_FUNCS(stack_uuid_len, struct btrfs_uuid_item, len, 64); +static inline u32 btrfs_level_size (struct btrfs_root *root,int level) {if (level ==0 )return root->leafsize;
print-tree.c +88 -3
139 lines not on this page · raw message
Signature · 1 line
1.8.2.1
PATCH 2/3 Btrfs-progs: add uuid-tree lookup methods
In reply to Stefan BehrensThis commit adds uuid-tree lookup methods that make use of the search ioctl. The code is based on the kernel code.
--- Makefile | 2 +- ctree.h | 5 ++ uuid-tree.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 1 deletion(-)
Makefile +1 -1
@@ -6,7 +6,7 @@ CFLAGS = -g -O1 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o inode-map.o \ extent-cache.o extent_io.o volumes.o utils.o repair.o \ - qgroup.o raid6.o free-space-cache.o + qgroup.o raid6.o free-space-cache.o uuid-tree.o cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \ cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \
ctree.h +5 -0
@@ -2355,4 +2355,9 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,int btrfs_csum_truncate (struct btrfs_trans_handle *trans,struct btrfs_root *root,struct btrfs_path *path,u64 isize); + +/* uuid-tree.c */ +int btrfs_lookup_uuid_subvol_item (int fd,const u8 *uuid,u64 *subvol_id); +int btrfs_lookup_uuid_received_subvol_item (int fd,const u8 *uuid, +u64 *subvol_id);#endif
uuid-tree.c new file +196 -0
196 lines not on this page · raw message
Signature · 1 line
1.8.2.1
PATCH 3/3 Btrfs-progs: use UUID tree for send/receive
In reply to Stefan BehrensThis commit changes the btrfs send/receive commands to use the UUID tree to map UUIDs to subvolumes, and to use the root tree to map subvolume IDs to paths. Now these tools start fast and are independent on the number of subvolules/snapshot that exist.
Before this commit, mapping UUIDs to subvolume IDs was an operation with a high effort. The algorithm even had quadratic effort (based on the number of existing subvolumes). E.g. with 15,000 subvolumes it took much more than 5 minutes on a state of the art XEON CPU to start btrfs send or receive before these tools were able to send or receive the first byte).
Even linear effort instead of the current quadratic effort would be too much since it would be a waste. And these data structures to allow mapping UUIDs to subvolume IDs had been created every time a btrfs send/receive instance was started.
It is much more efficient to maintain a searchable persistent data structure in the filesystem, one that is updated whenever a subvolume/snapshot is created and deleted, and when the received subvolume UUID is set by the btrfs-receive tool.
Therefore kernel code was added that is able to maintain data structures in the filesystem that allow to quickly search for a given UUID and to retrieve data that is assigned to this UUID, like which subvolume ID is related to this UUID.
--- cmds-receive.c | 23 ++- cmds-send.c | 53 +++++-- send-utils.c | 477 +++++++++++++++++++++++---------------------------------- send-utils.h | 9 +- 4 files changed, 253 insertions(+), 309 deletions(-)
cmds-receive.c +16 -7
@@ -31,6 +31,7 @@#include <math.h> #include <ftw.h> #include <wait.h> +#include <assert.h> #include <sys/stat.h> #include <sys/types.h>
@@ -129,14 +130,14 @@ static int finish_subvol(struct btrfs_receive *r) goto out; } - ret =btrfs_list_get_path_rootid (subvol_fd, &r->cur_subvol->root_id); -if (ret <0 ) - goto out; -subvol_uuid_search_add (&r->sus, r->cur_subvol); - r->cur_subvol =NULL ; ret =0 ; out: +if (r->cur_subvol) { +free (r->cur_subvol->path); +free (r->cur_subvol); + r->cur_subvol =NULL ; + }if (subvol_fd !=-1 )close (subvol_fd);return ret;
@@ -197,7 +198,7 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,struct btrfs_receive *r = user;char uuid_str[128 ];struct btrfs_ioctl_vol_args_v2 args_v2; -struct subvol_info *parent_subvol; +struct subvol_info *parent_subvol =NULL ; ret =finish_subvol (r);if (ret <0 )
@@ -268,6 +269,10 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid, } out: +if (parent_subvol) { +free (parent_subvol->path); +free (parent_subvol); + }return ret; }
@@ -557,7 +562,7 @@ static int process_clone(const char *path, u64 offset, u64 len, const char *clone_path, u64 clone_offset, void *user) { - int ret = 0; + int ret;struct btrfs_receive *r = user;struct btrfs_ioctl_clone_range_args clone_args;struct subvol_info *si =NULL ;
@@ -624,6 +629,10 @@ static int process_clone(const char *path, u64 offset, u64 len, } out: +if (si) { +free (si->path); +free (si); + }free (full_path);free (full_clone_path);free (subvol_path);
cmds-send.c +44 -9
123 lines not on this page · raw message
send-utils.c +192 -285
524 lines not on this page · raw message
send-utils.h +1 -8
@@ -38,10 +38,6 @@ enum subvol_search_type { };struct subvol_info { -struct rb_node rb_root_id_node; -struct rb_node rb_local_node; -struct rb_node rb_received_node; -struct rb_node rb_path_node;u64 root_id;u8 uuid[BTRFS_UUID_SIZE ];u8 parent_uuid[BTRFS_UUID_SIZE ];
@@ -55,10 +51,7 @@ struct subvol_info { };struct subvol_uuid_search { -struct rb_root root_id_subvols; -struct rb_root local_subvols; -struct rb_root received_subvols; -struct rb_root path_subvols; +int mnt_fd; };int subvol_uuid_search_init (int mnt_fd,struct subvol_uuid_search *s);
Signature · 1 line
1.8.2.1