]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore: refactor LBAMapping 61261/head
authorXuehan Xu <xuxuehan@qianxin.com>
Wed, 8 Jan 2025 08:07:21 +0000 (16:07 +0800)
committerXuehan Xu <xuxuehan@qianxin.com>
Fri, 10 Jan 2025 07:15:56 +0000 (15:15 +0800)
So that PhyscalNodeMapping doesn't contain LBAMapping specific
interfaces

Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
14 files changed:
src/crimson/os/seastore/CMakeLists.txt
src/crimson/os/seastore/async_cleaner.h
src/crimson/os/seastore/backref/btree_backref_manager.h
src/crimson/os/seastore/backref_manager.h
src/crimson/os/seastore/backref_mapping.h [new file with mode: 0644]
src/crimson/os/seastore/btree/btree_range_pin.cc [deleted file]
src/crimson/os/seastore/btree/btree_range_pin.h
src/crimson/os/seastore/cached_extent.cc
src/crimson/os/seastore/cached_extent.h
src/crimson/os/seastore/lba_manager.h
src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc
src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.h
src/crimson/os/seastore/lba_mapping.cc [new file with mode: 0644]
src/crimson/os/seastore/lba_mapping.h [new file with mode: 0644]

index e5b8960c38c1bb5a4f0dcdfd1cb8ccfbbe52128e..3da5e65ceec7be7d91f4448307986b67f27804ab 100644 (file)
@@ -1,5 +1,6 @@
 set(crimson_seastore_srcs
   cached_extent.cc
+  lba_mapping.cc
   seastore_types.cc
   segment_manager.cc
   segment_manager/ephemeral.cc
@@ -19,7 +20,6 @@ set(crimson_seastore_srcs
   omap_manager.cc
   omap_manager/btree/btree_omap_manager.cc
   omap_manager/btree/omap_btree_node_impl.cc
-  btree/btree_range_pin.cc
   btree/fixed_kv_node.cc
   onode.cc
   onode_manager/staged-fltree/node.cc
index 424247c5bdc20509abcd31d334ebe70c5e4a98e2..b907b1ffcea03fb68faa375f4f571033d1f04833 100644 (file)
@@ -17,6 +17,7 @@
 #include "crimson/os/seastore/randomblock_manager_group.h"
 #include "crimson/os/seastore/transaction.h"
 #include "crimson/os/seastore/segment_seq_allocator.h"
+#include "crimson/os/seastore/backref_mapping.h"
 
 namespace crimson::os::seastore {
 
index 38084bb00e6979350d441863d70390446043fecf..24897dd55da567af02db955b0b0391bfbc2f432b 100644 (file)
@@ -9,44 +9,28 @@
 
 namespace crimson::os::seastore::backref {
 
-constexpr size_t BACKREF_BLOCK_SIZE = 4096;
-
-class BtreeBackrefMapping : public BtreeNodeMapping<paddr_t, laddr_t> {
-  extent_types_t type;
+class BtreeBackrefMapping : public BackrefMapping {
 public:
   BtreeBackrefMapping(op_context_t<paddr_t> ctx)
-    : BtreeNodeMapping(ctx) {}
+    : BackrefMapping(ctx) {}
   BtreeBackrefMapping(
     op_context_t<paddr_t> ctx,
     CachedExtentRef parent,
     uint16_t pos,
     backref_map_val_t &val,
     backref_node_meta_t &&meta)
-    : BtreeNodeMapping(
+    : BackrefMapping(
+       val.type,
        ctx,
        parent,
        pos,
        val.laddr,
        val.len,
-       std::forward<backref_node_meta_t>(meta)),
-      type(val.type)
-  {}
-  extent_types_t get_type() const final {
-    return type;
-  }
-
-  bool is_clone() const final {
-    return false;
-  }
-
-protected:
-  std::unique_ptr<BtreeNodeMapping<paddr_t, laddr_t>> _duplicate(
-    op_context_t<paddr_t> ctx) const final {
-    return std::unique_ptr<BtreeNodeMapping<paddr_t, laddr_t>>(
-      new BtreeBackrefMapping(ctx));
-  }
+       std::forward<backref_node_meta_t>(meta)) {}
 };
 
+constexpr size_t BACKREF_BLOCK_SIZE = 4096;
+
 using BackrefBtree = FixedKVBtree<
   paddr_t, backref_map_val_t, BackrefInternalNode,
   BackrefLeafNode, BtreeBackrefMapping, BACKREF_BLOCK_SIZE, false>;
index 3feedb997b4c39c674993a5751fb8d3a33b529b8..8c746b571b2257c07922b371de26bc8a62af0025 100644 (file)
@@ -6,6 +6,7 @@
 #include "crimson/os/seastore/cache.h"
 #include "crimson/os/seastore/cached_extent.h"
 #include "crimson/os/seastore/transaction.h"
+#include "crimson/os/seastore/backref_mapping.h"
 
 namespace crimson::os::seastore {
 
diff --git a/src/crimson/os/seastore/backref_mapping.h b/src/crimson/os/seastore/backref_mapping.h
new file mode 100644 (file)
index 0000000..d0a6a0e
--- /dev/null
@@ -0,0 +1,27 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include "crimson/os/seastore/btree/btree_range_pin.h"
+
+namespace crimson::os::seastore {
+
+class BackrefMapping : public BtreeNodeMapping<paddr_t, laddr_t> {
+  extent_types_t type;
+public:
+  BackrefMapping(op_context_t<paddr_t> ctx)
+    : BtreeNodeMapping(ctx) {}
+  template <typename... T>
+  BackrefMapping(extent_types_t type, T&&... t)
+    : BtreeNodeMapping(std::forward<T>(t)...),
+      type(type) {}
+  extent_types_t get_type() const {
+    return type;
+  }
+};
+
+using BackrefMappingRef = std::unique_ptr<BackrefMapping>;
+using backref_pin_list_t = std::list<BackrefMappingRef>;
+
+} // namespace crimson::os::seastore
diff --git a/src/crimson/os/seastore/btree/btree_range_pin.cc b/src/crimson/os/seastore/btree/btree_range_pin.cc
deleted file mode 100644 (file)
index f0d507a..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "crimson/os/seastore/btree/btree_range_pin.h"
-#include "crimson/os/seastore/btree/fixed_kv_node.h"
-
-namespace crimson::os::seastore {
-
-template <typename key_t, typename val_t>
-get_child_ret_t<LogicalCachedExtent>
-BtreeNodeMapping<key_t, val_t>::get_logical_extent(
-  Transaction &t)
-{
-  ceph_assert(is_parent_viewable());
-  assert(pos != std::numeric_limits<uint16_t>::max());
-  ceph_assert(t.get_trans_id() == ctx.trans.get_trans_id());
-  auto &p = (FixedKVNode<key_t>&)*parent;
-  auto k = this->is_indirect()
-    ? this->get_intermediate_base()
-    : get_key();
-  auto v = p.template get_child<LogicalCachedExtent>(ctx, pos, k);
-  if (!v.has_child()) {
-    this->child_pos = v.get_child_pos();
-  }
-  return v;
-}
-
-template <typename key_t, typename val_t>
-bool BtreeNodeMapping<key_t, val_t>::is_stable() const
-{
-  assert(!this->parent_modified());
-  assert(pos != std::numeric_limits<uint16_t>::max());
-  auto &p = (FixedKVNode<key_t>&)*parent;
-  auto k = this->is_indirect()
-    ? this->get_intermediate_base()
-    : get_key();
-  return p.is_child_stable(ctx, pos, k);
-}
-
-template <typename key_t, typename val_t>
-bool BtreeNodeMapping<key_t, val_t>::is_data_stable() const
-{
-  assert(!this->parent_modified());
-  assert(pos != std::numeric_limits<uint16_t>::max());
-  auto &p = (FixedKVNode<key_t>&)*parent;
-  auto k = this->is_indirect()
-    ? this->get_intermediate_base()
-    : get_key();
-  return p.is_child_data_stable(ctx, pos, k);
-}
-
-template class BtreeNodeMapping<laddr_t, paddr_t>;
-template class BtreeNodeMapping<paddr_t, laddr_t>;
-} // namespace crimson::os::seastore
index 91751801e5d6c48d67d52ce4520483ef746baacf..bfd350a8bed4fd980a6e14908d42cc27791e5439 100644 (file)
@@ -7,11 +7,12 @@
 
 #include "crimson/common/log.h"
 
-#include "crimson/os/seastore/cache.h"
 #include "crimson/os/seastore/cached_extent.h"
 #include "crimson/os/seastore/seastore_types.h"
+#include "crimson/os/seastore/transaction.h"
 
 namespace crimson::os::seastore {
+class Cache;
 
 template <typename node_key_t>
 struct op_context_t {
@@ -116,8 +117,6 @@ protected:
   extent_len_t len = 0;
   fixed_kv_node_meta_t<key_t> range;
   uint16_t pos = std::numeric_limits<uint16_t>::max();
-
-  virtual std::unique_ptr<BtreeNodeMapping> _duplicate(op_context_t<key_t>) const = 0;
   fixed_kv_node_meta_t<key_t> _get_pin_range() const {
     return range;
   }
@@ -139,11 +138,7 @@ public:
       len(len),
       range(meta),
       pos(pos)
-  {
-    if (!parent->is_pending()) {
-      this->child_pos = {parent, pos};
-    }
-  }
+  {}
 
   CachedExtentRef get_parent() const final {
     return parent;
@@ -162,11 +157,6 @@ public:
     return len;
   }
 
-  extent_types_t get_type() const override {
-    ceph_abort("should never happen");
-    return extent_types_t::ROOT;
-  }
-
   val_t get_val() const final {
     if constexpr (std::is_same_v<val_t, paddr_t>) {
       return value.get_paddr();
@@ -180,16 +170,6 @@ public:
     return range.begin;
   }
 
-  PhysicalNodeMappingRef<key_t, val_t> duplicate() const final {
-    auto ret = _duplicate(ctx);
-    ret->range = range;
-    ret->value = value;
-    ret->parent = parent;
-    ret->len = len;
-    ret->pos = pos;
-    return ret;
-  }
-
   bool has_been_invalidated() const final {
     return parent->has_been_invalidated();
   }
@@ -215,9 +195,6 @@ public:
     return unviewable;
   }
 
-  get_child_ret_t<LogicalCachedExtent> get_logical_extent(Transaction&) final;
-  bool is_stable() const final;
-  bool is_data_stable() const final;
   bool is_parent_viewable() const final {
     ceph_assert(parent);
     if (!parent->is_valid()) {
index ab2492f5bb67df280e686f405d01b09f2795286c..49fede1d9a8696a97e411bed9ebe195dadbbab17 100644 (file)
@@ -7,6 +7,7 @@
 #include "crimson/common/log.h"
 
 #include "crimson/os/seastore/btree/fixed_kv_node.h"
+#include "crimson/os/seastore/lba_mapping.h"
 
 namespace {
   [[maybe_unused]] seastar::logger& logger() {
@@ -142,6 +143,12 @@ void LogicalCachedExtent::on_replace_prior() {
   parent->children[off] = this;
 }
 
+void LogicalCachedExtent::maybe_set_intermediate_laddr(LBAMapping &mapping) {
+  laddr = mapping.is_indirect()
+    ? mapping.get_intermediate_base()
+    : mapping.get_key();
+}
+
 parent_tracker_t::~parent_tracker_t() {
   // this is parent's tracker, reset it
   auto &p = (FixedKVNode<laddr_t>&)*parent;
@@ -150,32 +157,6 @@ parent_tracker_t::~parent_tracker_t() {
   }
 }
 
-std::ostream &operator<<(std::ostream &out, const LBAMapping &rhs)
-{
-  out << "LBAMapping(" << rhs.get_key()
-      << "~0x" << std::hex << rhs.get_length() << std::dec
-      << "->" << rhs.get_val();
-  if (rhs.is_indirect()) {
-    out << ",indirect(" << rhs.get_intermediate_base()
-        << "~0x" << std::hex << rhs.get_intermediate_length()
-        << "@0x" << rhs.get_intermediate_offset() << std::dec
-        << ")";
-  }
-  out << ")";
-  return out;
-}
-
-std::ostream &operator<<(std::ostream &out, const lba_pin_list_t &rhs)
-{
-  bool first = true;
-  out << '[';
-  for (const auto &i: rhs) {
-    out << (first ? "" : ",") << *i;
-    first = false;
-  }
-  return out << ']';
-}
-
 bool BufferSpace::is_range_loaded(extent_len_t offset, extent_len_t length) const
 {
   assert(length > 0);
index f9356f40b830fc51babb08692167eee7ce94f112..9dc60d719eb06fe2f117bb1da8b9ad8822bcc09d 100644 (file)
@@ -1279,7 +1279,6 @@ private:
 };
 
 class ChildableCachedExtent;
-class LogicalCachedExtent;
 
 class child_pos_t {
 public:
@@ -1337,48 +1336,18 @@ using PhysicalNodeMappingRef = std::unique_ptr<PhysicalNodeMapping<key_t, val_t>
 template <typename key_t, typename val_t>
 class PhysicalNodeMapping {
 public:
+  PhysicalNodeMapping() = default;
+  PhysicalNodeMapping(const PhysicalNodeMapping&) = delete;
   virtual extent_len_t get_length() const = 0;
-  virtual extent_types_t get_type() const = 0;
   virtual val_t get_val() const = 0;
   virtual key_t get_key() const = 0;
-  virtual PhysicalNodeMappingRef<key_t, val_t> duplicate() const = 0;
-  virtual PhysicalNodeMappingRef<key_t, val_t> refresh_with_pending_parent() {
-    ceph_abort("impossible");
-    return {};
-  }
   virtual bool has_been_invalidated() const = 0;
   virtual CachedExtentRef get_parent() const = 0;
   virtual uint16_t get_pos() const = 0;
-  // An lba pin may be indirect, see comments in lba_manager/btree/btree_lba_manager.h
-  virtual bool is_indirect() const { return false; }
-  virtual key_t get_intermediate_key() const { return min_max_t<key_t>::null; }
-  virtual key_t get_intermediate_base() const { return min_max_t<key_t>::null; }
-  virtual extent_len_t get_intermediate_length() const { return 0; }
   virtual uint32_t get_checksum() const {
     ceph_abort("impossible");
     return 0;
   }
-  // The start offset of the pin, must be 0 if the pin is not indirect
-  virtual extent_len_t get_intermediate_offset() const {
-    return std::numeric_limits<extent_len_t>::max();
-  }
-
-  virtual get_child_ret_t<LogicalCachedExtent>
-  get_logical_extent(Transaction &t) = 0;
-
-  void link_child(ChildableCachedExtent *c) {
-    ceph_assert(child_pos);
-    child_pos->link_child(c);
-  }
-
-  // For reserved mappings, the return values are
-  // undefined although it won't crash
-  virtual bool is_stable() const = 0;
-  virtual bool is_data_stable() const = 0;
-  virtual bool is_clone() const = 0;
-  bool is_zero_reserved() const {
-    return !get_val().is_real();
-  }
   virtual bool is_parent_viewable() const = 0;
   virtual bool is_parent_valid() const = 0;
   virtual bool parent_modified() const {
@@ -1391,24 +1360,8 @@ public:
   }
 
   virtual ~PhysicalNodeMapping() {}
-protected:
-  std::optional<child_pos_t> child_pos = std::nullopt;
 };
 
-using LBAMapping = PhysicalNodeMapping<laddr_t, paddr_t>;
-using LBAMappingRef = PhysicalNodeMappingRef<laddr_t, paddr_t>;
-
-std::ostream &operator<<(std::ostream &out, const LBAMapping &rhs);
-
-using lba_pin_list_t = std::list<LBAMappingRef>;
-
-std::ostream &operator<<(std::ostream &out, const lba_pin_list_t &rhs);
-
-using BackrefMapping = PhysicalNodeMapping<paddr_t, laddr_t>;
-using BackrefMappingRef = PhysicalNodeMappingRef<paddr_t, laddr_t>;
-
-using backref_pin_list_t = std::list<BackrefMappingRef>;
-
 /**
  * RetiredExtentPlaceholder
  *
@@ -1522,6 +1475,8 @@ private:
     return out;
   }
 };
+
+class LBAMapping;
 /**
  * LogicalCachedExtent
  *
@@ -1556,11 +1511,7 @@ public:
     laddr = nladdr;
   }
 
-  void maybe_set_intermediate_laddr(LBAMapping &mapping) {
-    laddr = mapping.is_indirect()
-      ? mapping.get_intermediate_base()
-      : mapping.get_key();
-  }
+  void maybe_set_intermediate_laddr(LBAMapping &mapping);
 
   void apply_delta_and_adjust_crc(
     paddr_t base, const ceph::bufferlist &bl) final {
@@ -1660,8 +1611,6 @@ using lextent_list_t = addr_extent_list_base_t<
 }
 
 #if FMT_VERSION >= 90000
-template <> struct fmt::formatter<crimson::os::seastore::lba_pin_list_t> : fmt::ostream_formatter {};
 template <> struct fmt::formatter<crimson::os::seastore::CachedExtent> : fmt::ostream_formatter {};
 template <> struct fmt::formatter<crimson::os::seastore::LogicalCachedExtent> : fmt::ostream_formatter {};
-template <> struct fmt::formatter<crimson::os::seastore::LBAMapping> : fmt::ostream_formatter {};
 #endif
index a050b2cdf47f7680a8d9ee47e8f8b488f5fc5ff3..9a34bf5615799f9b5b79d5454dc9a66925bf0f3f 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "crimson/os/seastore/cache.h"
 #include "crimson/os/seastore/seastore_types.h"
+#include "crimson/os/seastore/lba_mapping.h"
 
 namespace crimson::os::seastore {
 
index 007737ff450cc7a0b3f6ff22a0680c67d6fdf238..888d3c359ac0debd8b8a61f30eb13415930390ab 100644 (file)
@@ -94,6 +94,45 @@ void unlink_phy_tree_root_node<laddr_t>(RootBlockRef &root_block) {
 
 namespace crimson::os::seastore::lba_manager::btree {
 
+get_child_ret_t<LogicalCachedExtent>
+BtreeLBAMapping::get_logical_extent(Transaction &t)
+{
+  ceph_assert(is_parent_viewable());
+  assert(pos != std::numeric_limits<uint16_t>::max());
+  ceph_assert(t.get_trans_id() == ctx.trans.get_trans_id());
+  auto &p = static_cast<LBALeafNode&>(*parent);
+  auto k = this->is_indirect()
+    ? this->get_intermediate_base()
+    : get_key();
+  auto v = p.template get_child<LogicalCachedExtent>(ctx, pos, k);
+  if (!v.has_child()) {
+    this->child_pos = v.get_child_pos();
+  }
+  return v;
+}
+
+bool BtreeLBAMapping::is_stable() const
+{
+  assert(!this->parent_modified());
+  assert(pos != std::numeric_limits<uint16_t>::max());
+  auto &p = static_cast<LBALeafNode&>(*parent);
+  auto k = this->is_indirect()
+    ? this->get_intermediate_base()
+    : get_key();
+  return p.is_child_stable(ctx, pos, k);
+}
+
+bool BtreeLBAMapping::is_data_stable() const
+{
+  assert(!this->parent_modified());
+  assert(pos != std::numeric_limits<uint16_t>::max());
+  auto &p = static_cast<LBALeafNode&>(*parent);
+  auto k = this->is_indirect()
+    ? this->get_intermediate_base()
+    : get_key();
+  return p.is_child_data_stable(ctx, pos, k);
+}
+
 BtreeLBAManager::mkfs_ret
 BtreeLBAManager::mkfs(
   Transaction &t)
index ef10ff9623b503ce5de8c7ca110d4261dcf6e360..e0902053d0ecd36a2e40f7a12fb64466860b0fd5 100644 (file)
 #include "crimson/os/seastore/lba_manager/btree/lba_btree_node.h"
 #include "crimson/os/seastore/btree/btree_range_pin.h"
 
+namespace crimson::os::seastore {
+class LogicalCachedExtent;
+}
+
 namespace crimson::os::seastore::lba_manager::btree {
 
 struct LBALeafNode;
 
-class BtreeLBAMapping : public BtreeNodeMapping<laddr_t, paddr_t> {
+class BtreeLBAMapping : public LBAMapping {
 // To support cloning, there are two kinds of lba mappings:
 //     1. physical lba mapping: the pladdr in the value of which is the paddr of
 //        the corresponding extent;
@@ -61,14 +65,14 @@ class BtreeLBAMapping : public BtreeNodeMapping<laddr_t, paddr_t> {
 // their keys.
 public:
   BtreeLBAMapping(op_context_t<laddr_t> ctx)
-    : BtreeNodeMapping(ctx) {}
+    : LBAMapping(ctx) {}
   BtreeLBAMapping(
     op_context_t<laddr_t> c,
     LBALeafNodeRef parent,
     uint16_t pos,
     lba_map_val_t &val,
     lba_node_meta_t meta)
-    : BtreeNodeMapping(
+    : LBAMapping(
        c,
        parent,
        pos,
@@ -190,8 +194,12 @@ public:
     SUBDEBUGT(seastore_lba, "new pin {}", ctx.trans, static_cast<LBAMapping&>(*new_pin));
     return new_pin;
   }
+  bool is_stable() const final;
+  bool is_data_stable() const final;
+  get_child_ret_t<LogicalCachedExtent> get_logical_extent(Transaction &t);
+
 protected:
-  std::unique_ptr<BtreeNodeMapping<laddr_t, paddr_t>> _duplicate(
+  LBAMappingRef _duplicate(
     op_context_t<laddr_t> ctx) const final {
     auto pin = std::unique_ptr<BtreeLBAMapping>(new BtreeLBAMapping(ctx));
     pin->key = key;
diff --git a/src/crimson/os/seastore/lba_mapping.cc b/src/crimson/os/seastore/lba_mapping.cc
new file mode 100644 (file)
index 0000000..90fae09
--- /dev/null
@@ -0,0 +1,44 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "lba_mapping.h"
+
+namespace crimson::os::seastore {
+
+std::ostream &operator<<(std::ostream &out, const LBAMapping &rhs)
+{
+  out << "LBAMapping(" << rhs.get_key()
+      << "~0x" << std::hex << rhs.get_length() << std::dec
+      << "->" << rhs.get_val();
+  if (rhs.is_indirect()) {
+    out << ",indirect(" << rhs.get_intermediate_base()
+        << "~0x" << std::hex << rhs.get_intermediate_length()
+        << "@0x" << rhs.get_intermediate_offset() << std::dec
+        << ")";
+  }
+  out << ")";
+  return out;
+}
+
+std::ostream &operator<<(std::ostream &out, const lba_pin_list_t &rhs)
+{
+  bool first = true;
+  out << '[';
+  for (const auto &i: rhs) {
+    out << (first ? "" : ",") << *i;
+    first = false;
+  }
+  return out << ']';
+}
+
+LBAMappingRef LBAMapping::duplicate() const {
+  auto ret = _duplicate(ctx);
+  ret->range = range;
+  ret->value = value;
+  ret->parent = parent;
+  ret->len = len;
+  ret->pos = pos;
+  return ret;
+}
+
+} // namespace crimson::os::seastore
diff --git a/src/crimson/os/seastore/lba_mapping.h b/src/crimson/os/seastore/lba_mapping.h
new file mode 100644 (file)
index 0000000..338d4d5
--- /dev/null
@@ -0,0 +1,73 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include "crimson/os/seastore/cached_extent.h"
+#include "crimson/os/seastore/btree/btree_range_pin.h"
+
+namespace crimson::os::seastore {
+
+class LBAMapping;
+using LBAMappingRef = std::unique_ptr<LBAMapping>;
+
+class LogicalCachedExtent;
+
+class LBAMapping : public BtreeNodeMapping<laddr_t, paddr_t> {
+public:
+  LBAMapping(op_context_t<laddr_t> ctx)
+    : BtreeNodeMapping<laddr_t, paddr_t>(ctx) {}
+  template <typename... T>
+  LBAMapping(T&&... t)
+    : BtreeNodeMapping<laddr_t, paddr_t>(std::forward<T>(t)...)
+  {
+    if (!parent->is_pending()) {
+      this->child_pos = {parent, pos};
+    }
+  }
+
+  // An lba pin may be indirect, see comments in lba_manager/btree/btree_lba_manager.h
+  virtual bool is_indirect() const = 0;
+  virtual laddr_t get_intermediate_key() const = 0;
+  virtual laddr_t get_intermediate_base() const = 0;
+  virtual extent_len_t get_intermediate_length() const = 0;
+  // The start offset of the pin, must be 0 if the pin is not indirect
+  virtual extent_len_t get_intermediate_offset() const = 0;
+
+  virtual get_child_ret_t<LogicalCachedExtent>
+  get_logical_extent(Transaction &t) = 0;
+
+  void link_child(ChildableCachedExtent *c) {
+    ceph_assert(child_pos);
+    child_pos->link_child(c);
+  }
+  virtual LBAMappingRef refresh_with_pending_parent() = 0;
+
+  // For reserved mappings, the return values are
+  // undefined although it won't crash
+  virtual bool is_stable() const = 0;
+  virtual bool is_data_stable() const = 0;
+  virtual bool is_clone() const = 0;
+  bool is_zero_reserved() const {
+    return !get_val().is_real();
+  }
+
+  LBAMappingRef duplicate() const;
+
+  virtual ~LBAMapping() {}
+protected:
+  virtual LBAMappingRef _duplicate(op_context_t<laddr_t>) const = 0;
+  std::optional<child_pos_t> child_pos = std::nullopt;
+};
+
+std::ostream &operator<<(std::ostream &out, const LBAMapping &rhs);
+using lba_pin_list_t = std::list<LBAMappingRef>;
+
+std::ostream &operator<<(std::ostream &out, const lba_pin_list_t &rhs);
+
+} // namespace crimson::os::seastore
+
+#if FMT_VERSION >= 90000
+template <> struct fmt::formatter<crimson::os::seastore::LBAMapping> : fmt::ostream_formatter {};
+template <> struct fmt::formatter<crimson::os::seastore::lba_pin_list_t> : fmt::ostream_formatter {};
+#endif