}
+ // return true if reached the next mapping and false otherwise
+ bool next_sync(op_context_t c) {
+#ifndef NDEBUG
+ assert_valid();
+#endif
+ assert(is_full());
+ assert(!is_end());
+ leaf.pos++;
+ if (at_boundary()) {
+ return handle_boundary_sync(c);
+ } else {
+ return true;
+ }
+ }
+
/**
* Move to the previous entry. If already at position 0 in the current
* leaf, walks up the internal stack (ensure_internal_bottom_up) to find
});
}
+ // return true if reached the next mapping and false otherwise
+ bool handle_boundary_sync(op_context_t c) {
+ assert(at_boundary());
+ assert(is_full());
+ depth_t depth = 2;
+ // find the first level (from the leaf's parent up) with a right sibling
+ for (; depth <= get_depth(); depth++) {
+ auto &internal = get_internal(depth);
+ auto it = internal.node->iter_idx(internal.pos + 1);
+ if (it != internal.node->end()) {
+ break;
+ }
+ }
+ if (depth > get_depth()) {
+ return false; // no next leaf (end)
+ }
+ // step to the right sibling at that level, then descend leftmost to the leaf
+ get_internal(depth).pos++;
+ while (depth > 2) {
+ auto &internal = get_internal(depth);
+ auto it = get_internal(depth).node->iter_idx(internal.pos);
+ auto child = get_internal(depth).node->template get_child_sync<
+ internal_node_t>(c.trans, c.cache, internal.pos, it.get_key());
+ if (!is_valid_child_ptr(child.get())) {
+ return false;
+ }
+ depth--;
+ get_internal(depth).node = child;
+ get_internal(depth).pos = 0;
+ }
+ assert(depth == 2);
+ // position `leaf` at the next leaf
+ auto &parent = get_internal(depth);
+ auto it = parent.node->begin();
+ auto child = parent.node->template get_child_sync<
+ leaf_node_t>(c.trans, c.cache, parent.pos, it.get_key());
+ if (!is_valid_child_ptr(child.get())) {
+ return false;
+ }
+ leaf.node = child;
+ leaf.pos = 0;
+ return true;
+ }
+
/**
* Called when leaf.pos has advanced past the end of the current leaf
* (at_boundary() == true). Walks up the internal stack to find the
if (depth > 1) {
auto child = entry.node->template get_child_sync<internal_node_t>(
c.trans, c.cache, entry.pos, riter.get_key());
+ ceph_assert(is_valid_child_ptr(child.get()));
iter.get_internal(depth).node = child;
} else {
auto child = entry.node->template get_child_sync<leaf_node_t>(
c.trans, c.cache, entry.pos, riter.get_key());
+ ceph_assert(is_valid_child_ptr(child.get()));
iter.leaf.node = child;
}
}
Transaction &t,
laddr_t laddr,
paddr_t paddr,
+ extent_len_t len,
std::optional<paddr_t> shadow)
{
LOG_PREFIX(BtreeLBAManager::update_paddr_sync);
auto c = get_context(t);
auto btree = get_btree_sync<LBABtree>(c);
auto iter = btree.lower_bound_sync(c, laddr);
- assert(iter.get_leaf_node()->is_pending());
- auto child = iter.get_leaf_node()->get_child_sync<LogicalChildNode>(
- c.trans, c.cache, iter.get_leaf_pos(), iter.get_key());
- ceph_assert(child);
- if (child->is_initial_pending()) {
- TRACET("{} is initial_pending, skipping", t, *child);
- return;
- }
- ceph_assert(child->is_exist_clean());
- auto cursor = iter.get_cursor(c);
- assert(cursor->get_laddr() == laddr);
- paddr_t shadow_paddr;
- if (shadow) {
- // the committing txn changed the shadow
- // to *shadow
- shadow_paddr = *shadow;
- } else if (cursor->has_shadow_paddr()) {
- // shadow is preserved by the committer,
- // and the copy inherited one, so the source
- // was promoted when it's copied
- shadow_paddr = cursor->get_shadow_paddr();
- } else {
- // shadow is preserved, and nothing is
- // inherited: not currently promoted
- shadow_paddr = P_ADDR_NULL;
+ while (iter.get_key() + iter.get_val().len <= laddr + len) {
+ assert(iter.get_leaf_node()->is_pending());
+ if (iter.get_val().pladdr.is_laddr() ||
+ iter.get_val().pladdr.get_paddr().is_zero()) {
+ TRACET("skipping mapping {}~{}", t, iter.get_key(), iter.get_val());
+ if (!iter.next_sync(c)) {
+ // can't reach the next mapping, which means the next
+ // mapping mustn't have been touched by the current
+ // transactions, we don't need to continue, just leave
+ return;
+ }
+ continue;
+ }
+ auto child = iter.get_leaf_node()->get_child_sync<LogicalChildNode>(
+ c.trans, c.cache, iter.get_leaf_pos(), iter.get_key());
+ ceph_assert(is_valid_child_ptr(child.get()));
+ if (child->is_initial_pending()) {
+ TRACET("{} is initial_pending, skipping", t, *child);
+ if (!iter.next_sync(c)) {
+ // can't reach the next mapping, which means the next
+ // mapping mustn't have been touched by the current
+ // transactions, we don't need to continue, just leave
+ return;
+ }
+ continue;
+ }
+ ceph_assert(child->is_exist_clean());
+ auto cursor = iter.get_cursor(c);
+ extent_len_t off = cursor->get_laddr().get_byte_distance<
+ extent_len_t>(laddr);
+ paddr_t shadow_paddr;
+ if (shadow) {
+ // the committing txn changed the shadow
+ // to *shadow
+ shadow_paddr = *shadow;
+ if (shadow_paddr != P_ADDR_NULL) {
+ shadow_paddr = shadow_paddr + off;
+ }
+ } else if (cursor->has_shadow_paddr()) {
+ // shadow is preserved by the committer,
+ // and the copy inherited one, so the source
+ // was promoted when it's copied
+ shadow_paddr = cursor->get_shadow_paddr();
+ } else {
+ // shadow is preserved, and nothing is
+ // inherited: not currently promoted
+ shadow_paddr = P_ADDR_NULL;
+ }
+ iter = btree.update(
+ c,
+ std::move(iter),
+ lba_map_val_t{
+ cursor->get_length(),
+ pladdr_t{paddr + off},
+ shadow_paddr,
+ cursor->get_refcount(),
+ cursor->get_checksum(),
+ cursor->get_extent_type()},
+ nullptr,
+ modification_t::TRANS_SYNC);
+ if (!iter.next_sync(c)) {
+ // can't reach the next mapping, which means the next
+ // mapping mustn't have been touched by the current
+ // transactions, we don't need to continue, just leave
+ return;
+ }
}
- btree.update(
- c,
- std::move(iter),
- lba_map_val_t{
- cursor->get_length(),
- pladdr_t{std::move(paddr)},
- shadow_paddr,
- cursor->get_refcount(),
- cursor->get_checksum(),
- cursor->get_extent_type()},
- nullptr,
- modification_t::TRANS_SYNC);
}
// ---------------------------------------------------------------------------
c.trans.new_lba_key_copied(
ret.src->get_key(),
dest_laddr,
- [this, c](laddr_t laddr, paddr_t paddr, std::optional<paddr_t> shadow) {
- update_paddr_sync(c.trans, laddr, paddr, shadow);
+ ret.src->get_length(),
+ [this, c](laddr_t laddr, paddr_t paddr,
+ extent_len_t len, std::optional<paddr_t> shadow) {
+ update_paddr_sync(c.trans, laddr, paddr, len, shadow);
});
auto [niter, inserted] = co_await btree.copy(
c,
bool force_rewrite_conflict = false;
+ struct lmapping_t {
+ laddr_t dest = L_ADDR_NULL;
+ extent_len_t len = 0;
+ };
using update_copied_lba_key_func_t =
- std::function<void (laddr_t, paddr_t, std::optional<paddr_t>)>;
+ std::function<void (laddr_t, paddr_t,
+ extent_len_t, std::optional<paddr_t>)>;
void new_lba_key_copied(
laddr_t src,
laddr_t dest,
+ extent_len_t len,
update_copied_lba_key_func_t &&func) {
- copied_lba_keys.emplace(src, dest);
+ copied_lba_keys.emplace(src, lmapping_t{dest, len});
if (!update_copied_lba_key) {
update_copied_lba_key = std::move(func);
}
if (it == copied_lba_keys.end()) {
return;
}
- laddr_t key = it->second;
- update_copied_lba_key(key, paddr, shadow);
+ laddr_t key = it->second.dest;
+ extent_len_t len = it->second.len;
+ update_copied_lba_key(key, paddr, len, shadow);
}
RootBlockRef peek_root() {
return root;
cache_hint_t cache_hint = CACHE_HINT_TOUCH;
- std::map<laddr_t, laddr_t> copied_lba_keys;
+ std::map<laddr_t, lmapping_t> copied_lba_keys;
update_copied_lba_key_func_t update_copied_lba_key;
};
using TransactionRef = Transaction::Ref;