assert(!this->parent_modified());
assert(pos != std::numeric_limits<uint16_t>::max());
auto &p = (FixedKVNode<key_t>&)*parent;
- return p.is_child_stable(ctx, pos);
+ auto k = this->is_indirect()
+ ? this->get_intermediate_base()
+ : get_key();
+ return p.is_child_stable(ctx, pos, k);
}
template <typename key_t, typename val_t>
assert(!this->parent_modified());
assert(pos != std::numeric_limits<uint16_t>::max());
auto &p = (FixedKVNode<key_t>&)*parent;
- return p.is_child_data_stable(ctx, pos);
+ auto k = this->is_indirect()
+ ? this->get_intermediate_base()
+ : get_key();
+ return p.is_child_data_stable(ctx, pos, k);
}
template class BtreeNodeMapping<laddr_t, paddr_t>;
set_child_ptracker(child);
}
- virtual bool is_child_stable(op_context_t<node_key_t>, uint16_t pos) const = 0;
- virtual bool is_child_data_stable(op_context_t<node_key_t>, uint16_t pos) const = 0;
+ virtual bool is_child_stable(
+ op_context_t<node_key_t>,
+ uint16_t pos,
+ node_key_t key) const = 0;
+ virtual bool is_child_data_stable(
+ op_context_t<node_key_t>,
+ uint16_t pos,
+ node_key_t key) const = 0;
template <typename T>
get_child_ret_t<T> get_child(
node_key_t key)
{
assert(children.capacity());
+ assert(key == get_key_from_idx(pos));
auto child = children[pos];
ceph_assert(!is_reserved_ptr(child));
if (is_valid_child_ptr(child)) {
}
}
- bool is_child_stable(op_context_t<NODE_KEY>, uint16_t pos) const final {
+ bool is_child_stable(
+ op_context_t<NODE_KEY>,
+ uint16_t pos,
+ NODE_KEY key) const final {
ceph_abort("impossible");
return false;
}
- bool is_child_data_stable(op_context_t<NODE_KEY>, uint16_t pos) const final {
+ bool is_child_data_stable(
+ op_context_t<NODE_KEY>,
+ uint16_t pos,
+ NODE_KEY key) const final {
ceph_abort("impossible");
return false;
}
// 2. The child extent is stable
//
// For reserved mappings, the return values are undefined.
- bool is_child_stable(op_context_t<NODE_KEY> c, uint16_t pos) const final {
- return _is_child_stable(c, pos);
+ bool is_child_stable(
+ op_context_t<NODE_KEY> c,
+ uint16_t pos,
+ NODE_KEY key) const final {
+ return _is_child_stable(c, pos, key);
}
- bool is_child_data_stable(op_context_t<NODE_KEY> c, uint16_t pos) const final {
- return _is_child_stable(c, pos, true);
+ bool is_child_data_stable(
+ op_context_t<NODE_KEY> c,
+ uint16_t pos,
+ NODE_KEY key) const final {
+ return _is_child_stable(c, pos, key, true);
}
- bool _is_child_stable(op_context_t<NODE_KEY> c, uint16_t pos, bool data_only = false) const {
+ bool _is_child_stable(
+ op_context_t<NODE_KEY> c,
+ uint16_t pos,
+ NODE_KEY key,
+ bool data_only = false) const {
+ assert(key == get_key_from_idx(pos));
auto child = this->children[pos];
if (is_reserved_ptr(child)) {
return true;
return false;
};
+ virtual void maybe_fix_pos() {
+ ceph_abort("impossible");
+ }
+
virtual ~PhysicalNodeMapping() {}
protected:
std::optional<child_pos_t> child_pos = std::nullopt;
namespace crimson::os::seastore::lba_manager::btree {
+struct LBALeafNode;
+
class BtreeLBAMapping : public BtreeNodeMapping<laddr_t, paddr_t> {
// To support cloning, there are two kinds of lba mappings:
// 1. physical lba mapping: the pladdr in the value of which is the paddr of
return p.modified_since(parent_modifications);
}
+ void maybe_fix_pos() final {
+ assert(is_parent_valid());
+ if (!parent_modified()) {
+ return;
+ }
+ auto &p = static_cast<LBALeafNode&>(*parent);
+ p.maybe_fix_mapping_pos(*this);
+ }
protected:
std::unique_ptr<BtreeNodeMapping<laddr_t, paddr_t>> _duplicate(
op_context_t<laddr_t> ctx) const final {
return pin;
}
private:
+ void _new_pos(uint16_t pos) {
+ this->pos = pos;
+ }
+
laddr_t key = L_ADDR_NULL;
bool indirect = false;
laddr_t intermediate_key = L_ADDR_NULL;
pladdr_t raw_val;
lba_map_val_t map_val;
uint64_t parent_modifications = 0;
+ friend struct LBALeafNode;
};
using BtreeLBAMappingRef = std::unique_ptr<BtreeLBAMapping>;
#include "include/buffer.h"
#include "include/byteorder.h"
-#include "crimson/os/seastore/lba_manager/btree/lba_btree_node.h"
+#include "crimson/os/seastore/lba_manager/btree/btree_lba_manager.h"
#include "crimson/os/seastore/logging.h"
SET_SUBSYS(seastore_lba);
}
}
+void LBALeafNode::maybe_fix_mapping_pos(BtreeLBAMapping &mapping)
+{
+ assert(mapping.get_parent() == this);
+ auto key = mapping.is_indirect()
+ ? mapping.get_intermediate_base()
+ : mapping.get_key();
+ if (key != iter_idx(mapping.get_pos()).get_key()) {
+ auto iter = lower_bound(key);
+ {
+ // a mapping that no longer exist or has its value
+ // modified is considered an outdated one, and
+ // shouldn't be used anymore
+ ceph_assert(iter != end());
+ assert(iter.get_val() == mapping.get_map_val());
+ }
+ mapping._new_pos(iter.get_offset());
+ }
+}
+
}
using base_iertr = LBAManager::base_iertr;
using LBANode = FixedKVNode<laddr_t>;
+class BtreeLBAMapping;
+
/**
* lba_map_val_t
*
}
std::ostream &_print_detail(std::ostream &out) const final;
+
+ void maybe_fix_mapping_pos(BtreeLBAMapping &mapping);
};
using LBALeafNodeRef = TCachedExtentRef<LBALeafNode>;
Transaction &t,
LBAMappingRef pin)
{
- // checking the lba child must be atomic with creating
- // and linking the absent child
- auto ret = get_extent_if_linked<T>(t, std::move(pin));
- if (ret.index() == 1) {
- return std::move(std::get<1>(ret));
+ auto fut = base_iertr::make_ready_future<LBAMappingRef>();
+ if (!pin->is_parent_valid()) {
+ fut = get_pin(t, pin->get_key()
+ ).handle_error_interruptible(
+ crimson::ct_error::enoent::assert_failure{"unexpected enoent"},
+ crimson::ct_error::input_output_error::pass_further{}
+ );
} else {
- return this->pin_to_extent<T>(t, std::move(std::get<0>(ret)));
+ pin->maybe_fix_pos();
+ fut = base_iertr::make_ready_future<LBAMappingRef>(std::move(pin));
}
+ return fut.si_then([&t, this](auto npin) mutable {
+ // checking the lba child must be atomic with creating
+ // and linking the absent child
+ auto ret = get_extent_if_linked<T>(t, std::move(npin));
+ if (ret.index() == 1) {
+ return std::move(std::get<1>(ret));
+ } else {
+ return this->pin_to_extent<T>(t, std::move(std::get<0>(ret)));
+ }
+ });
}
template <typename T>
LBAMappingRef pin)
{
ceph_assert(pin->is_parent_valid());
+ // checking the lba child must be atomic with creating
+ // and linking the absent child
auto v = pin->get_logical_extent(t);
if (v.has_child()) {
return v.get_child_fut().safe_then([pin=std::move(pin)](auto extent) {
// The according extent might be stable or pending.
auto fut = base_iertr::now();
if (!pin->is_indirect()) {
- auto fut2 = base_iertr::make_ready_future<TCachedExtentRef<T>>();
- if (full_extent_integrity_check) {
- fut2 = read_pin<T>(t, pin->duplicate());
+ if (!pin->is_parent_valid()) {
+ fut = get_pin(t, pin->get_key()
+ ).si_then([&pin](auto npin) {
+ assert(npin);
+ pin = std::move(npin);
+ return seastar::now();
+ }).handle_error_interruptible(
+ crimson::ct_error::enoent::assert_failure{"unexpected enoent"},
+ crimson::ct_error::input_output_error::pass_further{}
+ );
} else {
- auto ret = get_extent_if_linked<T>(t, pin->duplicate());
- if (ret.index() == 1) {
- fut2 = std::move(std::get<1>(ret));
- }
+ pin->maybe_fix_pos();
}
- fut = fut2.si_then([this, &t, &remaps, original_paddr,
+
+ fut = fut.si_then([this, &t, &pin] {
+ if (full_extent_integrity_check) {
+ return read_pin<T>(t, pin->duplicate());
+ } else {
+ auto ret = get_extent_if_linked<T>(t, pin->duplicate());
+ if (ret.index() == 1) {
+ return std::move(std::get<1>(ret));
+ }
+ }
+ return base_iertr::make_ready_future<TCachedExtentRef<T>>();
+ }).si_then([this, &t, &remaps, original_paddr,
original_laddr, original_len,
&extents, FNAME](auto ext) mutable {
ceph_assert(full_extent_integrity_check