From 7f9f1c551c2f89174c59fe79a2e83142caa4d2a4 Mon Sep 17 00:00:00 2001 From: Xuehan Xu Date: Thu, 3 Jul 2025 16:36:27 +0800 Subject: [PATCH] crimson/os/seastore/lba_mapping: add interfaces to determine the pending state of mappings' child extents Signed-off-by: Xuehan Xu --- src/crimson/os/seastore/cache.h | 14 +--- src/crimson/os/seastore/lba/lba_btree_node.h | 11 ++- src/crimson/os/seastore/lba_mapping.cc | 11 +++ src/crimson/os/seastore/lba_mapping.h | 9 +++ src/crimson/os/seastore/linked_tree_node.h | 82 ++++++++++++-------- 5 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index 0ae19c34317..332a5ebecba 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -449,22 +449,12 @@ public: std::forward(extent_init_func)); } - bool is_viewable_extent_stable( + CachedExtentRef peek_extent_viewable_by_trans( Transaction &t, CachedExtentRef extent) final { assert(extent); - auto view = extent->get_transactional_view(t); - return view->is_stable(); - } - - bool is_viewable_extent_data_stable( - Transaction &t, - CachedExtentRef extent) final - { - assert(extent); - auto view = extent->get_transactional_view(t); - return view->is_data_stable(); + return extent->get_transactional_view(t); } get_extent_iertr::future<> maybe_wait_accessible( diff --git a/src/crimson/os/seastore/lba/lba_btree_node.h b/src/crimson/os/seastore/lba/lba_btree_node.h index 05f26b6b292..94b73c342cd 100644 --- a/src/crimson/os/seastore/lba/lba_btree_node.h +++ b/src/crimson/os/seastore/lba/lba_btree_node.h @@ -217,13 +217,20 @@ struct LBALeafNode op_context_t c, uint16_t pos, laddr_t key) const { - return parent_node_t::_is_child_stable(c.trans, c.cache, pos, key); + return parent_node_t::is_child_stable(c.trans, c.cache, pos, key); } bool is_child_data_stable( op_context_t c, uint16_t pos, laddr_t key) const { - return parent_node_t::_is_child_stable(c.trans, c.cache, pos, key, true); + return parent_node_t::is_child_stable(c.trans, c.cache, pos, key, true); + } + bool is_child_initial_pending( + op_context_t c, + uint16_t pos, + laddr_t key) const { + return parent_node_t::is_child_initial_pending( + c.trans, c.cache, pos, key); } void on_split( diff --git a/src/crimson/os/seastore/lba_mapping.cc b/src/crimson/os/seastore/lba_mapping.cc index a4bbf4a41ff..53b52b39e92 100644 --- a/src/crimson/os/seastore/lba_mapping.cc +++ b/src/crimson/os/seastore/lba_mapping.cc @@ -129,4 +129,15 @@ LBAMapping::refresh_iertr::future LBAMapping::refresh() }); } +bool LBAMapping::is_initial_pending() const { + assert(is_linked_direct()); + ceph_assert(direct_cursor->is_viewable()); + assert(!direct_cursor->is_end()); + auto leaf = direct_cursor->parent->cast(); + return leaf->is_child_initial_pending( + direct_cursor->ctx, + direct_cursor->pos, + direct_cursor->key); +} + } // namespace crimson::os::seastore diff --git a/src/crimson/os/seastore/lba_mapping.h b/src/crimson/os/seastore/lba_mapping.h index cefb288713f..2fc06fac069 100644 --- a/src/crimson/os/seastore/lba_mapping.h +++ b/src/crimson/os/seastore/lba_mapping.h @@ -51,6 +51,9 @@ public: return !is_indirect() && !is_data_stable(); } + // whether the mapping corresponds to an initial pending extent + bool is_initial_pending() const; + bool is_linked_direct() const { return (bool)direct_cursor; } @@ -155,7 +158,13 @@ public: get_child_ret_t get_logical_extent(Transaction &t) const; + LogicalChildNodeRef peek_logical_extent(Transaction &t) const; + using refresh_iertr = LBACursor::base_iertr; + //TODO: should be changed to return future<> once all calls + // to refresh are through co_await. We return LBAMapping + // for now to avoid mandating the callers to make sure + // the life of the lba mapping survives the refresh. refresh_iertr::future refresh(); using next_iertr = LBACursor::base_iertr; diff --git a/src/crimson/os/seastore/linked_tree_node.h b/src/crimson/os/seastore/linked_tree_node.h index 2dd152b07e7..40f9aa513af 100644 --- a/src/crimson/os/seastore/linked_tree_node.h +++ b/src/crimson/os/seastore/linked_tree_node.h @@ -251,8 +251,8 @@ public: } virtual get_child_iertr::future<> maybe_wait_accessible( Transaction &, CachedExtent&) = 0; - virtual bool is_viewable_extent_data_stable(Transaction &, CachedExtentRef) = 0; - virtual bool is_viewable_extent_stable(Transaction &, CachedExtentRef) = 0; + virtual CachedExtentRef peek_extent_viewable_by_trans( + Transaction &t, CachedExtentRef extent) = 0; virtual ~ExtentTransViewRetriever() {} protected: virtual get_child_iertr::future get_extent_viewable_by_trans( @@ -884,54 +884,68 @@ protected: assert(me.validate_stable_children()); } - // children are considered stable if any of the following case is true: - // 1. The child extent is absent in cache - // 2. The child extent is (data) stable - // - // For reserved mappings, the return values are undefined. - bool _is_child_stable( + CachedExtentRef peek_child( Transaction &t, ExtentTransViewRetriever &etvr, btreenode_pos_t pos, - node_key_t key, - bool data_only = false) const { + node_key_t key) const + { auto &me = down_cast(); - assert(key == me.iter_idx(pos).get_key()); - auto child = this->children[pos]; + assert(children.capacity()); + assert(key == down_cast().iter_idx(pos).get_key()); + auto child = children[pos]; if (is_reserved_ptr(child)) { - return true; + return nullptr; } else if (is_valid_child_ptr(child)) { - assert(dynamic_cast(child)->is_logical()); - assert( - dynamic_cast(child)->is_pending_in_trans(t.get_trans_id()) - || me.is_stable_ready()); - if (data_only) { - return etvr.is_viewable_extent_data_stable( - t, dynamic_cast(child)); - } else { - return etvr.is_viewable_extent_stable( - t, dynamic_cast(child)); - } + return etvr.peek_extent_viewable_by_trans( + t, dynamic_cast(child)); } else if (me.is_pending()) { - auto key = me.iter_idx(pos).get_key(); auto &sparent = me.get_stable_for_key(key); auto spos = sparent.lower_bound(key).get_offset(); auto child = sparent.children[spos]; if (is_valid_child_ptr(child)) { - assert(dynamic_cast(child)->is_logical()); - if (data_only) { - return etvr.is_viewable_extent_data_stable( - t, dynamic_cast(child)); - } else { - return etvr.is_viewable_extent_stable( - t, dynamic_cast(child)); - } + return etvr.peek_extent_viewable_by_trans( + t, dynamic_cast(child)); } else { - return true; + return nullptr; } } else { + return nullptr; + } + } + + // children are considered stable if any of the following case is true: + // 1. The child extent is absent in cache + // 2. The child extent is (data) stable + // + // For reserved mappings, the return values are undefined. + bool is_child_stable( + Transaction &t, + ExtentTransViewRetriever &etvr, + btreenode_pos_t pos, + node_key_t key, + bool data_only = false) const { + auto extent = peek_child(t, etvr, pos, key); + if (!extent) { return true; } + if (data_only) { + return extent->is_data_stable(); + } else { + return extent->is_stable(); + } + } + + bool is_child_initial_pending( + Transaction &t, + ExtentTransViewRetriever &etvr, + btreenode_pos_t pos, + node_key_t key) const { + auto extent = peek_child(t, etvr, pos, key); + if (!extent) { + return false; + } + return extent->is_initial_pending(); } parent_tracker_t* my_tracker = nullptr; -- 2.39.5