}
}
+CachedExtentRef Cache::alloc_remapped_extent_by_type(
+ Transaction &t,
+ extent_types_t type,
+ laddr_t remap_laddr,
+ paddr_t remap_paddr,
+ extent_len_t remap_offset,
+ extent_len_t remap_length,
+ const std::optional<ceph::bufferptr> &original_bptr)
+{
+ ceph_assert(is_logical_type(type));
+ switch (type) {
+ case extent_types_t::ROOT_META:
+ return alloc_remapped_extent<RootMetaBlock>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::OMAP_INNER:
+ return alloc_remapped_extent<omap_manager::OMapInnerNode>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::OMAP_LEAF:
+ return alloc_remapped_extent<omap_manager::OMapLeafNode>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::ONODE_BLOCK_STAGED:
+ return alloc_remapped_extent<onode::SeastoreNodeExtent>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::COLL_BLOCK:
+ return alloc_remapped_extent<collection_manager::CollectionNode>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::OBJECT_DATA_BLOCK:
+ return alloc_remapped_extent<ObjectDataBlock>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ case extent_types_t::TEST_BLOCK:
+ return alloc_remapped_extent<TestBlock>(
+ t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+ default:
+ ceph_abort("invalid extent type");
+ return CachedExtentRef();
+ }
+}
+
CachedExtentRef Cache::alloc_new_non_data_extent_by_type(
Transaction &t, ///< [in, out] current transaction
extent_types_t type, ///< [in] type tag
return extent;
}
+ CachedExtentRef alloc_remapped_extent_by_type(
+ Transaction &t,
+ extent_types_t type,
+ laddr_t remap_laddr,
+ paddr_t remap_paddr,
+ extent_len_t remap_offset,
+ extent_len_t remap_length,
+ const std::optional<ceph::bufferptr> &original_bptr);
+
/**
* alloc_new_non_data_extent_by_type
*
ObjectDataHandler::write_iertr::future<std::optional<LBAMapping>>
ObjectDataHandler::prepare_data_reservation(
context_t ctx,
+ Onode &onode,
object_data_t &object_data,
extent_len_t size)
{
object_data.get_reserved_data_len());
return write_iertr::make_ready_future<std::optional<LBAMapping>>();
} else {
+ auto hint = onode.get_data_hint();
DEBUGT("reserving: {}~0x{:x}",
- ctx.t,
- ctx.onode.get_data_hint(),
- max_object_size);
+ ctx.t, hint, max_object_size);
return ctx.tm.reserve_region(
ctx.t,
- ctx.onode.get_data_hint(),
+ hint,
max_object_size,
extent_types_t::OBJECT_DATA_BLOCK
).si_then([max_object_size=max_object_size, &object_data](auto pin) {
ceph_assert(!object_data.is_null());
data_t data;
auto dest_mapping = co_await prepare_data_reservation(
- ctx, d_object_data, object_data.get_reserved_data_len());
+ ctx, *ctx.d_onode, d_object_data, object_data.get_reserved_data_len());
if (!dest_mapping) {
auto d_base = d_object_data.get_reserved_data_base();
auto laddr = (d_base + srcoff).get_aligned_laddr(
object_data.is_null());
return prepare_data_reservation(
ctx,
+ ctx.onode,
object_data,
p2roundup(offset + len, ctx.tm.get_block_size())
).si_then([this, ctx, offset, len, &object_data](auto mapping) {
{
return with_object_data(ctx, [this, ctx](auto &obj_data) {
return prepare_data_reservation(
- ctx, obj_data, max_object_size
+ ctx, ctx.onode, obj_data, max_object_size
).discard_result();
});
}
object_data.is_null());
return prepare_data_reservation(
ctx,
+ ctx.onode,
object_data,
p2roundup(offset + bl.length(), ctx.tm.get_block_size())
).si_then([this, ctx, offset, &object_data, &bl]
} else if (offset > object_data.get_reserved_data_len()) {
return prepare_data_reservation(
ctx,
+ ctx.onode,
object_data,
p2roundup(offset, ctx.tm.get_block_size())).discard_result();
} else {
auto old_base = object_data.get_reserved_data_base();
auto old_len = object_data.get_reserved_data_len();
auto mapping = co_await prepare_data_reservation(
- ctx, d_object_data, old_len);
+ ctx, *ctx.d_onode, d_object_data, old_len);
ceph_assert(mapping.has_value());
DEBUGT("new obj reserve_data_base: {}, len 0x{:x}",
ctx.t,
});
}
+ObjectDataHandler::rename_ret
+ObjectDataHandler::rename(context_t ctx)
+{
+ bool move_indirect = true;
+ if (!ctx.onode.get_hobj().is_temp()) {
+ // we are moving an object in a logical pool
+ // to another object, we should copy the content
+ // of indirect mappings to the new location
+ // instead of moving indirect mappings directly
+ move_indirect = false;
+ }
+ return with_objects_data(
+ ctx,
+ [ctx, this, move_indirect](object_data_t &src, object_data_t &dst)
+ -> rename_ret {
+ ceph_assert(!src.is_null());
+ ceph_assert(dst.is_null());
+ auto dst_mapping = co_await prepare_data_reservation(
+ ctx, *ctx.d_onode, dst, src.get_reserved_data_len());
+ assert(dst_mapping);
+ auto src_mapping = co_await ctx.tm.get_pin(
+ ctx.t, src.get_reserved_data_base()
+ ).handle_error_interruptible(
+ rename_iertr::pass_further{},
+ crimson::ct_error::assert_all("invalid error")
+ );
+ auto dst_prefix = dst_mapping->get_key();
+ dst_mapping = co_await ctx.tm.remove(
+ ctx.t, std::move(*dst_mapping)
+ ).handle_error_interruptible(
+ rename_iertr::pass_further{},
+ crimson::ct_error::assert_all("invalid error")
+ );
+ src_mapping = co_await src_mapping.refresh();
+ co_await ctx.tm.move_region(
+ ctx.t,
+ std::move(src_mapping),
+ std::move(*dst_mapping),
+ dst_prefix,
+ move_indirect);
+
+ auto old_md_start = src.get_reserved_data_base()
+ .with_metadata()
+ .with_offset_by_blocks(0);
+ auto md_mapping = co_await ctx.tm.lower_bound_pin(ctx.t, old_md_start);
+ if (md_mapping.is_end() ||
+ md_mapping.get_key().get_clone_prefix() !=
+ old_md_start.get_clone_prefix()) {
+ co_return;
+ }
+ auto new_prefix = dst
+ .get_reserved_data_base()
+ .get_clone_prefix()
+ .with_metadata();
+ auto md_dst_mapping = co_await ctx.tm.lower_bound_pin(ctx.t, new_prefix);
+ co_await ctx.tm.move_region(
+ ctx.t,
+ md_mapping,
+ md_dst_mapping,
+ new_prefix,
+ move_indirect);
+ });
+}
+
} // namespace crimson::os::seastore
#if FMT_VERSION >= 90000
extent_len_t len,
extent_len_t destoff);
+ using rename_iertr = base_iertr;
+ using rename_ret = rename_iertr::future<>;
+ rename_ret rename(context_t ctx);
private:
/// Updates region [_offset, _offset + bl.length) to bl
write_ret overwrite(
write_iertr::future<std::optional<LBAMapping>>
prepare_data_reservation(
context_t ctx,
+ Onode &onode,
object_data_t &object_data,
extent_len_t size);
std::ostream &OMapLeafNode::print_detail_l(std::ostream &out) const
{
- out << ", size=" << get_size()
- << ", depth=" << get_meta().depth
- << ", is_root=" << is_btree_root();
- if (get_size() > 0) {
- out << ", begin=" << get_begin()
- << ", end=" << get_end();
+ if (is_fully_loaded()) {
+ out << ", size=" << get_size()
+ << ", depth=" << get_meta().depth
+ << ", is_root=" << is_btree_root();
+ if (get_size() > 0) {
+ out << ", begin=" << get_begin()
+ << ", end=" << get_end();
+ }
}
if (this->child_node_t::is_parent_valid())
return out << ", parent=" << (void*)this->child_node_t::peek_parent_node().get();
OnodeRef &onode,
OnodeRef &d_onode)
{
+ auto &objHandler = ObjectDataHandler(max_object_size);
+ co_await objHanlder.rename(ObjectDataHandler::context_t{
+ *transaction_manager, *ctx.transaction, *onode, d_onode.get()
+ });
+ auto get_prefix = [](Onode &onode) {
+ auto p = onode.get_clone_prefix();
+ assert(p);
+ return *p;
+ };
+ auto src_prefix = get_prefix(*onode);
+ auto dst_prefix = get_prefix(*d_onode);
+
+ auto rename_omap_root = [&](omap_type_t type) {
+ auto root = onode->get_root(type).get(d_onode->get_metadata_hint());
+ if (root.is_null()) {
+ return root;
+ }
+ auto offset = root.addr.get_byte_distance<loffset_t>(src_prefix);
+ root.update(
+ (dst_prefix + offset).checked_to_laddr(),
+ root.depth, d_onode->get_metadata_hint(), type);
+ return root;
+ };
+
auto olayout = onode->get_layout();
uint32_t size = olayout.size;
- auto omap_root = rename_omap_root(omap_type_t::OMAP, *onode, *d_onode);
- auto xattr_root = rename_omap_root(omap_type_t::XATTR, *onode, *d_onode);
- auto object_data = olayout.object_data.get();
+ auto omap_root = rename_omap_root(omap_type_t::OMAP);
+ auto xattr_root = rename_omap_root(omap_type_t::XATTR);
+ auto log_root = rename_omap_root(omap_type_t::LOG);
auto oi_bl = ceph::bufferlist::static_from_mem(
&olayout.oi[0],
(uint32_t)olayout.oi_size);
d_onode->update_onode_size(*ctx.transaction, size);
d_onode->update_omap_root(*ctx.transaction, omap_root);
d_onode->update_xattr_root(*ctx.transaction, xattr_root);
- d_onode->update_object_data(*ctx.transaction, object_data);
+ d_onode->update_log_root(*ctx.transaction, log_root);
d_onode->update_object_info(*ctx.transaction, oi_bl);
d_onode->update_snapset(*ctx.transaction, ss_bl);
- return onode_manager->erase_onode(
+ co_await onode_manager->erase_onode(
*ctx.transaction, onode
).handle_error_interruptible(
crimson::ct_error::input_output_error::pass_further(),
crimson::ct_error::assert_all{
- "Invalid error in SeaStoreS::_rename"}
- );
+ "Invalid error in SeaStoreS::_rename"});
}
SeaStore::Shard::tm_ret
onode.get_metadata_hint(device->get_block_size()));
}
- omap_root_t rename_omap_root(
- omap_type_t type,
- Onode& onode,
- Onode& d_onode) const {
- return onode.get_root(type).get(
- d_onode.get_metadata_hint(device->get_block_size()));
- }
-
omaptree_get_value_ret omaptree_get_value(
Transaction& t,
omap_root_t&& root,
#include "include/denc.h"
#include "include/intarith.h"
+#include "crimson/common/coroutine.h"
#include "crimson/os/seastore/logging.h"
#include "crimson/os/seastore/transaction_manager.h"
#include "crimson/os/seastore/journal.h"
#include "crimson/os/seastore/journal/circular_bounded_journal.h"
#include "crimson/os/seastore/lba/lba_btree_node.h"
#include "crimson/os/seastore/random_block_manager/rbm_device.h"
+#include "crimson/os/seastore/object_data_handler.h"
+#include "crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.h"
/*
* TransactionManager logs
});
}
+base_iertr::future<LogicalChildNodeRef>
+TransactionManager::relocate_logical_extent(
+ Transaction &t, LBAMapping mapping)
+{
+ LOG_PREFIX(TransactionManager::relocate_logical_extent);
+ SUBDEBUGT(seastore_tm, "relocate {}", t, mapping);
+ assert(!mapping.is_indirect());
+ assert(!mapping.is_zero_reserved());
+ assert(mapping.is_viewable());
+ auto v = get_extent_if_linked(t, *(mapping.direct_cursor));
+ if (!v.has_child()) {
+ auto &child_pos = v.get_child_pos();
+ auto laddr = mapping.get_key();
+ std::ignore = cache->retire_absent_extent_addr_by_type(
+ t,
+ laddr,
+ mapping.get_val(),
+ mapping.get_length(),
+ mapping.get_extent_type(),
+ [laddr, &child_pos](auto &extent) {
+ auto lextent = extent.template cast<LogicalChildNode>();
+ assert(extent.is_logical());
+ assert(!lextent->has_laddr());
+ assert(!extent.has_been_invalidated());
+ child_pos.link_child(lextent.get());
+ lextent->set_laddr(laddr);
+ }
+ );
+ co_return cache->alloc_remapped_extent_by_type(
+ t, mapping.get_extent_type(), mapping.get_key(),
+ mapping.get_val(), 0, mapping.get_length(), std::nullopt
+ )->cast<LogicalChildNode>();
+ }
+
+ auto extent = co_await v.get_child_fut().si_then([](auto ext) {
+ return ext;
+ });
+
+ if (extent->is_stable()) {
+ cache->retire_extent(t, extent);
+ co_return cache->alloc_remapped_extent_by_type(
+ t, mapping.get_extent_type(), mapping.get_key(),
+ mapping.get_val(), 0, mapping.get_length(), std::nullopt
+ )->cast<LogicalChildNode>();
+ } else {
+ //TODO: relocating logical extents doesn't support
+ // mutation pending extents yet.
+ assert(extent->is_initial_pending() || extent->is_exist_clean());
+ co_return extent;
+ }
+}
+
TransactionManager::submit_transaction_iertr::future<>
TransactionManager::submit_transaction(
Transaction &t)
});
}
+TransactionManager::move_region_ret
+TransactionManager::move_region(
+ Transaction &t,
+ LBAMapping src,
+ LBAMapping dst,
+ laddr_t dst_prefix,
+ bool move_indirect)
+{
+ LOG_PREFIX(TransactionManager::move_region);
+ DEBUGT("src: {}, dst: {}, prefix: {}", t, src, dst, dst_prefix);
+ auto src_prefix = src.get_key().get_metadata_prefix();
+ assert(dst.get_key().get_metadata_prefix() != dst_prefix);
+ auto calc_dst_key = [&src, dst_prefix] {
+ auto key = src.get_key();
+ auto offset = key.get_byte_distance<loffset_t>(key.get_metadata_prefix());
+ return (dst_prefix + offset).checked_to_laddr();
+ };
+
+ assert(src.is_viewable());
+ assert(dst.is_viewable());
+ // move mapping from src to dst
+ while (src.get_key().get_metadata_prefix() == src_prefix) {
+ if (src.is_indirect()) {
+ if (move_indirect) {
+ auto ret = co_await lba_manager->move_indirect_mapping(
+ t,
+ src.get_effective_cursor_ref(),
+ calc_dst_key(),
+ dst.get_effective_cursor_ref());
+ src = co_await resolve_cursor_to_mapping(t, std::move(ret.src));
+ dst = co_await resolve_cursor_to_mapping(t, std::move(ret.dest));
+ } else {
+ using namespace crimson::os::seastore::omap_manager;
+ switch (src.get_extent_type()) {
+ case extent_types_t::OBJECT_DATA_BLOCK:
+ {
+ auto maybe_indirect_extent = co_await read_pin<ObjectDataBlock>(
+ t, src, src.get_intermediate_offset(), src.get_length());
+ auto extents = co_await alloc_data_extents<ObjectDataBlock>(
+ t,
+ laddr_hint_t::create_as_fixed(calc_dst_key()),
+ src.get_length(),
+ dst
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ auto off = 0;
+ auto bl = maybe_indirect_extent.get_range(
+ src.get_intermediate_offset(),
+ src.get_length());
+ auto iter = bl.begin();
+ for (auto &extent : extents) {
+ auto &ext = *extent;
+ assert(off + ext.get_length() <= src.get_length());
+ iter.copy(ext.get_length(), ext.get_bptr().c_str());
+ off += ext.get_length();
+ }
+ }
+ break;
+ case extent_types_t::OMAP_LEAF:
+ {
+ auto maybe_indirect_extent = co_await read_pin<OMapLeafNode>(
+ t, src, src.get_intermediate_offset(), src.get_length());
+ auto extent = co_await alloc_non_data_extent<OMapLeafNode>(
+ t,
+ laddr_hint_t::create_as_fixed(calc_dst_key()),
+ src.get_length()
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ extent->set_bptr(maybe_indirect_extent.extent->get_bptr());
+ }
+ break;
+ case extent_types_t::OMAP_INNER:
+ {
+ auto maybe_indirect_extent = co_await read_pin<OMapInnerNode>(
+ t, src, src.get_intermediate_offset(), src.get_length());
+ auto extent = co_await alloc_non_data_extent<OMapInnerNode>(
+ t,
+ laddr_hint_t::create_as_fixed(calc_dst_key()),
+ src.get_length()
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ extent->set_bptr(maybe_indirect_extent.extent->get_bptr());
+ }
+ break;
+ default:
+ ceph_abort("unexpected extent type");
+ break;
+ }
+ auto cursor = co_await lba_manager->update_mapping_refcount(
+ t, src.indirect_cursor, -1
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ src = co_await resolve_cursor_to_mapping(t, std::move(cursor));
+ dst = co_await dst.refresh();
+ }
+ } else if (!src.is_zero_reserved()) {
+ auto extent = co_await relocate_logical_extent(t, src);
+ auto laddr = calc_dst_key();
+ extent->set_laddr(laddr);
+ auto ret = co_await lba_manager->move_direct_mapping(
+ t, src.get_effective_cursor_ref(),
+ laddr, dst.get_effective_cursor_ref(), *extent);
+ src = co_await resolve_cursor_to_mapping(t, std::move(ret.src));
+ dst = co_await resolve_cursor_to_mapping(t, std::move(ret.dest));
+ } else { // src is direct mapping
+ auto len = src.get_length();
+ auto dst_key = calc_dst_key();
+ auto type = src.get_extent_type();
+ dst = co_await dst.refresh();
+ auto insert = co_await reserve_region(
+ t, std::move(dst), dst_key, len, type
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ src = co_await src.refresh();
+ auto cursor = co_await lba_manager->update_mapping_refcount(
+ t, src.get_effective_cursor_ref(), -1
+ ).handle_error_interruptible(
+ move_region_iertr::pass_further(),
+ crimson::ct_error::assert_all("invalid error"));
+ src = co_await resolve_cursor_to_mapping(t, std::move(cursor));
+ dst = co_await insert.next();
+ }
+ assert(src.is_viewable());
+ assert(dst.is_viewable());
+ }
+ co_return;
+}
+
TransactionManager::get_extents_if_live_ret
TransactionManager::get_extents_if_live(
Transaction &t,
return cache->reset_transaction_preserve_handle(t);
}
+ /**
+ * relocate_logical_extent
+ *
+ * Make a new logical extent to update its laddr. The caller is
+ * responsible to update the corresponding lba mapping.
+ */
+ base_iertr::future<LogicalChildNodeRef> relocate_logical_extent(
+ Transaction &t,
+ LBAMapping mapping);
+
/**
* get_pin
*
co_return clone_range_ret_t{shared_direct, std::move(pos)};
}
+ using move_region_iertr = base_iertr;
+ using move_region_ret = move_region_iertr::future<>;
+ move_region_ret move_region(
+ Transaction &t,
+ LBAMapping src,
+ LBAMapping dst,
+ laddr_t dst_prefix,
+ bool move_indirect);
+
/* alloc_extents
*
* allocates more than one new blocks of type T.