]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore/transaction_manager: invalidate
authorXuehan Xu <xuxuehan@qianxin.com>
Mon, 21 Jul 2025 12:01:18 +0000 (20:01 +0800)
committerXuehan Xu <xxhdx1985126@gmail.com>
Tue, 12 Aug 2025 05:43:25 +0000 (13:43 +0800)
RetiredExtentPlaceholder when reading extents

Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/linked_tree_node.h
src/crimson/os/seastore/logical_child_node.h
src/crimson/os/seastore/transaction_manager.h

index 97cc7b6568a93c6b07985e30007cf6d461228b08..1259f52eac0de26b29dc9770ca75f89e0453f7b0 100644 (file)
@@ -102,7 +102,8 @@ class SegmentProvider;
  * - TRACE: DEBUG details
  * - seastore_t logs
  */
-class Cache : public ExtentTransViewRetriever {
+class Cache : public ExtentTransViewRetriever,
+             public RetiredExtentPlaceholderInvalidater {
 public:
   using base_ertr = crimson::errorator<
     crimson::ct_error::input_output_error>;
@@ -369,6 +370,18 @@ public:
     }
   }
 
+  void invalidate_retired_placeholder(
+    Transaction &t,
+    CachedExtent &retired_placeholder,
+    CachedExtent &extent) {
+    // replace placeholder in transactions
+    while (!retired_placeholder.read_transactions.empty()) {
+      auto t = retired_placeholder.read_transactions.begin()->t;
+      t->replace_placeholder(retired_placeholder, extent);
+    }
+    retired_placeholder.set_invalid(t);
+  }
+
   /*
    * get_absent_extent
    *
index 888ecb5d6bf172c6fd086ae92e1714b4498d4062..308f53ff8dc9361a4a72e37d07cef323087240a2 100644 (file)
@@ -9,11 +9,27 @@
 
 namespace crimson::os::seastore {
 
+struct RetiredExtentPlaceholderInvalidater {
+  virtual void invalidate_retired_placeholder(
+    Transaction &t,
+    CachedExtent &retired_placeholder,
+    CachedExtent &extent) = 0;
+};
+
 template <typename ParentT>
 class child_pos_t {
 public:
   child_pos_t(TCachedExtentRef<ParentT> stable_parent, btreenode_pos_t pos)
     : stable_parent(stable_parent), pos(pos) {}
+  child_pos_t(
+    TCachedExtentRef<ParentT> stable_parent,
+    btreenode_pos_t pos,
+    CachedExtent* placeholder)
+    : stable_parent(stable_parent),
+      pos(pos),
+      retired_placeholder(placeholder) {
+    assert(retired_placeholder->is_placeholder());
+  }
 
   TCachedExtentRef<ParentT> get_parent() {
     ceph_assert(stable_parent);
@@ -26,9 +42,18 @@ public:
   void link_child(ChildT *c) {
     get_parent()->link_child(c, pos);
   }
+  void invalidate_retired_placeholder(
+    Transaction &t,
+    RetiredExtentPlaceholderInvalidater &repi,
+    CachedExtent &extent) {
+    if (retired_placeholder) {
+      repi.invalidate_retired_placeholder(t, *retired_placeholder, extent);
+    }
+  }
 private:
   TCachedExtentRef<ParentT> stable_parent;
   btreenode_pos_t pos = std::numeric_limits<btreenode_pos_t>::max();
+  CachedExtentRef retired_placeholder;
 };
 
 using get_child_iertr = trans_iertr<crimson::errorator<
@@ -204,6 +229,7 @@ public:
     return parent_tracker->get_parent();
   }
   virtual key_t node_begin() const = 0;
+  virtual bool is_retired_placeholder() const = 0;
 protected:
   parent_tracker_ref<ParentT> parent_tracker;
   virtual bool _is_valid() const = 0;
@@ -328,15 +354,26 @@ public:
     auto child = children[pos];
     ceph_assert(!is_reserved_ptr(child));
     if (is_valid_child_ptr(child)) {
-      return etvr.get_extent_viewable_by_trans<ChildT>(
-       t, static_cast<ChildT*>(child));
+      if (child->is_retired_placeholder()) {
+       assert(me.is_stable());
+       return child_pos_t<T>(
+         &me, pos, dynamic_cast<CachedExtent*>(child));
+      } else {
+       return etvr.get_extent_viewable_by_trans<ChildT>(
+         t, static_cast<ChildT*>(child));
+      }
     } else if (me.is_pending()) {
       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)) {
-       return etvr.get_extent_viewable_by_trans<ChildT>(
-         t, static_cast<ChildT*>(child));
+       if (child->is_retired_placeholder()) {
+         return child_pos_t<T>(
+           &sparent, spos, dynamic_cast<CachedExtent*>(child));
+       } else {
+         return etvr.get_extent_viewable_by_trans<ChildT>(
+           t, static_cast<ChildT*>(child));
+       }
       } else {
        return child_pos_t<T>(&sparent, spos);
       }
@@ -352,7 +389,10 @@ public:
     assert(child);
     ceph_assert(me.is_stable());
     assert(child->_is_stable());
-    assert(!children[pos]);
+    if (unlikely(children[pos] != nullptr)) {
+      assert(is_valid_child_ptr(children[pos]));
+      assert(children[pos]->is_retired_placeholder());
+    }
     ceph_assert(is_valid_child_ptr(child));
     update_child_ptr(pos, child);
   }
@@ -1034,6 +1074,10 @@ public:
     }
   }
 
+  bool is_retired_placeholder() const final {
+    auto &me = down_cast();
+    return me.is_placeholder();
+  }
 protected:
   void on_invalidated() {
     this->reset_parent_tracker();
index 71e6ee0ed136bfa9bae3015c82252e59d2d707b2..722060d8b7a6d2bfecf025a2715c9548011693d7 100644 (file)
@@ -25,6 +25,8 @@ class RetiredExtentPlaceholder
   : public CachedExtent,
     public ChildNode<lba::LBALeafNode, RetiredExtentPlaceholder, laddr_t> {
 
+  using lba_child_node_t =
+    ChildNode<lba::LBALeafNode, RetiredExtentPlaceholder, laddr_t>;
 public:
   RetiredExtentPlaceholder(extent_len_t length)
     : CachedExtent(CachedExtent::retired_placeholder_construct_t{}, length) {}
@@ -35,6 +37,10 @@ public:
     }
   }
 
+  void on_invalidated(Transaction&) final {
+    this->lba_child_node_t::on_invalidated();
+  }
+
   CachedExtentRef duplicate_for_write(Transaction&) final {
     ceph_abort_msg("Should never happen for a placeholder");
     return CachedExtentRef();
index 98f0d0188183014672298bb6e04375dbec667c19..9bfb310cce1f8d3353e1b52bf52383100c4b586e 100644 (file)
@@ -1445,12 +1445,14 @@ private:
       partial_len,
       [laddr=pin.get_intermediate_base(),
        maybe_init=std::move(maybe_init),
-       child_pos=std::move(child_pos)]
+       child_pos=std::move(child_pos),
+       &t, this]
       (T &extent) mutable {
        assert(extent.is_logical());
        assert(!extent.has_laddr());
        assert(!extent.has_been_invalidated());
        child_pos.link_child(&extent);
+       child_pos.invalidate_retired_placeholder(t, *cache, extent);
        extent.set_laddr(laddr);
        maybe_init(extent);
        extent.set_seen_by_users();
@@ -1517,12 +1519,14 @@ private:
       pin.get_val(),
       direct_key,
       direct_length,
-      [direct_key, child_pos=std::move(child_pos)](CachedExtent &extent) mutable {
+      [direct_key, child_pos=std::move(child_pos),
+      &t, this](CachedExtent &extent) mutable {
        assert(extent.is_logical());
        auto &lextent = static_cast<LogicalChildNode&>(extent);
        assert(!lextent.has_laddr());
        assert(!lextent.has_been_invalidated());
        child_pos.link_child(&lextent);
+       child_pos.invalidate_retired_placeholder(t, *cache, lextent);
        lextent.set_laddr(direct_key);
         // No change to extent::seen_by_user because this path is only
         // for background cleaning.