]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_journal_iter.c
Disable pristine-tar option in gbp.conf, since there is no pristine-tar branch.
[bcachefs-tools-debian] / libbcachefs / btree_journal_iter.c
index 58a981bcf3aa8ca6749c41ca9e22655098adee14..3da65562fdb0423ab0cfcba0fdf3d5cff40b74fa 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include "bcachefs.h"
+#include "bkey_buf.h"
 #include "bset.h"
+#include "btree_cache.h"
 #include "btree_journal_iter.h"
 #include "journal_io.h"
 
@@ -73,6 +75,7 @@ static size_t bch2_journal_key_search(struct journal_keys *keys,
        return idx_to_pos(keys, __bch2_journal_key_search(keys, id, level, pos));
 }
 
+/* Returns first non-overwritten key >= search key: */
 struct bkey_i *bch2_journal_keys_peek_upto(struct bch_fs *c, enum btree_id btree_id,
                                           unsigned level, struct bpos pos,
                                           struct bpos end_pos, size_t *idx)
@@ -80,16 +83,32 @@ struct bkey_i *bch2_journal_keys_peek_upto(struct bch_fs *c, enum btree_id btree
        struct journal_keys *keys = &c->journal_keys;
        unsigned iters = 0;
        struct journal_key *k;
+
+       BUG_ON(*idx > keys->nr);
 search:
        if (!*idx)
                *idx = __bch2_journal_key_search(keys, btree_id, level, pos);
 
+       while (*idx &&
+              __journal_key_cmp(btree_id, level, end_pos, idx_to_key(keys, *idx - 1)) <= 0) {
+               --(*idx);
+               iters++;
+               if (iters == 10) {
+                       *idx = 0;
+                       goto search;
+               }
+       }
+
        while ((k = *idx < keys->nr ? idx_to_key(keys, *idx) : NULL)) {
                if (__journal_key_cmp(btree_id, level, end_pos, k) < 0)
                        return NULL;
 
-               if (__journal_key_cmp(btree_id, level, pos, k) <= 0 &&
-                   !k->overwritten)
+               if (k->overwritten) {
+                       (*idx)++;
+                       continue;
+               }
+
+               if (__journal_key_cmp(btree_id, level, pos, k) <= 0)
                        return k->k;
 
                (*idx)++;
@@ -160,7 +179,7 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
        struct journal_keys *keys = &c->journal_keys;
        size_t idx = bch2_journal_key_search(keys, id, level, k->k.p);
 
-       BUG_ON(test_bit(BCH_FS_RW, &c->flags));
+       BUG_ON(test_bit(BCH_FS_rw, &c->flags));
 
        if (idx < keys->size &&
            journal_key_cmp(&n, &keys->d[idx]) == 0) {
@@ -189,10 +208,12 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
                /* Since @keys was full, there was no gap: */
                memcpy(new_keys.d, keys->d, sizeof(keys->d[0]) * keys->nr);
                kvfree(keys->d);
-               *keys = new_keys;
+               keys->d         = new_keys.d;
+               keys->nr        = new_keys.nr;
+               keys->size      = new_keys.size;
 
                /* And now the gap is at the end: */
-               keys->gap = keys->nr;
+               keys->gap       = keys->nr;
        }
 
        journal_iters_move_gap(c, keys->gap, idx);
@@ -315,9 +336,38 @@ void bch2_btree_and_journal_iter_advance(struct btree_and_journal_iter *iter)
                iter->pos = bpos_successor(iter->pos);
 }
 
+static void btree_and_journal_iter_prefetch(struct btree_and_journal_iter *_iter)
+{
+       struct btree_and_journal_iter iter = *_iter;
+       struct bch_fs *c = iter.trans->c;
+       unsigned level = iter.journal.level;
+       struct bkey_buf tmp;
+       unsigned nr = test_bit(BCH_FS_started, &c->flags)
+               ? (level > 1 ? 0 :  2)
+               : (level > 1 ? 1 : 16);
+
+       iter.prefetch = false;
+       bch2_bkey_buf_init(&tmp);
+
+       while (nr--) {
+               bch2_btree_and_journal_iter_advance(&iter);
+               struct bkey_s_c k = bch2_btree_and_journal_iter_peek(&iter);
+               if (!k.k)
+                       break;
+
+               bch2_bkey_buf_reassemble(&tmp, c, k);
+               bch2_btree_node_prefetch(iter.trans, NULL, tmp.k, iter.journal.btree_id, level - 1);
+       }
+
+       bch2_bkey_buf_exit(&tmp, c);
+}
+
 struct bkey_s_c bch2_btree_and_journal_iter_peek(struct btree_and_journal_iter *iter)
 {
        struct bkey_s_c btree_k, journal_k, ret;
+
+       if (iter->prefetch && iter->journal.level)
+               btree_and_journal_iter_prefetch(iter);
 again:
        if (iter->at_end)
                return bkey_s_c_null;
@@ -357,17 +407,18 @@ void bch2_btree_and_journal_iter_exit(struct btree_and_journal_iter *iter)
        bch2_journal_iter_exit(&iter->journal);
 }
 
-void __bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *iter,
-                                                 struct bch_fs *c,
+void __bch2_btree_and_journal_iter_init_node_iter(struct btree_trans *trans,
+                                                 struct btree_and_journal_iter *iter,
                                                  struct btree *b,
                                                  struct btree_node_iter node_iter,
                                                  struct bpos pos)
 {
        memset(iter, 0, sizeof(*iter));
 
+       iter->trans = trans;
        iter->b = b;
        iter->node_iter = node_iter;
-       bch2_journal_iter_init(c, &iter->journal, b->c.btree_id, b->c.level, pos);
+       bch2_journal_iter_init(trans->c, &iter->journal, b->c.btree_id, b->c.level, pos);
        INIT_LIST_HEAD(&iter->journal.list);
        iter->pos = b->data->min_key;
        iter->at_end = false;
@@ -377,15 +428,15 @@ void __bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter
  * this version is used by btree_gc before filesystem has gone RW and
  * multithreaded, so uses the journal_iters list:
  */
-void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *iter,
-                                               struct bch_fs *c,
+void bch2_btree_and_journal_iter_init_node_iter(struct btree_trans *trans,
+                                               struct btree_and_journal_iter *iter,
                                                struct btree *b)
 {
        struct btree_node_iter node_iter;
 
        bch2_btree_node_iter_init_from_start(&node_iter, b);
-       __bch2_btree_and_journal_iter_init_node_iter(iter, c, b, node_iter, b->data->min_key);
-       list_add(&iter->journal.list, &c->journal_iters);
+       __bch2_btree_and_journal_iter_init_node_iter(trans, iter, b, node_iter, b->data->min_key);
+       list_add(&iter->journal.list, &trans->c->journal_iters);
 }
 
 /* sort and dedup all keys in the journal: */
@@ -396,9 +447,7 @@ void bch2_journal_entries_free(struct bch_fs *c)
        struct genradix_iter iter;
 
        genradix_for_each(&c->journal_entries, iter, i)
-               if (*i)
-                       kvpfree(*i, offsetof(struct journal_replay, j) +
-                               vstruct_bytes(&(*i)->j));
+               kvfree(*i);
        genradix_free(&c->journal_entries);
 }
 
@@ -415,10 +464,16 @@ static int journal_sort_key_cmp(const void *_l, const void *_r)
                cmp_int(l->journal_offset, r->journal_offset);
 }
 
-void bch2_journal_keys_free(struct journal_keys *keys)
+void bch2_journal_keys_put(struct bch_fs *c)
 {
+       struct journal_keys *keys = &c->journal_keys;
        struct journal_key *i;
 
+       BUG_ON(atomic_read(&keys->ref) <= 0);
+
+       if (!atomic_dec_and_test(&keys->ref))
+               return;
+
        move_gap(keys->d, keys->nr, keys->size, keys->gap, keys->nr);
        keys->gap = keys->nr;
 
@@ -429,6 +484,8 @@ void bch2_journal_keys_free(struct journal_keys *keys)
        kvfree(keys->d);
        keys->d = NULL;
        keys->nr = keys->gap = keys->size = 0;
+
+       bch2_journal_entries_free(c);
 }
 
 static void __journal_keys_sort(struct journal_keys *keys)
@@ -440,9 +497,7 @@ static void __journal_keys_sort(struct journal_keys *keys)
        src = dst = keys->d;
        while (src < keys->d + keys->nr) {
                while (src + 1 < keys->d + keys->nr &&
-                      src[0].btree_id  == src[1].btree_id &&
-                      src[0].level     == src[1].level &&
-                      bpos_eq(src[0].k->k.p, src[1].k->k.p))
+                      !journal_key_cmp(src, src + 1))
                        src++;
 
                *dst++ = *src++;