Commit 17e21a9f authored by Kent Overstreet's avatar Kent Overstreet

bcache: Have btree_split() insert into parent directly

The flow control in btree_insert_node() was... fragile... before,
this'll use more stack (but since our btrees are never more than depth
1, that shouldn't matter) and it should be significantly clearer and
less fragile.
Signed-off-by: default avatarKent Overstreet <kmo@daterainc.com>
parent 65d22e91
...@@ -2025,15 +2025,16 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op, ...@@ -2025,15 +2025,16 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op,
static int btree_split(struct btree *b, struct btree_op *op, static int btree_split(struct btree *b, struct btree_op *op,
struct keylist *insert_keys, struct keylist *insert_keys,
struct keylist *parent_keys,
struct bkey *replace_key) struct bkey *replace_key)
{ {
bool split; bool split;
struct btree *n1, *n2 = NULL, *n3 = NULL; struct btree *n1, *n2 = NULL, *n3 = NULL;
uint64_t start_time = local_clock(); uint64_t start_time = local_clock();
struct closure cl; struct closure cl;
struct keylist parent_keys;
closure_init_stack(&cl); closure_init_stack(&cl);
bch_keylist_init(&parent_keys);
n1 = btree_node_alloc_replacement(b, true); n1 = btree_node_alloc_replacement(b, true);
if (IS_ERR(n1)) if (IS_ERR(n1))
...@@ -2078,7 +2079,7 @@ static int btree_split(struct btree *b, struct btree_op *op, ...@@ -2078,7 +2079,7 @@ static int btree_split(struct btree *b, struct btree_op *op,
bkey_copy_key(&n2->key, &b->key); bkey_copy_key(&n2->key, &b->key);
bch_keylist_add(parent_keys, &n2->key); bch_keylist_add(&parent_keys, &n2->key);
bch_btree_node_write(n2, &cl); bch_btree_node_write(n2, &cl);
rw_unlock(true, n2); rw_unlock(true, n2);
} else { } else {
...@@ -2087,33 +2088,39 @@ static int btree_split(struct btree *b, struct btree_op *op, ...@@ -2087,33 +2088,39 @@ static int btree_split(struct btree *b, struct btree_op *op,
bch_btree_insert_keys(n1, op, insert_keys, replace_key); bch_btree_insert_keys(n1, op, insert_keys, replace_key);
} }
bch_keylist_add(parent_keys, &n1->key); bch_keylist_add(&parent_keys, &n1->key);
bch_btree_node_write(n1, &cl); bch_btree_node_write(n1, &cl);
if (n3) { if (n3) {
/* Depth increases, make a new root */ /* Depth increases, make a new root */
bkey_copy_key(&n3->key, &MAX_KEY); bkey_copy_key(&n3->key, &MAX_KEY);
bch_btree_insert_keys(n3, op, parent_keys, NULL); bch_btree_insert_keys(n3, op, &parent_keys, NULL);
bch_btree_node_write(n3, &cl); bch_btree_node_write(n3, &cl);
closure_sync(&cl); closure_sync(&cl);
bch_btree_set_root(n3); bch_btree_set_root(n3);
rw_unlock(true, n3); rw_unlock(true, n3);
btree_node_free(b);
} else if (!b->parent) { } else if (!b->parent) {
/* Root filled up but didn't need to be split */ /* Root filled up but didn't need to be split */
bch_keylist_reset(parent_keys);
closure_sync(&cl); closure_sync(&cl);
bch_btree_set_root(n1); bch_btree_set_root(n1);
btree_node_free(b);
} else { } else {
/* Split a non root node */
closure_sync(&cl); closure_sync(&cl);
make_btree_freeing_key(b, parent_keys->top); make_btree_freeing_key(b, parent_keys.top);
bch_keylist_push(parent_keys); bch_keylist_push(&parent_keys);
btree_node_free(b);
bch_btree_insert_node(b->parent, op, &parent_keys, NULL, NULL);
BUG_ON(!bch_keylist_empty(&parent_keys));
} }
rw_unlock(true, n1); rw_unlock(true, n1);
btree_node_free(b);
bch_time_stats_update(&b->c->btree_split_time, start_time); bch_time_stats_update(&b->c->btree_split_time, start_time);
...@@ -2139,46 +2146,32 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op, ...@@ -2139,46 +2146,32 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
atomic_t *journal_ref, atomic_t *journal_ref,
struct bkey *replace_key) struct bkey *replace_key)
{ {
int ret = 0;
struct keylist split_keys;
bch_keylist_init(&split_keys);
do {
BUG_ON(b->level && replace_key); BUG_ON(b->level && replace_key);
if (should_split(b)) { if (should_split(b)) {
if (current->bio_list) { if (current->bio_list) {
op->lock = b->c->root->level + 1; op->lock = b->c->root->level + 1;
ret = -EAGAIN; return -EAGAIN;
} else if (op->lock <= b->c->root->level) { } else if (op->lock <= b->c->root->level) {
op->lock = b->c->root->level + 1; op->lock = b->c->root->level + 1;
ret = -EINTR; return -EINTR;
} else { } else {
struct btree *parent = b->parent; /* Invalidated all iterators */
return btree_split(b, op, insert_keys, replace_key) ?:
ret = btree_split(b, op, insert_keys, -EINTR;
&split_keys, replace_key);
insert_keys = &split_keys;
replace_key = NULL;
b = parent;
if (!ret)
ret = -EINTR;
} }
} else { } else {
BUG_ON(write_block(b) != b->sets[b->nsets].data); BUG_ON(write_block(b) != b->sets[b->nsets].data);
if (bch_btree_insert_keys(b, op, insert_keys, if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
replace_key)) {
if (!b->level) if (!b->level)
bch_btree_leaf_dirty(b, journal_ref); bch_btree_leaf_dirty(b, journal_ref);
else else
bch_btree_node_write_sync(b); bch_btree_node_write_sync(b);
} }
}
} while (!bch_keylist_empty(&split_keys));
return ret; return 0;
}
} }
int bch_btree_insert_check_key(struct btree *b, struct btree_op *op, int bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
......
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