From 25be5fd3949910c6cf2dd75273e4d990ac221b61 Mon Sep 17 00:00:00 2001 From: Xuehan Xu Date: Mon, 21 Jul 2025 17:28:59 +0800 Subject: [PATCH] crimson/os/seastore/transaction_manager: link RetiredExtentPlaceholder onto lba leaf nodes Signed-off-by: Xuehan Xu --- src/crimson/os/seastore/cache.cc | 6 +- src/crimson/os/seastore/cache.h | 4 +- src/crimson/os/seastore/cached_extent.h | 48 ---- src/crimson/os/seastore/logical_child_node.h | 77 ++++++ .../os/seastore/retired_extent_placeholder.h | 0 .../os/seastore/transaction_manager.cc | 256 +++++++++++------- src/crimson/os/seastore/transaction_manager.h | 19 +- 7 files changed, 261 insertions(+), 149 deletions(-) create mode 100644 src/crimson/os/seastore/retired_extent_placeholder.h diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index 33660d34082..640be677130 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -93,8 +93,8 @@ Cache::retire_extent_ret Cache::retire_extent_addr( return retire_extent_iertr::now(); } -void Cache::retire_absent_extent_addr( - Transaction &t, paddr_t paddr, extent_len_t length) +CachedExtentRef Cache::retire_absent_extent_addr( + Transaction &t, laddr_t laddr, paddr_t paddr, extent_len_t length) { assert(paddr.is_absolute()); @@ -112,10 +112,12 @@ void Cache::retire_absent_extent_addr( ext->init( CachedExtent::extent_state_t::CLEAN, paddr, PLACEMENT_HINT_NULL, NULL_GENERATION, TRANS_ID_NULL); + static_cast(*ext).set_laddr(laddr); DEBUGT("retire {}~0x{:x} as placeholder, add extent -- {}", t, paddr, length, *ext); add_extent(ext); t.add_absent_to_retired_set(ext); + return ext; } void Cache::dump_contents() diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index 332a5ebecba..97cc7b6568a 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -163,8 +163,8 @@ public: retire_extent_ret retire_extent_addr( Transaction &t, paddr_t addr, extent_len_t length); - void retire_absent_extent_addr( - Transaction &t, paddr_t addr, extent_len_t length); + CachedExtentRef retire_absent_extent_addr( + Transaction &t, laddr_t laddr, paddr_t addr, extent_len_t length); /** * get_root diff --git a/src/crimson/os/seastore/cached_extent.h b/src/crimson/os/seastore/cached_extent.h index 2ac55b3405c..5cf591c35b3 100644 --- a/src/crimson/os/seastore/cached_extent.h +++ b/src/crimson/os/seastore/cached_extent.h @@ -1366,54 +1366,6 @@ private: uint64_t bytes = 0; }; -/** - * RetiredExtentPlaceholder - * - * Cache::retire_extent_addr(Transaction&, paddr_t, extent_len_t) can retire an - * extent not currently in cache. In that case, in order to detect transaction - * invalidation, we need to add a placeholder to the cache to create the - * mapping back to the transaction. And whenever there is a transaction tries - * to read the placeholder extent out, Cache is responsible to replace the - * placeholder by the real one. Anyway, No placeholder extents should escape - * the Cache interface boundary. - */ -class RetiredExtentPlaceholder : public CachedExtent { - -public: - RetiredExtentPlaceholder(extent_len_t length) - : CachedExtent(CachedExtent::retired_placeholder_construct_t{}, length) {} - - CachedExtentRef duplicate_for_write(Transaction&) final { - ceph_abort_msg("Should never happen for a placeholder"); - return CachedExtentRef(); - } - - ceph::bufferlist get_delta() final { - ceph_abort_msg("Should never happen for a placeholder"); - return ceph::bufferlist(); - } - - static constexpr extent_types_t TYPE = extent_types_t::RETIRED_PLACEHOLDER; - extent_types_t get_type() const final { - return TYPE; - } - - void apply_delta_and_adjust_crc( - paddr_t base, const ceph::bufferlist &bl) final { - ceph_abort_msg("Should never happen for a placeholder"); - } - - void on_rewrite(Transaction &, CachedExtent&, extent_len_t) final {} - - std::ostream &print_detail(std::ostream &out) const final { - return out << ", RetiredExtentPlaceholder"; - } - - void on_delta_write(paddr_t record_block_offset) final { - ceph_abort_msg("Should never happen for a placeholder"); - } -}; - class LBAMapping; /** * LogicalCachedExtent diff --git a/src/crimson/os/seastore/logical_child_node.h b/src/crimson/os/seastore/logical_child_node.h index 3b2786f1eb2..71e6ee0ed13 100644 --- a/src/crimson/os/seastore/logical_child_node.h +++ b/src/crimson/os/seastore/logical_child_node.h @@ -10,6 +10,83 @@ namespace crimson::os::seastore { +/** + * RetiredExtentPlaceholder + * + * Cache::retire_extent_addr(Transaction&, paddr_t, extent_len_t) can retire an + * extent not currently in cache. In that case, in order to detect transaction + * invalidation, we need to add a placeholder to the cache to create the + * mapping back to the transaction. And whenever there is a transaction tries + * to read the placeholder extent out, Cache is responsible to replace the + * placeholder by the real one. Anyway, No placeholder extents should escape + * the Cache interface boundary. + */ +class RetiredExtentPlaceholder + : public CachedExtent, + public ChildNode { + +public: + RetiredExtentPlaceholder(extent_len_t length) + : CachedExtent(CachedExtent::retired_placeholder_construct_t{}, length) {} + + ~RetiredExtentPlaceholder() { + if (this->is_stable()) { + lba_child_node_t::destroy(); + } + } + + CachedExtentRef duplicate_for_write(Transaction&) final { + ceph_abort_msg("Should never happen for a placeholder"); + return CachedExtentRef(); + } + + ceph::bufferlist get_delta() final { + ceph_abort_msg("Should never happen for a placeholder"); + return ceph::bufferlist(); + } + + static constexpr extent_types_t TYPE = extent_types_t::RETIRED_PLACEHOLDER; + extent_types_t get_type() const final { + return TYPE; + } + + void apply_delta_and_adjust_crc( + paddr_t base, const ceph::bufferlist &bl) final { + ceph_abort_msg("Should never happen for a placeholder"); + } + + void on_rewrite(Transaction &, CachedExtent&, extent_len_t) final {} + + std::ostream &print_detail(std::ostream &out) const final { + return out << ", RetiredExtentPlaceholder"; + } + + void on_delta_write(paddr_t record_block_offset) final { + ceph_abort_msg("Should never happen for a placeholder"); + } + + void set_laddr(laddr_t laddr) { + this->laddr = laddr; + } + + bool is_btree_root() const { + return false; + } + + laddr_t get_begin() const { + assert(laddr != L_ADDR_NULL); + return laddr; + } + + laddr_t get_end() const { + assert(laddr != L_ADDR_NULL); + return (laddr + get_length()).checked_to_laddr(); + } + +private: + laddr_t laddr = L_ADDR_NULL; +}; + class LogicalChildNode : public LogicalCachedExtent, public ChildNodeget_mapping(t, offset - ).si_then([&t, this, FNAME, offset](auto mapping) { - return seastar::do_with( - std::move(mapping), - [&t, this, FNAME, offset](auto &mapping) { - auto fut = base_iertr::make_ready_future(); - if (mapping.is_indirect()) { - fut = lba_manager->complete_indirect_lba_mapping(t, std::move(mapping) - ).si_then([&mapping, &t, this](auto m) { - mapping = std::move(m); - auto ret = get_extent_if_linked(t, mapping); - if (ret.index() == 1) { - return std::move(std::get<1>(ret)); - } - return get_child_iertr::make_ready_future(); + ).si_then([&t, this](auto mapping) { + return _remove(t, std::move(mapping)); + }).si_then([](auto result) { + return result.result.refcount; + }); +} + +TransactionManager::ref_iertr::future +TransactionManager::remove( + Transaction &t, + LBAMapping mapping) +{ + return mapping.refresh().si_then([&t, this](auto mapping) { + return _remove(t, std::move(mapping)); + }).si_then([](auto res) { + return std::move(res.result.mapping); + }); +} + +TransactionManager::ref_iertr::future< + TransactionManager::_remove_mapping_result_t> +TransactionManager::_remove_indirect_mapping( + Transaction &t, + LBAMapping mapping) +{ + LOG_PREFIX(TransactionManager::_remove_indirect_mapping); + return seastar::do_with( + std::move(mapping), + [&t, this, FNAME](auto &mapping) { + return lba_manager->complete_indirect_lba_mapping(t, std::move(mapping) + ).si_then([FNAME, &mapping, &t, this](auto m) { + mapping = std::move(m); + auto ret = get_extent_if_linked(t, mapping); + if (ret.index() == 1) { + return std::move(std::get<1>(ret) + ).si_then([&t, mapping, this, FNAME](auto extent) { + return lba_manager->remove_mapping(t, std::move(mapping) + ).si_then([this, FNAME, &t, extent](auto result) { + ceph_assert(result.direct_result); + auto &primary_result = result.result; + ceph_assert(primary_result.refcount == 0); + auto &direct_result = *result.direct_result; + ceph_assert(direct_result.addr.is_paddr()); + ceph_assert(!direct_result.addr.get_paddr().is_zero()); + ceph_assert(extent); + if (direct_result.refcount == 0) { + cache->retire_extent(t, extent); + } + DEBUGT("removed indirect mapping {}~0x{:x} refcount={} offset={} " + "with direct mapping {}~0x{:x} refcount={} offset={}", + t, primary_result.addr, + primary_result.length, + primary_result.refcount, + primary_result.key, + direct_result.addr, + direct_result.length, + direct_result.refcount, + direct_result.key); + return ref_iertr::make_ready_future< + _remove_mapping_result_t>(std::move(result)); + }); }); - } else if (mapping.get_val().is_real_location()) { - auto ret = get_extent_if_linked(t, mapping); - if (ret.index() == 1) { - fut = std::move(std::get<1>(ret)); - } - } - return fut.si_then([&t, &mapping, this, FNAME, offset](auto extent) { + } else { + auto unlinked_child = std::move(std::get<0>(ret)); return lba_manager->remove_mapping(t, std::move(mapping) - ).si_then([this, FNAME, offset, &t, extent](auto result) -> ref_ret { - auto fut = ref_iertr::now(); + ).si_then([child_pos=unlinked_child.child_pos, &t, + FNAME, this](auto result) mutable { + ceph_assert(result.direct_result); auto &primary_result = result.result; - assert(primary_result.refcount == 0); - if (primary_result.need_to_remove_extent()) { - ceph_assert(!result.direct_result); - assert(extent->get_laddr() == primary_result.direct_key); - if (extent) { - cache->retire_extent(t, extent); - } else { - fut = cache->retire_extent_addr( - t, primary_result.addr.get_paddr(), primary_result.length); - } - } else if (auto &direct_result = result.direct_result; - direct_result.has_value() && - direct_result->need_to_remove_extent()) { - assert(extent->get_laddr() == direct_result->direct_key); - if (extent) { - cache->retire_extent(t, extent); - } else { - fut = cache->retire_extent_addr( - t, direct_result->addr.get_paddr(), direct_result->length); - } + ceph_assert(primary_result.refcount == 0); + auto &direct_result = *result.direct_result; + ceph_assert(direct_result.addr.is_paddr()); + ceph_assert(!direct_result.addr.get_paddr().is_zero()); + if (direct_result.refcount == 0) { + auto retired_placeholder = cache->retire_absent_extent_addr( + t, direct_result.key, + direct_result.addr.get_paddr(), + direct_result.length + )->template cast(); + child_pos.link_child(retired_placeholder.get()); } - return fut.si_then([result=std::move(result), offset, &t, FNAME] { - DEBUGT("removed {}~0x{:x} refcount={} -- offset={}", - t, result.result.addr, result.result.length, - result.result.refcount, offset); - return result.result.refcount; - }); + DEBUGT("removed indirect mapping {}~0x{:x} refcount={} offset={} " + "with direct mapping {}~0x{:x} refcount={} offset={}", + t, primary_result.addr, + primary_result.length, + primary_result.refcount, + primary_result.key, + direct_result.addr, + direct_result.length, + direct_result.refcount, + direct_result.key); + return ref_iertr::make_ready_future< + _remove_mapping_result_t>(std::move(result)); }); - }); + } }); }); } -TransactionManager::ref_iertr::future TransactionManager::remove( +TransactionManager::ref_iertr::future< + TransactionManager::_remove_mapping_result_t> +TransactionManager::_remove_direct_mapping( Transaction &t, LBAMapping mapping) { - LOG_PREFIX(TransactionManager::remove); - return mapping.refresh().si_then([&t, this](auto mapping) { - if (mapping.is_indirect()) { - return lba_manager->complete_indirect_lba_mapping(t, std::move(mapping)); - } - return LBAManager::complete_lba_mapping_iertr::make_ready_future< - LBAMapping>(std::move(mapping)); - }).si_then([&t, this, FNAME](auto mapping) { - auto fut = base_iertr::make_ready_future(); - if (!mapping.is_indirect() && mapping.get_val().is_real_location()) { - auto ret = get_extent_if_linked(t, mapping); - if (ret.index() == 1) { - fut = std::move(std::get<1>(ret)); - } - } - return fut.si_then([mapping=std::move(mapping), - FNAME, this, &t](auto extent) mutable { - auto offset = mapping.get_key(); + LOG_PREFIX(TransactionManager::_remove_direct_mapping); + auto ret = get_extent_if_linked(t, mapping); + if (ret.index() == 1) { + return std::move(std::get<1>(ret) + ).si_then([&t, mapping, this, FNAME](auto extent) { return lba_manager->remove_mapping(t, std::move(mapping) - ).si_then([FNAME, this, extent, &t, offset](auto result) { - auto fut = ref_iertr::now(); + ).si_then([this, FNAME, &t, extent](auto result) { auto &primary_result = result.result; - assert(primary_result.refcount == 0); - if (primary_result.need_to_remove_extent()) { - ceph_assert(!result.direct_result); - if (extent) { - cache->retire_extent(t, extent); - } else { - fut = cache->retire_extent_addr( - t, primary_result.addr.get_paddr(), primary_result.length); - } - } else if (auto &direct_result = result.direct_result; - direct_result.has_value() && - direct_result->need_to_remove_extent()) { - ceph_assert(!extent); - fut = cache->retire_extent_addr( - t, direct_result->addr.get_paddr(), direct_result->length); - } else { - ceph_assert(!extent); - } - return fut.si_then([result=std::move(result), &t, FNAME, offset]() mutable { - DEBUGT("removed {}~0x{:x} refcount={} -- offset={}", - t, result.result.addr, result.result.length, - result.result.refcount, offset); - return std::move(result.result.mapping); - }); + ceph_assert(primary_result.refcount == 0); + ceph_assert(primary_result.addr.is_paddr()); + ceph_assert(!primary_result.addr.get_paddr().is_zero()); + ceph_assert(extent); + cache->retire_extent(t, extent); + DEBUGT("removed {}~0x{:x} refcount={} -- offset={}", + t, primary_result.addr, primary_result.length, + primary_result.refcount, primary_result.key); + return ref_iertr::make_ready_future< + _remove_mapping_result_t>(std::move(result)); }); }); - }); + } else { + auto unlinked_child = std::move(std::get<0>(ret)); + return lba_manager->remove_mapping(t, std::move(mapping) + ).si_then([child_pos=unlinked_child.child_pos, &t, + FNAME, this](auto result) mutable { + auto &primary_result = result.result; + ceph_assert(primary_result.refcount == 0); + ceph_assert(primary_result.addr.is_paddr()); + ceph_assert(!primary_result.addr.get_paddr().is_zero()); + auto retired_placeholder = cache->retire_absent_extent_addr( + t, primary_result.key, + primary_result.addr.get_paddr(), + primary_result.length + )->template cast(); + child_pos.link_child(retired_placeholder.get()); + DEBUGT("removed {}~0x{:x} refcount={} -- offset={}", + t, primary_result.addr, primary_result.length, + primary_result.refcount, primary_result.key); + return ref_iertr::make_ready_future< + _remove_mapping_result_t>(std::move(result)); + }); + } +} + +TransactionManager::ref_iertr::future< + TransactionManager::_remove_mapping_result_t> +TransactionManager::_remove( + Transaction &t, + LBAMapping mapping) +{ + LOG_PREFIX(TransactionManager::_remove); + if (mapping.is_indirect()) { + return _remove_indirect_mapping(t, std::move(mapping)); + } else if (mapping.get_val().is_real_location()) { + return _remove_direct_mapping(t, std::move(mapping)); + } else { + return lba_manager->remove_mapping(t, std::move(mapping) + ).si_then([&t, FNAME](auto result) { + auto &primary_result = result.result; + ceph_assert(primary_result.refcount == 0); + ceph_assert(primary_result.addr.is_paddr()); + ceph_assert(primary_result.addr.get_paddr().is_zero()); + DEBUGT("removed {}~0x{:x} refcount={} -- offset={}", + t, primary_result.addr, + primary_result.length, + primary_result.refcount, + primary_result.key); + return ref_iertr::make_ready_future< + _remove_mapping_result_t>(std::move(result)); + }); + } } TransactionManager::refs_ret TransactionManager::remove( diff --git a/src/crimson/os/seastore/transaction_manager.h b/src/crimson/os/seastore/transaction_manager.h index 32500343c80..98f0d018818 100644 --- a/src/crimson/os/seastore/transaction_manager.h +++ b/src/crimson/os/seastore/transaction_manager.h @@ -1310,7 +1310,11 @@ private: }); } else { // absent - cache->retire_absent_extent_addr(t, original_paddr, original_len); + auto unlinked_child = std::move(std::get<0>(ret)); + auto retired_placeholder = cache->retire_absent_extent_addr( + t, pin.get_key(), original_paddr, original_len + )->template cast(); + unlinked_child.child_pos.link_child(retired_placeholder.get()); return base_iertr::make_ready_future>(); } } @@ -1375,6 +1379,19 @@ private: }); } + using _remove_mapping_result_t = LBAManager::ref_update_result_t; + ref_iertr::future<_remove_mapping_result_t> _remove( + Transaction &t, + LBAMapping mapping); + ref_iertr::future<_remove_mapping_result_t> + _remove_indirect_mapping( + Transaction &t, + LBAMapping mapping); + ref_iertr::future<_remove_mapping_result_t> + _remove_direct_mapping( + Transaction &t, + LBAMapping mapping); + rewrite_extent_ret rewrite_logical_extent( Transaction& t, LogicalChildNodeRef extent); -- 2.39.5