From: Zhang Song Date: Tue, 22 Apr 2025 08:16:12 +0000 (+0800) Subject: crimson/os/seastore/btree: introduce BtreeCursor X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=4a8aecc99557f8d873ac1089763f3881b71d9923;p=ceph.git crimson/os/seastore/btree: introduce BtreeCursor Signed-off-by: Zhang Song (cherry picked from commit 972c139e9c5c1405378495fa9d50b1a314dea618) --- diff --git a/src/crimson/os/seastore/btree/btree_types.cc b/src/crimson/os/seastore/btree/btree_types.cc index 61f50e574916a..a8d6e883153f6 100644 --- a/src/crimson/os/seastore/btree/btree_types.cc +++ b/src/crimson/os/seastore/btree/btree_types.cc @@ -2,6 +2,8 @@ // vim: ts=8 sw=2 smarttab #include "crimson/os/seastore/btree/btree_types.h" +#include "crimson/os/seastore/lba_manager/btree/lba_btree_node.h" +#include "crimson/os/seastore/backref/backref_tree_node.h" namespace crimson::os::seastore { @@ -29,4 +31,40 @@ std::ostream& operator<<(std::ostream &out, const backref_map_val_t& val) { } } // namespace backref + +namespace { +template +bool modified_since(T &&extent, uint64_t iter_modifications) { + using backref::BackrefLeafNode; + using lba_manager::btree::LBALeafNode; + if constexpr (std::is_same_v) { + assert(extent->get_type() == extent_types_t::LADDR_LEAF); + auto leaf = extent->template cast(); + return leaf->modified_since(iter_modifications); + } else { + assert(extent->get_type() == extent_types_t::BACKREF_LEAF); + auto leaf = extent->template cast(); + return leaf->modified_since(iter_modifications); + } +} +} + +template +bool BtreeCursor::is_viewable() const { + LOG_PREFIX(BtreeCursor::is_viewable()); + if (!parent->is_valid() || + modified_since(parent, modifications)) { + return false; + } + + auto [viewable, state] = parent->is_viewable_by_trans(ctx.trans); + assert(state != CachedExtent::viewable_state_t::invalid); + SUBTRACET(seastore_cache, "{} with viewable state {}", + ctx.trans, *parent, state); + return viewable; +} + +template struct BtreeCursor; +template struct BtreeCursor; + } // namespace crimson::os::seastore diff --git a/src/crimson/os/seastore/btree/btree_types.h b/src/crimson/os/seastore/btree/btree_types.h index 1c850a31cd062..cd616ee6e96ca 100644 --- a/src/crimson/os/seastore/btree/btree_types.h +++ b/src/crimson/os/seastore/btree/btree_types.h @@ -192,4 +192,142 @@ struct __attribute__((packed)) backref_map_val_le_t { } // namespace backerf +/** + * BtreeCursor + * + * BtreeCursor is the type-erased wrapper for FixedKVBtree::iterator, stores + * a key-value mapping's location and the snapshot of its data at construction + * time. + */ +template +struct BtreeCursor { + BtreeCursor( + op_context_t &ctx, + CachedExtentRef parent, + uint64_t modifications, + key_t key, + std::optional val, + btreenode_pos_t pos) + : ctx(ctx), + parent(std::move(parent)), + modifications(modifications), + key(key), + val(std::move(val)), + pos(pos) + { + if constexpr (std::is_same_v) { + static_assert(std::is_same_v, + "the value type of laddr_t for BtreeCursor should be lba_map_val_t"); + } else { + static_assert(std::is_same_v, + "the key type of BtreeCursor should be either laddr_t or paddr_t"); + static_assert(std::is_same_v, + "the value type should be either lba_map_val_t or backref_map_val_t"); + } + } + + op_context_t ctx; + CachedExtentRef parent; + uint64_t modifications; + key_t key; + std::optional val; + btreenode_pos_t pos; + + // NOTE: The overhead of calling is_viewable() might be not negligible in the + // case of the parent extent is stable and shared by multiple transactions. + // The best practice is to only hold cursors whose parent is pending in + // current transaction in the long term. + bool is_viewable() const; + + bool is_end() const { + auto max_key = min_max_t::max; + assert((key != max_key) == (bool)val); + return key == max_key; + } + + extent_len_t get_length() const { + assert(!is_end()); + return val->len; + } +}; + +struct LBACursor : BtreeCursor { + using Base = BtreeCursor; + using Base::BtreeCursor; + bool is_indirect() const { + assert(!is_end()); + return val->pladdr.is_laddr(); + } + laddr_t get_laddr() const { + return key; + } + paddr_t get_paddr() const { + assert(!is_indirect()); + assert(!is_end()); + return val->pladdr.get_paddr(); + } + laddr_t get_intermediate_key() const { + assert(is_indirect()); + assert(!is_end()); + return val->pladdr.get_laddr(); + } + checksum_t get_checksum() const { + assert(!is_end()); + assert(!is_indirect()); + return val->checksum; + } + extent_ref_count_t get_refcount() const { + assert(!is_end()); + assert(!is_indirect()); + return val->refcount; + } + std::unique_ptr duplicate() const { + return std::make_unique(*this); + } +}; +using LBACursorRef = std::unique_ptr; + +struct BackrefCursor : BtreeCursor { + using Base = BtreeCursor; + using Base::BtreeCursor; + paddr_t get_paddr() const { + return key; + } + laddr_t get_laddr() const { + assert(!is_end()); + return val->laddr; + } + extent_types_t get_type() const { + assert(!is_end()); + return val->type; + } +}; +using BackrefCursorRef = std::unique_ptr; + +template +std::ostream &operator<<( + std::ostream &out, const BtreeCursor &cursor) +{ + if constexpr (std::is_same_v) { + out << "LBACursor("; + } else { + out << "BackrefCursor("; + } + out << (void*)cursor.parent.get() + << "@" << cursor.pos + << "#" << cursor.modifications + << ","; + if (cursor.is_end()) { + return out << "END)"; + } + return out << "," << cursor.key + << "~" << *cursor.val + << ")"; +} + } // namespace crimson::os::seastore + +#if FMT_VERSION >= 90000 +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; +#endif diff --git a/src/crimson/os/seastore/linked_tree_node.h b/src/crimson/os/seastore/linked_tree_node.h index 154353776a256..6a903df257145 100644 --- a/src/crimson/os/seastore/linked_tree_node.h +++ b/src/crimson/os/seastore/linked_tree_node.h @@ -9,10 +9,6 @@ namespace crimson::os::seastore { -// XXX: It happens to be true that the width of node -// index in lba and omap tree are the same. -using btreenode_pos_t = uint16_t; - template class child_pos_t { public: diff --git a/src/crimson/os/seastore/seastore_types.h b/src/crimson/os/seastore/seastore_types.h index 74c2e2f404a21..5a80c6ef720f5 100644 --- a/src/crimson/os/seastore/seastore_types.h +++ b/src/crimson/os/seastore/seastore_types.h @@ -77,6 +77,12 @@ using checksum_t = uint32_t; using checksum_le_t = ceph_le32; constexpr checksum_t CRC_NULL = 0; +// XXX: It happens to be true that the width of node +// index in lba and omap tree are the same. +using btreenode_pos_t = uint16_t; +constexpr auto BTREENODE_POS_MAX = std::numeric_limits::max(); +constexpr auto BTREENODE_POS_NULL = BTREENODE_POS_MAX; + // Immutable metadata for seastore to set at mkfs time struct seastore_meta_t { uuid_d seastore_id;