From c35866f3716715b2e8c35ac76c8c14582db1f7f2 Mon Sep 17 00:00:00 2001 From: Xuehan Xu Date: Fri, 19 Jan 2024 13:26:03 +0800 Subject: [PATCH] crimson/os/seastore/transaction_manager: allow allocating multiple extents when rewriting data extents Signed-off-by: Xuehan Xu --- src/crimson/os/seastore/lba_manager.cc | 2 + src/crimson/os/seastore/lba_manager.h | 2 + .../lba_manager/btree/btree_lba_manager.cc | 6 +- .../lba_manager/btree/btree_lba_manager.h | 2 + .../os/seastore/transaction_manager.cc | 119 ++++++++++++++---- 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/crimson/os/seastore/lba_manager.cc b/src/crimson/os/seastore/lba_manager.cc index d113bbd1e95..c3473bc483e 100644 --- a/src/crimson/os/seastore/lba_manager.cc +++ b/src/crimson/os/seastore/lba_manager.cc @@ -16,7 +16,9 @@ LBAManager::update_mappings( return update_mapping( t, extent->get_laddr(), + extent->get_length(), extent->get_prior_paddr_and_reset(), + extent->get_length(), extent->get_paddr(), nullptr // all the extents should have already been // added to the fixed_kv_btree diff --git a/src/crimson/os/seastore/lba_manager.h b/src/crimson/os/seastore/lba_manager.h index d4d1826bcf9..0c02e1bd61b 100644 --- a/src/crimson/os/seastore/lba_manager.h +++ b/src/crimson/os/seastore/lba_manager.h @@ -191,7 +191,9 @@ public: virtual update_mapping_ret update_mapping( Transaction& t, laddr_t laddr, + extent_len_t prev_len, paddr_t prev_addr, + extent_len_t len, paddr_t paddr, LogicalCachedExtent *nextent) = 0; diff --git a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc index 1b7f927ec0f..b9fa0685a80 100644 --- a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc +++ b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc @@ -530,7 +530,9 @@ BtreeLBAManager::update_mapping_ret BtreeLBAManager::update_mapping( Transaction& t, laddr_t laddr, + extent_len_t prev_len, paddr_t prev_addr, + extent_len_t len, paddr_t addr, LogicalCachedExtent *nextent) { @@ -539,13 +541,15 @@ BtreeLBAManager::update_mapping( return _update_mapping( t, laddr, - [prev_addr, addr]( + [prev_addr, addr, prev_len, len]( const lba_map_val_t &in) { assert(!addr.is_null()); lba_map_val_t ret = in; ceph_assert(in.pladdr.is_paddr()); ceph_assert(in.pladdr.get_paddr() == prev_addr); + ceph_assert(in.len == prev_len); ret.pladdr = addr; + ret.len = len; return ret; }, nextent diff --git a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.h b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.h index 1c907f76d31..626b9e02c0c 100644 --- a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.h +++ b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.h @@ -333,7 +333,9 @@ public: update_mapping_ret update_mapping( Transaction& t, laddr_t laddr, + extent_len_t prev_len, paddr_t prev_addr, + extent_len_t len, paddr_t paddr, LogicalCachedExtent*) final; diff --git a/src/crimson/os/seastore/transaction_manager.cc b/src/crimson/os/seastore/transaction_manager.cc index e4522441205..348c43e3c82 100644 --- a/src/crimson/os/seastore/transaction_manager.cc +++ b/src/crimson/os/seastore/transaction_manager.cc @@ -439,32 +439,99 @@ TransactionManager::rewrite_logical_extent( auto lextent = extent->cast(); cache->retire_extent(t, extent); - auto nlextent = cache->alloc_new_extent_by_type( - t, - lextent->get_type(), - lextent->get_length(), - lextent->get_user_hint(), - // get target rewrite generation - lextent->get_rewrite_generation())->cast(); - lextent->get_bptr().copy_out( - 0, - lextent->get_length(), - nlextent->get_bptr().c_str()); - nlextent->set_laddr(lextent->get_laddr()); - nlextent->set_modify_time(lextent->get_modify_time()); - - DEBUGT("rewriting logical extent -- {} to {}", t, *lextent, *nlextent); - - /* This update_mapping is, strictly speaking, unnecessary for delayed_alloc - * extents since we're going to do it again once we either do the ool write - * or allocate a relative inline addr. TODO: refactor AsyncCleaner to - * avoid this complication. */ - return lba_manager->update_mapping( - t, - lextent->get_laddr(), - lextent->get_paddr(), - nlextent->get_paddr(), - nlextent.get()); + if (get_extent_category(lextent->get_type()) == data_category_t::METADATA) { + auto nlextent = cache->alloc_new_extent_by_type( + t, + lextent->get_type(), + lextent->get_length(), + lextent->get_user_hint(), + // get target rewrite generation + lextent->get_rewrite_generation())->cast(); + lextent->get_bptr().copy_out( + 0, + lextent->get_length(), + nlextent->get_bptr().c_str()); + nlextent->set_laddr(lextent->get_laddr()); + nlextent->set_modify_time(lextent->get_modify_time()); + + DEBUGT("rewriting logical extent -- {} to {}", t, *lextent, *nlextent); + + /* This update_mapping is, strictly speaking, unnecessary for delayed_alloc + * extents since we're going to do it again once we either do the ool write + * or allocate a relative inline addr. TODO: refactor AsyncCleaner to + * avoid this complication. */ + return lba_manager->update_mapping( + t, + lextent->get_laddr(), + lextent->get_length(), + lextent->get_paddr(), + nlextent->get_length(), + nlextent->get_paddr(), + nlextent.get()); + } else { + assert(get_extent_category(lextent->get_type()) == data_category_t::DATA); + auto extents = cache->alloc_new_data_extents_by_type( + t, + lextent->get_type(), + lextent->get_length(), + lextent->get_user_hint(), + // get target rewrite generation + lextent->get_rewrite_generation()); + return seastar::do_with( + std::move(extents), + 0, + lextent->get_length(), + [this, lextent, &t](auto &extents, auto &off, auto &left) { + return trans_intr::do_for_each( + extents, + [lextent, this, &t, &off, &left](auto &nextent) { + LOG_PREFIX(TransactionManager::rewrite_logical_extent); + bool first_extent = (off == 0); + ceph_assert(left >= nextent->get_length()); + auto nlextent = nextent->template cast(); + lextent->get_bptr().copy_out( + 0, + nlextent->get_length(), + nlextent->get_bptr().c_str()); + nlextent->set_laddr(lextent->get_laddr() + off); + nlextent->set_modify_time(lextent->get_modify_time()); + DEBUGT("rewriting logical extent -- {} to {}", t, *lextent, *nlextent); + + /* This update_mapping is, strictly speaking, unnecessary for delayed_alloc + * extents since we're going to do it again once we either do the ool write + * or allocate a relative inline addr. TODO: refactor AsyncCleaner to + * avoid this complication. */ + auto fut = base_iertr::now(); + if (first_extent) { + fut = lba_manager->update_mapping( + t, + lextent->get_laddr() + off, + lextent->get_length(), + lextent->get_paddr(), + nlextent->get_length(), + nlextent->get_paddr(), + nlextent.get()); + } else { + fut = lba_manager->alloc_extent( + t, + lextent->get_laddr() + off, + nlextent->get_length(), + nlextent->get_paddr(), + *nlextent + ).si_then([lextent, nlextent, off](auto mapping) { + ceph_assert(mapping->get_key() == lextent->get_laddr() + off); + ceph_assert(mapping->get_val() == nlextent->get_paddr()); + return seastar::now(); + }); + } + return fut.si_then([&off, &left, nlextent] { + off += nlextent->get_length(); + left -= nlextent->get_length(); + return seastar::now(); + }); + }); + }); + } } TransactionManager::rewrite_extent_ret TransactionManager::rewrite_extent( -- 2.39.5