From c118f7cc036b070d30faa522760362d815b6d800 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 12 Apr 2018 12:09:16 -0700 Subject: [PATCH] scoutfs: add option to force tiny btree blocks Add a tunable option to force using tiny btree blocks on an active mount. This lets us quickly exercise large btrees. Signed-off-by: Zach Brown --- kmod/src/btree.c | 23 +++++++++++++++++------ kmod/src/format.h | 8 ++++++++ kmod/src/options.c | 14 +++++++++++++- kmod/src/options.h | 5 +++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/kmod/src/btree.c b/kmod/src/btree.c index 7fdb2b72..15e28c8c 100644 --- a/kmod/src/btree.c +++ b/kmod/src/btree.c @@ -26,6 +26,7 @@ #include "sort_priv.h" #include "counters.h" #include "triggers.h" +#include "options.h" #include "scoutfs_trace.h" @@ -184,9 +185,9 @@ static inline unsigned int all_len_bytes(unsigned key_len, unsigned val_len) * 2 * min_used <= (bs - parent_min_free - hdr) * min_used <= (bs - parent_min_free - hdr) / 2 */ -static inline unsigned int min_used_bytes(void) +static inline int min_used_bytes(int block_size) { - return (SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_btree_block) - + return (block_size - sizeof(struct scoutfs_btree_block) - SCOUTFS_BTREE_PARENT_MIN_FREE_BYTES) / 2; } @@ -852,7 +853,9 @@ static int try_split(struct super_block *sb, struct scoutfs_btree_root *root, bool put_parent = false; int ret; - if (right->level) + if (scoutfs_option_bool(sb, Opt_btree_force_tiny_blocks)) + all_bytes = SCOUTFS_BLOCK_SIZE - SCOUTFS_BTREE_TINY_BLOCK_SIZE; + else if (right->level) all_bytes = SCOUTFS_BTREE_PARENT_MIN_FREE_BYTES; else all_bytes = all_len_bytes(key_len, val_len); @@ -913,12 +916,20 @@ static int try_merge(struct super_block *sb, struct scoutfs_btree_root *root, struct scoutfs_btree_ring *bring = &SCOUTFS_SB(sb)->super.bring; struct scoutfs_btree_block *sib; struct scoutfs_btree_ref *ref; + unsigned int min_used; unsigned int sib_pos; bool move_right; int to_move; int ret; - if (used_total(bt) >= min_used_bytes()) + BUILD_BUG_ON(min_used_bytes(SCOUTFS_BTREE_TINY_BLOCK_SIZE) < 0); + + if (scoutfs_option_bool(sb, Opt_btree_force_tiny_blocks)) + min_used = min_used_bytes(SCOUTFS_BTREE_TINY_BLOCK_SIZE); + else + min_used = min_used_bytes(SCOUTFS_BLOCK_SIZE); + + if (used_total(bt) >= min_used) return 0; /* move items right into our block if we have a left sibling */ @@ -935,10 +946,10 @@ static int try_merge(struct super_block *sb, struct scoutfs_btree_root *root, if (ret) return ret; - if (used_total(sib) < min_used_bytes()) + if (used_total(sib) < min_used) to_move = used_total(sib); else - to_move = min_used_bytes() - used_total(bt); + to_move = min_used - used_total(bt); move_items(bt, sib, move_right, to_move); diff --git a/kmod/src/format.h b/kmod/src/format.h index 29ea140c..b935d033 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -137,6 +137,14 @@ struct scoutfs_key_be { sizeof(struct scoutfs_btree_item) + SCOUTFS_BTREE_MAX_KEY_LEN +\ sizeof(struct scoutfs_btree_ref)) +/* + * When debugging we can tune the splitting and merging thresholds to + * create much larger trees by having blocks with many fewer items. We + * implement this by pretending the blocks are tiny. They're still + * large enough for a handful of items. + */ +#define SCOUTFS_BTREE_TINY_BLOCK_SIZE 512 + /* * A 4EB test image measured a worst case height of 17. This is plenty * generous. diff --git a/kmod/src/options.c b/kmod/src/options.c index 2d468553..f4b7e472 100644 --- a/kmod/src/options.c +++ b/kmod/src/options.c @@ -34,12 +34,17 @@ static const match_table_t tokens = { struct options_sb_info { struct dentry *debugfs_dir; + u32 btree_force_tiny_blocks; }; u32 scoutfs_option_u32(struct super_block *sb, int token) { + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct options_sb_info *osi = sbi->options; + switch(token) { - default: break; + case Opt_btree_force_tiny_blocks: + return osi->btree_force_tiny_blocks; } WARN_ON_ONCE(1); @@ -109,6 +114,13 @@ int scoutfs_options_setup(struct super_block *sb) goto out; } + if (!debugfs_create_bool("btree_force_tiny_blocks", 0644, + osi->debugfs_dir, + &osi->btree_force_tiny_blocks)) { + ret = -ENOMEM; + goto out; + } + ret = 0; out: if (ret) diff --git a/kmod/src/options.h b/kmod/src/options.h index 8bf58b36..0c038c92 100644 --- a/kmod/src/options.h +++ b/kmod/src/options.h @@ -7,6 +7,11 @@ enum { Opt_listen = 0, Opt_cluster, + /* + * For debugging we can quickly create huge trees by limiting + * the number of items in each block as though the blocks were tiny. + */ + Opt_btree_force_tiny_blocks, Opt_err, };