Transaction &t,
laddr_t remap_laddr,
paddr_t remap_paddr,
+ extent_len_t remap_offset,
extent_len_t remap_length,
- laddr_t original_laddr,
- std::optional<ceph::bufferptr> &original_bptr) {
+ const std::optional<ceph::bufferptr> &original_bptr) {
LOG_PREFIX(Cache::alloc_remapped_extent);
- assert(remap_laddr >= original_laddr);
TCachedExtentRef<T> ext;
if (original_bptr.has_value()) {
// shallow copy the buffer from original extent
- auto remap_offset = remap_laddr.get_byte_distance<
- extent_len_t>(original_laddr);
-
auto nbp = ceph::bufferptr(buffer::create_page_aligned(remap_length));
original_bptr->copy_out(remap_offset, remap_length, nbp.c_str());
-
// ExtentPlacementManager::alloc_new_extent will make a new
// (relative/temp) paddr, so make extent directly
ext = CachedExtent::make_cached_extent_ref<T>(std::move(nbp));
co_return ret;
}
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_copy_mapping(
+ op_context_t c,
+ LBABtree &btree,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode *extent)
+{
+ LOG_PREFIX(BtreeLBAManager::_copy_mapping);
+ assert(src && dest);
+ assert(dest->is_viewable());
+ assert(src->is_viewable());
+ assert(!src->is_end());
+ assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+ assert(!src->is_indirect() == (bool)extent);
+ DEBUGT("src={} dest={}", c.trans, *src, *dest);
+ move_mapping_ret_t ret{std::move(src), std::move(dest)};
+ auto &cursor = *ret.dest;
+ auto iter = btree.make_partial_iter(c, cursor);
+ if (!iter.is_end()) {
+ assert(iter.get_key() >= dest_laddr + ret.src->get_length());
+ }
+ // insert the src mapping to dest
+ // attach extent to the new mapping if it exists
+ pladdr_t addr;
+ if (ret.src->is_indirect()) {
+ addr = ret.src->get_intermediate_key().get_local_clone_id();
+ } else {
+ addr = ret.src->get_paddr();
+ }
+ auto [niter, inserted] = co_await btree.insert(
+ c,
+ std::move(iter),
+ dest_laddr,
+ lba_map_val_t{
+ ret.src->get_length(),
+ std::move(addr),
+ EXTENT_DEFAULT_REF_COUNT,
+ ret.src->is_indirect() ? 0 : ret.src->get_checksum(),
+ ret.src->get_extent_type()},
+ extent ? extent : get_reserved_ptr<LBALeafNode, laddr_t>());
+ ceph_assert(inserted);
+ ret.dest = niter.get_cursor(c);
+ co_await ret.src->refresh();
+ co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_move_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode *extent) {
+ LOG_PREFIX(BtreeLBAManager::_move_mapping);
+ assert(src && dest);
+ assert(dest->is_viewable());
+ assert(src->is_viewable());
+ assert(!src->is_end());
+ assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+ DEBUGT("src={} dest={}", t, *src, *dest);
+ auto c = get_context(t);
+ auto btree = co_await get_btree<LBABtree>(cache, c);
+ auto ret = co_await _copy_mapping(
+ c, btree, std::move(src), dest_laddr, std::move(dest), extent);
+
+ ret.src = co_await update_mapping_refcount(
+ c.trans, ret.src, -1
+ ).handle_error_interruptible(
+ move_mapping_iertr::pass_further{},
+ crimson::ct_error::assert_all{"unexpected error"});
+
+ co_await ret.dest->refresh();
+ auto iter = btree.make_partial_iter(c, *ret.dest);
+ iter = co_await iter.next(c);
+ ret.dest = iter.get_cursor(c);
+
+ co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::move_and_clone_direct_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode &extent)
+{
+ LOG_PREFIX(BtreeLBAManager::move_and_clone_direct_mapping);
+ assert(src && dest);
+ assert(dest->is_viewable());
+ assert(src->is_viewable());
+ assert(!src->is_indirect());
+ assert(!src->is_end());
+ assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+ DEBUGT("src={} dest={}", t, *src, *dest);
+ auto c = get_context(t);
+ auto btree = co_await get_btree<LBABtree>(cache, c);
+ auto ret = co_await _copy_mapping(
+ c, btree, std::move(src), dest_laddr, std::move(dest), &extent);
+
+ // turn the src mapping into an indirect one pointing to
+ // the previously inserted mapping
+ auto cursor = co_await _update_mapping(
+ c.trans,
+ *ret.src,
+ [&ret](const auto &in) {
+ lba_map_val_t val = in;
+ val.pladdr = ret.dest->get_key().get_local_clone_id();
+ val.checksum = 0;
+ return val;
+ },
+ nullptr
+ ).handle_error_interruptible(
+ move_mapping_iertr::pass_further{},
+ crimson::ct_error::assert_all{"unexpected error"});
+
+ assert(cursor->is_indirect());
+ auto iter = btree.make_partial_iter(c, *cursor);
+ DEBUGT("resetting child ptr, leaf: {}, pos: {}",
+ t, *iter.get_leaf_node(), iter.get_leaf_pos());
+ iter.get_leaf_node()->reset_child_ptr(iter.get_leaf_pos());
+ ret.src = std::move(cursor);
+ co_await ret.dest->refresh();
+ co_return ret;
+}
+
}
extent_len_t len,
bool updateref) final;
+ move_mapping_ret move_indirect_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest) final {
+ assert(src->is_indirect());
+ return _move_mapping(
+ t, std::move(src), dest_laddr, std::move(dest), nullptr);
+ }
+
+ move_mapping_ret move_direct_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode &extent) final {
+ assert(!src->is_indirect());
+ return _move_mapping(
+ t, std::move(src), dest_laddr, std::move(dest), &extent);
+ }
+
+ move_mapping_ret move_and_clone_direct_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode &extent) final;
+
#ifdef UNIT_TESTS_BUILT
get_end_mapping_ret get_end_mapping(Transaction &t) final;
#endif
seastar::metrics::metric_group metrics;
void register_metrics(store_index_t store_index);
+ /*
+ * _move_mapping
+ *
+ * copy the mapping "src" to "dest" and remove the "src" mapping.
+ *
+ * Return: the mappings next to "src" and the "dest" mapping
+ */
+ move_mapping_ret _move_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode *extent);
+
+ /*
+ * _copy_mapping
+ *
+ * copy the mapping "src" to "dest", the extent attached to
+ * "src" will also be attached to the dest. This is the building
+ * block for _move_mapping and move_and_clone_direct_mapping
+ *
+ * Return: the "src" and the new "dest"
+ */
+ move_mapping_ret _copy_mapping(
+ op_context_t c,
+ LBABtree &btree,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode *extent);
+
/**
* _update_mapping
*
// direct mapping
) = 0;
+ struct move_mapping_ret_t {
+ LBACursorRef src;
+ LBACursorRef dest;
+ };
+ /*
+ * move_and_clone_direct_mapping
+ *
+ * move the direct mapping "src" to "dest" and clone it at the
+ * position of "src".
+ *
+ * Return: the new indirect mapping and the moved direct mapping
+ */
+ using move_mapping_iertr = alloc_extent_iertr;
+ using move_mapping_ret = move_mapping_iertr::future<move_mapping_ret_t>;
+ virtual move_mapping_ret move_and_clone_direct_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode &extent) = 0;
+
+ /*
+ * move_indirect_mapping
+ *
+ * move the indirect mapping "src" to dest, and remove "src".
+ *
+ * Return: the mapping next to "src" and the original "dest"
+ */
+ virtual move_mapping_ret move_indirect_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest) = 0;
+
+ /*
+ * move_direct_mapping
+ *
+ * move the indirect mapping "src" to dest, and remove "src".
+ *
+ * Return: the mapping next to "src" and the original "dest"
+ */
+ virtual move_mapping_ret move_direct_mapping(
+ Transaction &t,
+ LBACursorRef src,
+ laddr_t dest_laddr,
+ LBACursorRef dest,
+ LogicalChildNode &extent) = 0;
+
virtual alloc_extent_ret reserve_region(
Transaction &t,
laddr_hint_t hint,