typename NodeType::Ref node;
uint16_t pos = INVALID;
+ node_position_t() = default;
+ node_position_t(
+ typename NodeType::Ref node,
+ uint16_t pos)
+ : node(node), pos(pos) {}
+
void reset() {
*this = node_position_t{};
}
phy_tree_root_t root;
bool root_dirty = false;
+ template <typename T>
+ using node_position_t = typename iterator::template node_position_t<T>;
+
using get_internal_node_iertr = base_iertr;
using get_internal_node_ret = get_internal_node_iertr::future<InternalNodeRef>;
static get_internal_node_ret get_internal_node(
depth_t depth,
paddr_t offset,
node_key_t begin,
- node_key_t end)
+ node_key_t end,
+ typename std::optional<node_position_t<internal_node_t>> parent_pos)
{
LOG_PREFIX(FixedKVBtree::get_internal_node);
SUBTRACET(
begin,
end);
assert(depth > 1);
- auto init_internal = [c, depth, begin, end](internal_node_t &node) {
+ auto init_internal = [c, depth, begin, end,
+ parent_pos=std::move(parent_pos)]
+ (internal_node_t &node) {
assert(!node.is_pending());
assert(!node.pin.is_linked());
node.pin.set_range(fixed_kv_node_meta_t<node_key_t>{begin, end, depth});
+ if (parent_pos) {
+ auto &parent = parent_pos->node;
+ parent->link_child(&node, parent_pos->pos);
+ }
if (c.pins) {
c.pins->add_pin(node.pin);
}
op_context_t<node_key_t> c,
paddr_t offset,
node_key_t begin,
- node_key_t end)
+ node_key_t end,
+ typename std::optional<node_position_t<leaf_node_t>> parent_pos)
{
LOG_PREFIX(FixedKVBtree::get_leaf_node);
SUBTRACET(
offset,
begin,
end);
- auto init_leaf = [c, begin, end](leaf_node_t &node) {
+ auto init_leaf = [c, begin, end,
+ parent_pos=std::move(parent_pos)]
+ (leaf_node_t &node) {
assert(!node.is_pending());
assert(!node.pin.is_linked());
node.pin.set_range(fixed_kv_node_meta_t<node_key_t>{begin, end, 1});
+ if (parent_pos) {
+ auto &parent = parent_pos->node;
+ parent->link_child(&node, parent_pos->pos);
+ }
if (c.pins) {
c.pins->add_pin(node.pin);
}
root.get_depth(),
root.get_location(),
min_max_t<node_key_t>::min,
- min_max_t<node_key_t>::max
+ min_max_t<node_key_t>::max,
+ std::nullopt
).si_then([this, visitor, &iter](InternalNodeRef root_node) {
iter.get_internal(root.get_depth()).node = root_node;
if (visitor) (*visitor)(
c,
root.get_location(),
min_max_t<node_key_t>::min,
- min_max_t<node_key_t>::max
+ min_max_t<node_key_t>::max,
+ std::nullopt
).si_then([visitor, &iter, this](LeafNodeRef root_node) {
iter.leaf.node = root_node;
if (visitor) (*visitor)(
F &f,
mapped_space_visitor_t *visitor
) {
+ LOG_PREFIX(FixedKVBtree::lookup_internal_level);
assert(depth > 1);
auto &parent_entry = iter.get_internal(depth + 1);
auto parent = parent_entry.node;
auto node_iter = parent->iter_idx(parent_entry.pos);
- auto next_iter = node_iter + 1;
- auto begin = node_iter->get_key();
- auto end = next_iter == parent->end()
- ? parent->get_node_meta().end
- : next_iter->get_key();
- return get_internal_node(
- c,
- depth,
- node_iter->get_val().maybe_relative_to(parent->get_paddr()),
- begin,
- end
- ).si_then([depth, visitor, &iter, &f](InternalNodeRef node) {
+
+ auto on_found = [depth, visitor, &iter, &f](InternalNodeRef node) {
auto &entry = iter.get_internal(depth);
entry.node = node;
auto node_iter = f(*node);
depth,
node->get_type());
return seastar::now();
+ };
+
+ auto child_pos = parent->get_child(c.trans, node_iter);
+ auto &child = child_pos.child;
+ if (child) {
+ SUBTRACET(seastore_fixedkv_tree,
+ "got child on {}, pos: {}, res: {}",
+ c.trans,
+ *parent_entry.node,
+ parent_entry.pos,
+ *child);
+
+ ceph_assert(child->is_valid());
+ if (!child->is_pending_in_trans(c.trans.get_trans_id())) {
+ c.trans.add_to_read_set(child);
+ if (!child->is_mutation_pending()) {
+ c.cache.touch_extent(*child);
+ }
+ }
+ return child->wait_io().then(
+ [child, on_found=std::move(on_found), node_iter]() mutable {
+ auto &cnode = (typename internal_node_t::base_t &)*child;
+ assert(cnode.get_node_meta().begin == node_iter.get_key());
+ assert(cnode.get_node_meta().end > node_iter.get_key());
+ return on_found(child->template cast<internal_node_t>());
+ });
+ }
+
+ auto next_iter = node_iter + 1;
+ auto begin = node_iter->get_key();
+ auto end = next_iter == parent->end()
+ ? parent->get_node_meta().end
+ : next_iter->get_key();
+ return get_internal_node(
+ c,
+ depth,
+ node_iter->get_val().maybe_relative_to(parent->get_paddr()),
+ begin,
+ end,
+ std::make_optional<node_position_t<internal_node_t>>(
+ child_pos.stable_parent->template cast<internal_node_t>(),
+ child_pos.pos)
+ ).si_then([on_found=std::move(on_found)](InternalNodeRef node) {
+ return on_found(node);
});
}
F &f,
mapped_space_visitor_t *visitor
) {
+ LOG_PREFIX(FixedKVBtree::lookup_leaf);
auto &parent_entry = iter.get_internal(2);
auto parent = parent_entry.node;
assert(parent);
auto node_iter = parent->iter_idx(parent_entry.pos);
- auto next_iter = node_iter + 1;
- auto begin = node_iter->get_key();
- auto end = next_iter == parent->end()
- ? parent->get_node_meta().end
- : next_iter->get_key();
- return get_leaf_node(
- c,
- node_iter->get_val().maybe_relative_to(parent->get_paddr()),
- begin,
- end
- ).si_then([visitor, &iter, &f](LeafNodeRef node) {
+ auto on_found = [visitor, &iter, &f](LeafNodeRef node) {
iter.leaf.node = node;
auto node_iter = f(*node);
iter.leaf.pos = node_iter->get_offset();
1,
node->get_type());
return seastar::now();
+ };
+
+ auto child_pos = parent->get_child(c.trans, node_iter);
+ auto &child = child_pos.child;
+ if (child) {
+ SUBTRACET(seastore_fixedkv_tree,
+ "got child on {}, pos: {}, res: {}",
+ c.trans,
+ *parent_entry.node,
+ parent_entry.pos,
+ *child);
+
+ ceph_assert(child->is_valid());
+ if (!child->is_pending_in_trans(c.trans.get_trans_id())) {
+ c.trans.add_to_read_set(child);
+ if (!child->is_mutation_pending()) {
+ c.cache.touch_extent(*child);
+ }
+ }
+ return child->wait_io().then(
+ [child, on_found=std::move(on_found), node_iter]() mutable {
+ auto &cnode = (typename internal_node_t::base_t &)*child;
+ assert(cnode.get_node_meta().begin == node_iter.get_key());
+ assert(cnode.get_node_meta().end > node_iter.get_key());
+ return on_found(child->template cast<leaf_node_t>());
+ });
+ }
+
+ auto next_iter = node_iter + 1;
+ auto begin = node_iter->get_key();
+ auto end = next_iter == parent->end()
+ ? parent->get_node_meta().end
+ : next_iter->get_key();
+
+ return get_leaf_node(
+ c,
+ node_iter->get_val().maybe_relative_to(parent->get_paddr()),
+ begin,
+ end,
+ std::make_optional<node_position_t<leaf_node_t>>(
+ child_pos.stable_parent->template cast<leaf_node_t>(),
+ child_pos.pos)
+ ).si_then([on_found=std::move(on_found)](LeafNodeRef node) {
+ return on_found(node);
});
}
});
}
- template <typename T>
- using node_position_t = typename iterator::template node_position_t<T>;
-
template <typename NodeType,
std::enable_if_t<std::is_same_v<NodeType, leaf_node_t>, int> = 0>
base_iertr::future<typename NodeType::Ref> get_node(
depth_t depth,
paddr_t addr,
node_key_t begin,
- node_key_t end) {
+ node_key_t end,
+ typename std::optional<node_position_t<leaf_node_t>> parent_pos) {
assert(depth == 1);
- return get_leaf_node(c, addr, begin, end);
+ return get_leaf_node(c, addr, begin, end, std::move(parent_pos));
}
template <typename NodeType,
depth_t depth,
paddr_t addr,
node_key_t begin,
- node_key_t end) {
- return get_internal_node(c, depth, addr, begin, end);
+ node_key_t end,
+ typename std::optional<node_position_t<internal_node_t>> parent_pos) {
+ return get_internal_node(c, depth, addr, begin, end, std::move(parent_pos));
}
template <typename NodeType>
: next_iter->get_key();
SUBTRACET(seastore_fixedkv_tree, "parent: {}, node: {}", c.trans, *parent_pos.node, *pos.node);
- return get_node<NodeType>(
- c,
- depth,
- donor_iter.get_val().maybe_relative_to(parent_pos.node->get_paddr()),
- begin,
- end
- ).si_then([c, iter, donor_iter, donor_is_left, &parent_pos, &pos](
+ auto do_merge = [c, iter, donor_iter, donor_is_left, &parent_pos, &pos](
typename NodeType::Ref donor) {
LOG_PREFIX(FixedKVBtree::merge_level);
auto [l, r] = donor_is_left ?
}
return seastar::now();
+ };
+
+ auto child_pos = parent_pos.node->get_child(c.trans, donor_iter);
+ auto &child = child_pos.child;
+ if (child) {
+ SUBTRACET(seastore_fixedkv_tree,
+ "got child on {}, pos: {}, res: {}",
+ c.trans,
+ *parent_pos.node,
+ donor_iter.get_offset(),
+ *child);
+
+ ceph_assert(child->is_valid());
+ if (!child->is_pending_in_trans(c.trans.get_trans_id())) {
+ c.trans.add_to_read_set(child);
+ if (!child->is_mutation_pending()) {
+ c.cache.touch_extent(*child);
+ }
+ }
+ return child->wait_io().then(
+ [child, do_merge=std::move(do_merge), &pos,
+ donor_iter, donor_is_left]() mutable {
+ auto &node = (typename internal_node_t::base_t&)*child;
+ assert(donor_is_left ?
+ node.get_node_meta().end == pos.node->get_node_meta().begin :
+ node.get_node_meta().begin == pos.node->get_node_meta().end);
+ assert(node.get_node_meta().begin == donor_iter.get_key());
+ assert(node.get_node_meta().end > donor_iter.get_key());
+ return do_merge(child->template cast<NodeType>());
+ });
+ }
+
+ return get_node<NodeType>(
+ c,
+ depth,
+ donor_iter.get_val().maybe_relative_to(parent_pos.node->get_paddr()),
+ begin,
+ end,
+ std::make_optional<node_position_t<NodeType>>(
+ child_pos.stable_parent->template cast<NodeType>(),
+ child_pos.pos)
+ ).si_then([do_merge=std::move(do_merge)](typename NodeType::Ref donor) {
+ return do_merge(donor);
});
}
};
class TransactionManager;
class ExtentPlacementManager;
+template <
+ typename node_key_t,
+ typename node_val_t,
+ typename internal_node_t,
+ typename leaf_node_t,
+ typename pin_t,
+ size_t node_size>
+class FixedKVBtree;
+
// #define DEBUG_CACHED_EXTENT_REF
#ifdef DEBUG_CACHED_EXTENT_REF
template <typename T>
class read_set_item_t {
- boost::intrusive::list_member_hook<> list_hook;
- using list_hook_options = boost::intrusive::member_hook<
+ using set_hook_t = boost::intrusive::set_member_hook<
+ boost::intrusive::link_mode<
+ boost::intrusive::auto_unlink>>;
+ set_hook_t trans_hook;
+ using set_hook_options = boost::intrusive::member_hook<
read_set_item_t,
- boost::intrusive::list_member_hook<>,
- &read_set_item_t::list_hook>;
+ set_hook_t,
+ &read_set_item_t::trans_hook>;
public:
struct cmp_t {
bool operator()(const read_set_item_t<T> &lhs, const paddr_t &rhs) const;
};
- using list = boost::intrusive::list<
+ struct trans_cmp_t {
+ bool operator()(
+ const read_set_item_t<Transaction> &lhs,
+ const read_set_item_t<Transaction> &rhs) const {
+ return lhs.t < rhs.t;
+ }
+ bool operator()(
+ const Transaction *lhs,
+ const read_set_item_t<Transaction> &rhs) const {
+ return lhs < rhs.t;
+ }
+ bool operator()(
+ const read_set_item_t<Transaction> &lhs,
+ const Transaction *rhs) const {
+ return lhs.t < rhs;
+ }
+ };
+
+ using trans_set_t = boost::intrusive::set<
read_set_item_t,
- list_hook_options>;
+ set_hook_options,
+ boost::intrusive::constant_time_size<false>,
+ boost::intrusive::compare<trans_cmp_t>>;
T *t = nullptr;
CachedExtentRef ref;
read_set_item_t(T *t, CachedExtentRef ref);
read_set_item_t(const read_set_item_t &) = delete;
read_set_item_t(read_set_item_t &&) = default;
- ~read_set_item_t();
+ ~read_set_item_t() = default;
};
template <typename T>
using read_set_t = std::set<
friend class onode::DummyNodeExtent;
friend class onode::TestReplayExtent;
+ template <
+ typename node_key_t,
+ typename node_val_t,
+ typename internal_node_t,
+ typename leaf_node_t,
+ typename pin_t,
+ size_t node_size>
+ friend class FixedKVBtree;
uint32_t last_committed_crc = 0;
// Points at current version while in state MUTATION_PENDING
return extent_index_hook.is_linked();
}
+ /// Returns true if the extent part of the open transaction
+ bool is_pending_in_trans(transaction_id_t id) const {
+ return is_pending() && pending_for_transaction == id;
+ }
+
/// hook for intrusive ref list (mainly dirty or lru list)
boost::intrusive::list_member_hook<> primary_ref_list_hook;
using primary_ref_list_member_options = boost::intrusive::member_hook<
}
}
- read_set_item_t<Transaction>::list transactions;
+ CachedExtent* get_transactional_view(Transaction &t);
+
+ read_set_item_t<Transaction>::trans_set_t transactions;
placement_hint_t user_hint = PLACEMENT_HINT_NULL;
struct retired_placeholder_t{};
CachedExtent(retired_placeholder_t) : state(extent_state_t::INVALID) {}
- CachedExtent& get_transactional_view(Transaction &t);
-
friend class Cache;
template <typename T, typename... Args>
static TCachedExtentRef<T> make_cached_extent_ref(
template <typename T>
read_set_item_t<T>::read_set_item_t(T *t, CachedExtentRef ref)
: t(t), ref(ref)
-{
- ref->transactions.push_back(*this);
-}
-
-template <typename T>
-read_set_item_t<T>::~read_set_item_t()
-{
- ref->transactions.erase(ref->transactions.s_iterator_to(*this));
-}
+{}
template <typename T>
inline bool read_set_item_t<T>::cmp_t::operator()(