Commit c297a763 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Refactor whiteouts compaction

The whiteout compaction path - as opposed to just dropping whiteouts -
is now only needed for extents, and soon will only be needed for extent
btree nodes in the old format.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent c9bebae6
...@@ -530,28 +530,6 @@ unsigned bch2_sort_extents(struct bkey_packed *dst, ...@@ -530,28 +530,6 @@ unsigned bch2_sort_extents(struct bkey_packed *dst,
return (u64 *) out - (u64 *) dst; return (u64 *) out - (u64 *) dst;
} }
static inline int sort_key_whiteouts_cmp(struct btree *b,
struct bkey_packed *l,
struct bkey_packed *r)
{
return bkey_cmp_packed(b, l, r);
}
unsigned bch2_sort_key_whiteouts(struct bkey_packed *dst,
struct sort_iter *iter)
{
struct bkey_packed *in, *out = dst;
sort_iter_sort(iter, sort_key_whiteouts_cmp);
while ((in = sort_iter_next(iter, sort_key_whiteouts_cmp))) {
bkey_copy(out, in);
out = bkey_next(out);
}
return (u64 *) out - (u64 *) dst;
}
static inline int sort_extent_whiteouts_cmp(struct btree *b, static inline int sort_extent_whiteouts_cmp(struct btree *b,
struct bkey_packed *l, struct bkey_packed *l,
struct bkey_packed *r) struct bkey_packed *r)
......
...@@ -61,8 +61,6 @@ unsigned bch2_sort_keys(struct bkey_packed *, ...@@ -61,8 +61,6 @@ unsigned bch2_sort_keys(struct bkey_packed *,
unsigned bch2_sort_extents(struct bkey_packed *, unsigned bch2_sort_extents(struct bkey_packed *,
struct sort_iter *, bool); struct sort_iter *, bool);
unsigned bch2_sort_key_whiteouts(struct bkey_packed *,
struct sort_iter *);
unsigned bch2_sort_extent_whiteouts(struct bkey_packed *, unsigned bch2_sort_extent_whiteouts(struct bkey_packed *,
struct sort_iter *); struct sort_iter *);
......
...@@ -154,27 +154,26 @@ static void bch2_sort_whiteouts(struct bch_fs *c, struct btree *b) ...@@ -154,27 +154,26 @@ static void bch2_sort_whiteouts(struct bch_fs *c, struct btree *b)
btree_bounce_free(c, order, used_mempool1, new_whiteouts); btree_bounce_free(c, order, used_mempool1, new_whiteouts);
} }
static unsigned should_compact_bset(struct btree *b, struct bset_tree *t, static bool should_compact_bset(struct btree *b, struct bset_tree *t,
bool compacting, bool compacting, enum compact_mode mode)
enum compact_mode mode)
{ {
unsigned bset_u64s = le16_to_cpu(bset(b, t)->u64s); if (!bset_dead_u64s(b, t))
unsigned dead_u64s = bset_u64s - b->nr.bset_u64s[t - b->set]; return false;
if (mode == COMPACT_LAZY) { switch (mode) {
if (should_compact_bset_lazy(b, t) || case COMPACT_LAZY:
(compacting && !bset_written(b, bset(b, t)))) return should_compact_bset_lazy(b, t) ||
return dead_u64s; (compacting && !bset_written(b, bset(b, t)));
} else { case COMPACT_ALL:
if (bset_written(b, bset(b, t))) return true;
return dead_u64s; default:
BUG();
} }
return 0;
} }
bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, static bool bch2_compact_extent_whiteouts(struct bch_fs *c,
enum compact_mode mode) struct btree *b,
enum compact_mode mode)
{ {
const struct bkey_format *f = &b->format; const struct bkey_format *f = &b->format;
struct bset_tree *t; struct bset_tree *t;
...@@ -184,9 +183,11 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -184,9 +183,11 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
unsigned order, whiteout_u64s = 0, u64s; unsigned order, whiteout_u64s = 0, u64s;
bool used_mempool, compacting = false; bool used_mempool, compacting = false;
BUG_ON(!btree_node_is_extents(b));
for_each_bset(b, t) for_each_bset(b, t)
whiteout_u64s += should_compact_bset(b, t, if (should_compact_bset(b, t, whiteout_u64s != 0, mode))
whiteout_u64s != 0, mode); whiteout_u64s += bset_dead_u64s(b, t);
if (!whiteout_u64s) if (!whiteout_u64s)
return false; return false;
...@@ -215,9 +216,12 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -215,9 +216,12 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
if (t != b->set && !bset_written(b, i)) { if (t != b->set && !bset_written(b, i)) {
src = container_of(i, struct btree_node_entry, keys); src = container_of(i, struct btree_node_entry, keys);
dst = max(write_block(b), dst = max(write_block(b),
(void *) btree_bkey_last(b, t -1)); (void *) btree_bkey_last(b, t - 1));
} }
if (src != dst)
compacting = true;
if (!should_compact_bset(b, t, compacting, mode)) { if (!should_compact_bset(b, t, compacting, mode)) {
if (src != dst) { if (src != dst) {
memmove(dst, src, sizeof(*src) + memmove(dst, src, sizeof(*src) +
...@@ -245,7 +249,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -245,7 +249,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
for (k = start; k != end; k = n) { for (k = start; k != end; k = n) {
n = bkey_next_skip_noops(k, end); n = bkey_next_skip_noops(k, end);
if (bkey_deleted(k) && btree_node_is_extents(b)) if (bkey_deleted(k))
continue; continue;
BUG_ON(bkey_whiteout(k) && BUG_ON(bkey_whiteout(k) &&
...@@ -259,7 +263,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -259,7 +263,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
memcpy_u64s(u_pos, k, bkeyp_key_u64s(f, k)); memcpy_u64s(u_pos, k, bkeyp_key_u64s(f, k));
set_bkeyp_val_u64s(f, u_pos, 0); set_bkeyp_val_u64s(f, u_pos, 0);
u_pos = bkey_next(u_pos); u_pos = bkey_next(u_pos);
} else if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK) { } else {
bkey_copy(out, k); bkey_copy(out, k);
out = bkey_next(out); out = bkey_next(out);
} }
...@@ -267,11 +271,9 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -267,11 +271,9 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
sort_iter_add(&sort_iter, u_start, u_pos); sort_iter_add(&sort_iter, u_start, u_pos);
if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK) { i->u64s = cpu_to_le16((u64 *) out - i->_data);
i->u64s = cpu_to_le16((u64 *) out - i->_data); set_btree_bset_end(b, t);
set_btree_bset_end(b, t); bch2_bset_set_no_aux_tree(b, t);
bch2_bset_set_no_aux_tree(b, t);
}
} }
b->whiteout_u64s = (u64 *) u_pos - (u64 *) whiteouts; b->whiteout_u64s = (u64 *) u_pos - (u64 *) whiteouts;
...@@ -279,13 +281,10 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -279,13 +281,10 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
BUG_ON((void *) unwritten_whiteouts_start(c, b) < BUG_ON((void *) unwritten_whiteouts_start(c, b) <
(void *) btree_bkey_last(b, bset_tree_last(b))); (void *) btree_bkey_last(b, bset_tree_last(b)));
u64s = (btree_node_is_extents(b) u64s = bch2_sort_extent_whiteouts(unwritten_whiteouts_start(c, b),
? bch2_sort_extent_whiteouts &sort_iter);
: bch2_sort_key_whiteouts)(unwritten_whiteouts_start(c, b),
&sort_iter);
BUG_ON(u64s > b->whiteout_u64s); BUG_ON(u64s > b->whiteout_u64s);
BUG_ON(u64s != b->whiteout_u64s && !btree_node_is_extents(b));
BUG_ON(u_pos != whiteouts && !u64s); BUG_ON(u_pos != whiteouts && !u64s);
if (u64s != b->whiteout_u64s) { if (u64s != b->whiteout_u64s) {
...@@ -301,8 +300,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -301,8 +300,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
btree_bounce_free(c, order, used_mempool, whiteouts); btree_bounce_free(c, order, used_mempool, whiteouts);
if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK) bch2_btree_build_aux_trees(b);
bch2_btree_build_aux_trees(b);
bch_btree_keys_u64s_remaining(c, b); bch_btree_keys_u64s_remaining(c, b);
bch2_verify_btree_nr_keys(b); bch2_verify_btree_nr_keys(b);
...@@ -310,7 +308,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b, ...@@ -310,7 +308,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
return true; return true;
} }
static bool bch2_drop_whiteouts(struct btree *b) static bool bch2_drop_whiteouts(struct btree *b, enum compact_mode mode)
{ {
struct bset_tree *t; struct bset_tree *t;
bool ret = false; bool ret = false;
...@@ -318,21 +316,34 @@ static bool bch2_drop_whiteouts(struct btree *b) ...@@ -318,21 +316,34 @@ static bool bch2_drop_whiteouts(struct btree *b)
for_each_bset(b, t) { for_each_bset(b, t) {
struct bset *i = bset(b, t); struct bset *i = bset(b, t);
struct bkey_packed *k, *n, *out, *start, *end; struct bkey_packed *k, *n, *out, *start, *end;
struct btree_node_entry *src = NULL, *dst = NULL;
if (t != b->set && !bset_written(b, i)) {
src = container_of(i, struct btree_node_entry, keys);
dst = max(write_block(b),
(void *) btree_bkey_last(b, t - 1));
}
if (src != dst)
ret = true;
if (!should_compact_bset(b, t, true, COMPACT_WRITTEN)) if (!should_compact_bset(b, t, ret, mode)) {
if (src != dst) {
memmove(dst, src, sizeof(*src) +
le16_to_cpu(src->keys.u64s) *
sizeof(u64));
i = &dst->keys;
set_btree_bset(b, t, i);
}
continue; continue;
}
start = btree_bkey_first(b, t); start = btree_bkey_first(b, t);
end = btree_bkey_last(b, t); end = btree_bkey_last(b, t);
if (!bset_written(b, i) && if (src != dst) {
t != b->set) { memmove(dst, src, sizeof(*src));
struct bset *dst = i = &dst->keys;
max_t(struct bset *, write_block(b),
(void *) btree_bkey_last(b, t -1));
memmove(dst, i, sizeof(struct bset));
i = dst;
set_btree_bset(b, t, i); set_btree_bset(b, t, i);
} }
...@@ -344,19 +355,32 @@ static bool bch2_drop_whiteouts(struct btree *b) ...@@ -344,19 +355,32 @@ static bool bch2_drop_whiteouts(struct btree *b)
if (!bkey_whiteout(k)) { if (!bkey_whiteout(k)) {
bkey_copy(out, k); bkey_copy(out, k);
out = bkey_next(out); out = bkey_next(out);
} else {
BUG_ON(k->needs_whiteout);
} }
} }
i->u64s = cpu_to_le16((u64 *) out - i->_data); i->u64s = cpu_to_le16((u64 *) out - i->_data);
set_btree_bset_end(b, t);
bch2_bset_set_no_aux_tree(b, t); bch2_bset_set_no_aux_tree(b, t);
ret = true; ret = true;
} }
bch2_verify_btree_nr_keys(b); bch2_verify_btree_nr_keys(b);
bch2_btree_build_aux_trees(b);
return ret; return ret;
} }
bool bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
enum compact_mode mode)
{
return !btree_node_is_extents(b)
? bch2_drop_whiteouts(b, mode)
: bch2_compact_extent_whiteouts(c, b, mode);
}
static void btree_node_sort(struct bch_fs *c, struct btree *b, static void btree_node_sort(struct bch_fs *c, struct btree *b,
struct btree_iter *iter, struct btree_iter *iter,
unsigned start_idx, unsigned start_idx,
...@@ -1631,7 +1655,7 @@ bool bch2_btree_post_write_cleanup(struct bch_fs *c, struct btree *b) ...@@ -1631,7 +1655,7 @@ bool bch2_btree_post_write_cleanup(struct bch_fs *c, struct btree *b)
btree_node_sort(c, b, NULL, 0, b->nsets, true); btree_node_sort(c, b, NULL, 0, b->nsets, true);
invalidated_iter = true; invalidated_iter = true;
} else { } else {
invalidated_iter = bch2_drop_whiteouts(b); invalidated_iter = bch2_drop_whiteouts(b, COMPACT_ALL);
} }
for_each_bset(b, t) for_each_bset(b, t)
......
...@@ -54,16 +54,17 @@ static inline bool btree_node_may_write(struct btree *b) ...@@ -54,16 +54,17 @@ static inline bool btree_node_may_write(struct btree *b)
enum compact_mode { enum compact_mode {
COMPACT_LAZY, COMPACT_LAZY,
COMPACT_WRITTEN, COMPACT_ALL,
COMPACT_WRITTEN_NO_WRITE_LOCK,
}; };
bool __bch2_compact_whiteouts(struct bch_fs *, struct btree *, enum compact_mode); bool bch2_compact_whiteouts(struct bch_fs *, struct btree *,
enum compact_mode);
static inline unsigned should_compact_bset_lazy(struct btree *b, struct bset_tree *t) static inline bool should_compact_bset_lazy(struct btree *b,
struct bset_tree *t)
{ {
unsigned total_u64s = bset_u64s(t); unsigned total_u64s = bset_u64s(t);
unsigned dead_u64s = total_u64s - b->nr.bset_u64s[t - b->set]; unsigned dead_u64s = bset_dead_u64s(b, t);
return dead_u64s > 64 && dead_u64s * 3 > total_u64s; return dead_u64s > 64 && dead_u64s * 3 > total_u64s;
} }
...@@ -74,7 +75,7 @@ static inline bool bch2_maybe_compact_whiteouts(struct bch_fs *c, struct btree * ...@@ -74,7 +75,7 @@ static inline bool bch2_maybe_compact_whiteouts(struct bch_fs *c, struct btree *
for_each_bset(b, t) for_each_bset(b, t)
if (should_compact_bset_lazy(b, t)) if (should_compact_bset_lazy(b, t))
return __bch2_compact_whiteouts(c, b, COMPACT_LAZY); return bch2_compact_whiteouts(c, b, COMPACT_LAZY);
return false; return false;
} }
......
...@@ -423,6 +423,11 @@ static inline unsigned bset_u64s(struct bset_tree *t) ...@@ -423,6 +423,11 @@ static inline unsigned bset_u64s(struct bset_tree *t)
sizeof(struct bset) / sizeof(u64); sizeof(struct bset) / sizeof(u64);
} }
static inline unsigned bset_dead_u64s(struct btree *b, struct bset_tree *t)
{
return bset_u64s(t) - b->nr.bset_u64s[t - b->set];
}
static inline unsigned bset_byte_offset(struct btree *b, void *i) static inline unsigned bset_byte_offset(struct btree *b, void *i)
{ {
return i - (void *) b->data; return i - (void *) b->data;
......
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