#include "crimson/os/seastore/cache.h"
#include "crimson/os/seastore/seastore_types.h"
#include "crimson/os/seastore/btree/btree_range_pin.h"
+#include "crimson/os/seastore/root_block.h"
namespace crimson::os::seastore::lba_manager::btree {
struct lba_map_val_t;
namespace crimson::os::seastore {
+template <typename T>
+phy_tree_root_t& get_phy_tree_root(root_t& r);
+
template <typename node_key_t>
struct op_context_t {
Cache &cache;
btree_pin_set_t<node_key_t> *pins = nullptr;
};
+using get_phy_tree_root_node_ret =
+ std::pair<bool,
+ ::crimson::interruptible::interruptible_future<
+ typename trans_intr::condition, CachedExtentRef>>;
+
+template <typename T, typename key_t>
+const get_phy_tree_root_node_ret get_phy_tree_root_node(
+ const RootBlockRef &root_block,
+ op_context_t<key_t> c);
+
+template <typename ROOT_T>
+void link_phy_tree_root_node(RootBlockRef &root_block, ROOT_T* root_node);
+
+template <typename T>
+void unlink_phy_tree_root_node(RootBlockRef &root_block);
+
+
template <typename T>
Transaction::tree_stats_t& get_tree_stats(Transaction &t);
}
};
- FixedKVBtree(phy_tree_root_t root) : root(root) {}
+ FixedKVBtree(RootBlockRef &root_block) : root_block(root_block) {}
- bool is_root_dirty() const {
- return root_dirty;
+ auto& get_root() {
+ return get_phy_tree_root<self_type>(root_block->get_root());
}
- phy_tree_root_t get_root_undirty() {
- ceph_assert(root_dirty);
- root_dirty = false;
- return root;
+
+ auto& get_root() const {
+ return get_phy_tree_root<self_type>(root_block->get_root());
+ }
+
+ template <typename T>
+ void set_root_node(const TCachedExtentRef<T> &root_node) {
+ static_assert(std::is_base_of_v<typename internal_node_t::base_t, T>);
+ link_phy_tree_root_node(root_block, root_node.get());
+ }
+
+ auto get_root_node(op_context_t<node_key_t> c) const {
+ return get_phy_tree_root_node<self_type>(root_block, c);
}
/// mkfs
using mkfs_ret = phy_tree_root_t;
- static mkfs_ret mkfs(op_context_t<node_key_t> c) {
+ static mkfs_ret mkfs(RootBlockRef &root_block, op_context_t<node_key_t> c) {
+ assert(root_block->is_mutation_pending());
auto root_leaf = c.cache.template alloc_new_extent<leaf_node_t>(
c.trans,
node_size,
root_leaf->pin.set_range(meta);
get_tree_stats<self_type>(c.trans).depth = 1u;
get_tree_stats<self_type>(c.trans).extents_num_delta++;
+ link_phy_tree_root_node(root_block, root_leaf.get());
return phy_tree_root_t{root_leaf->get_paddr(), 1u};
}
depth,
old_addr,
new_addr,
- root.get_location());
+ get_root().get_location());
ceph_assert(0 == "impossible");
}
- if (root.get_location() != old_addr) {
+ if (get_root().get_location() != old_addr) {
SUBERRORT(
seastore_fixedkv_tree,
"updating root laddr {} at depth {} from {} to {},"
depth,
old_addr,
new_addr,
- root.get_location());
+ get_root().get_location());
ceph_assert(0 == "impossible");
}
- root.set_location(new_addr);
- root_dirty = true;
+ root_block = c.cache.duplicate_for_write(
+ c.trans, root_block)->template cast<RootBlock>();
+ get_root().set_location(new_addr);
+ set_root_node(nextent);
} else {
auto &parent = iter.get_internal(depth + 1);
assert(parent.node);
private:
- phy_tree_root_t root;
- bool root_dirty = false;
+ RootBlockRef root_block;
template <typename T>
using node_position_t = typename iterator::template node_position_t<T>;
if (parent_pos) {
auto &parent = parent_pos->node;
parent->link_child(&node, parent_pos->pos);
+ } else {
+ assert(node.range.is_root());
+ auto root_block = c.cache.get_root_fast(c.trans);
+ if (root_block->is_mutation_pending()) {
+ auto &stable_root = (RootBlockRef&)*root_block->get_prior_instance();
+ link_phy_tree_root_node(stable_root, &node);
+ } else {
+ assert(!root_block->is_pending());
+ link_phy_tree_root_node(root_block, &node);
+ }
}
if (c.pins) {
c.pins->add_pin(node.pin);
if (parent_pos) {
auto &parent = parent_pos->node;
parent->link_child(&node, parent_pos->pos);
+ } else {
+ assert(node.range.is_root());
+ auto root_block = c.cache.get_root_fast(c.trans);
+ if (root_block->is_mutation_pending()) {
+ auto &stable_root = (RootBlockRef&)*root_block->get_prior_instance();
+ link_phy_tree_root_node(stable_root, &node);
+ } else {
+ assert(!root_block->is_pending());
+ link_phy_tree_root_node(root_block, &node);
+ }
}
if (c.pins) {
c.pins->add_pin(node.pin);
op_context_t<node_key_t> c,
iterator &iter,
mapped_space_visitor_t *visitor) const {
- if (root.get_depth() > 1) {
- return get_internal_node(
- c,
- root.get_depth(),
- root.get_location(),
- min_max_t<node_key_t>::min,
- 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)(
- root_node->get_paddr(),
- root_node->get_node_meta().begin,
- root_node->get_length(),
- root.get_depth(),
- internal_node_t::TYPE);
- return lookup_root_iertr::now();
+ LOG_PREFIX(FixedKVBtree::lookup_root);
+ SUBTRACET(seastore_fixedkv_tree,
+ "looking up root on {}",
+ c.trans,
+ *root_block);
+ auto [found, fut] = get_root_node(c);
+
+ auto on_found_internal =
+ [this, visitor, &iter](InternalNodeRef &root_node) {
+ iter.get_internal(get_root().get_depth()).node = root_node;
+ if (visitor) (*visitor)(
+ root_node->get_paddr(),
+ root_node->get_node_meta().begin,
+ root_node->get_length(),
+ get_root().get_depth(),
+ internal_node_t::TYPE);
+ return lookup_root_iertr::now();
+ };
+ auto on_found_leaf =
+ [visitor, &iter, this](LeafNodeRef root_node) {
+ iter.leaf.node = root_node;
+ if (visitor) (*visitor)(
+ root_node->get_paddr(),
+ root_node->get_node_meta().begin,
+ root_node->get_length(),
+ get_root().get_depth(),
+ leaf_node_t::TYPE);
+ return lookup_root_iertr::now();
+ };
+
+ if (found) {
+ return fut.then_interruptible(
+ [this, c, on_found_internal=std::move(on_found_internal),
+ on_found_leaf=std::move(on_found_leaf)](auto root) {
+ LOG_PREFIX(FixedKVBtree::lookup_root);
+ ceph_assert(root);
+ SUBTRACET(seastore_fixedkv_tree,
+ "got root node on {}, res: {}",
+ c.trans,
+ *root_block,
+ *root);
+
+ if (get_root().get_depth() > 1) {
+ auto root_node = root->template cast<internal_node_t>();
+ return on_found_internal(root_node);
+ } else {
+ auto root_node = root->template cast<leaf_node_t>();
+ return on_found_leaf(root_node);
+ }
});
} else {
- return get_leaf_node(
- c,
- root.get_location(),
- min_max_t<node_key_t>::min,
- 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)(
- root_node->get_paddr(),
- root_node->get_node_meta().begin,
- root_node->get_length(),
- root.get_depth(),
- leaf_node_t::TYPE);
- return lookup_root_iertr::now();
- });
+ if (get_root().get_depth() > 1) {
+ return get_internal_node(
+ c,
+ get_root().get_depth(),
+ get_root().get_location(),
+ min_max_t<node_key_t>::min,
+ min_max_t<node_key_t>::max,
+ std::nullopt
+ ).si_then([on_found=std::move(on_found_internal)](InternalNodeRef root_node) {
+ return on_found(root_node);
+ });
+ } else {
+ return get_leaf_node(
+ c,
+ get_root().get_location(),
+ min_max_t<node_key_t>::min,
+ min_max_t<node_key_t>::max,
+ std::nullopt
+ ).si_then([on_found=std::move(on_found_leaf)](LeafNodeRef root_node) {
+ return on_found(root_node);
+ });
+ }
}
}
LOG_PREFIX(FixedKVBtree::lookup);
assert(min_depth > 0);
return seastar::do_with(
- iterator{root.get_depth()},
+ iterator{get_root().get_depth()},
std::forward<LI>(lookup_internal),
std::forward<LL>(lookup_leaf),
[FNAME, this, visitor, c, min_depth](auto &iter, auto &li, auto &ll) {
auto riter = ll(*(root_entry.node));
root_entry.pos = riter->get_offset();
}
- SUBTRACET(seastore_fixedkv_tree, "got root, depth {}", c.trans, root.get_depth());
+ SUBTRACET(seastore_fixedkv_tree, "got root, depth {}",
+ c.trans, get_root().get_depth());
return lookup_depth_range(
c,
iter,
- root.get_depth() - 1,
+ get_root().get_depth() - 1,
min_depth - 1,
li,
ll,
nroot->journal_insert(
nroot->begin(),
min_max_t<node_key_t>::min,
- root.get_location(),
+ get_root().get_location(),
nullptr);
iter.internal.push_back({nroot, 0});
- root.set_location(nroot->get_paddr());
- root.set_depth(iter.get_depth());
- ceph_assert(root.get_depth() <= MAX_FIXEDKVBTREE_DEPTH);
get_tree_stats<self_type>(c.trans).depth = iter.get_depth();
get_tree_stats<self_type>(c.trans).extents_num_delta++;
- root_dirty = true;
+
+ root_block = c.cache.duplicate_for_write(
+ c.trans, root_block)->template cast<RootBlock>();
+ get_root().set_location(nroot->get_paddr());
+ get_root().set_depth(iter.get_depth());
+ ceph_assert(get_root().get_depth() <= MAX_FIXEDKVBTREE_DEPTH);
+ set_root_node(nroot);
}
/* pos may be either node_position_t<leaf_node_t> or
c.cache.retire_extent(c.trans, pos.node);
assert(pos.pos == 0);
auto node_iter = pos.get_iter();
- root.set_location(
- node_iter->get_val().maybe_relative_to(pos.node->get_paddr()));
iter.internal.pop_back();
- root.set_depth(iter.get_depth());
get_tree_stats<self_type>(c.trans).depth = iter.get_depth();
get_tree_stats<self_type>(c.trans).extents_num_delta--;
- root_dirty = true;
+
+ root_block = c.cache.duplicate_for_write(
+ c.trans, root_block
+ )->template cast<RootBlock>();
+ get_root().set_location(
+ node_iter->get_val().maybe_relative_to(pos.node->get_paddr()));
+ get_root().set_depth(iter.get_depth());
+ if (iter.get_depth() > 1) {
+ auto root_node = iter.get_internal(iter.get_depth()).node;
+ set_root_node(root_node);
+ } else {
+ set_root_node(iter.leaf.node);
+ }
} else {
SUBTRACET(seastore_fixedkv_tree, "no need to collapse root", c.trans);
}
pin_t,
node_size>> : std::true_type {};
-template <typename T>
-phy_tree_root_t& get_phy_tree_root(root_t& r);
-
template <
typename tree_type_t,
typename node_key_t,
Cache &cache,
op_context_t<node_key_t> c,
F &&f) {
- using base_ertr = crimson::errorator<
- crimson::ct_error::input_output_error>;
- using base_iertr = trans_iertr<base_ertr>;
return cache.get_root(
c.trans
- ).si_then([c, f=std::forward<F>(f), &cache](RootBlockRef croot) mutable {
+ ).si_then([f=std::forward<F>(f)](RootBlockRef croot) mutable {
return seastar::do_with(
- tree_type_t(get_phy_tree_root<tree_type_t>(croot->get_root())),
- [c, croot, f=std::move(f), &cache](auto &btree) mutable {
- return f(
- btree
- ).si_then([c, croot, &btree, &cache] {
- if (btree.is_root_dirty()) {
- auto mut_croot = cache.duplicate_for_write(
- c.trans, croot
- )->template cast<RootBlock>();
- get_phy_tree_root<tree_type_t>(mut_croot->get_root()) =
- btree.get_root_undirty();
- }
- return base_iertr::now();
- });
+ tree_type_t(croot),
+ [f=std::move(f)](auto &btree) mutable {
+ return f(btree);
});
});
}
#include "crimson/os/seastore/btree/btree_range_pin.h"
#include "crimson/os/seastore/btree/fixed_kv_btree.h"
+#include "crimson/os/seastore/root_block.h"
namespace crimson::os::seastore {
uint16_t capacity = 0;
parent_tracker_t* my_tracker = nullptr;
parent_tracker_ref parent_tracker;
+ RootBlockRef root_block;
FixedKVNode(uint16_t capacity, ceph::bufferptr &&ptr)
: CachedExtent(std::move(ptr)),
}
void set_parent_tracker_from_prior_instance() {
+ assert(is_mutation_pending());
+ auto &prior = (FixedKVNode&)(*get_prior_instance());
if (pin.is_root()) {
+ ceph_assert(prior.root_block);
+ ceph_assert(pending_for_transaction);
+ root_block = prior.root_block;
+ link_phy_tree_root_node(root_block, this);
return;
}
- assert(is_mutation_pending());
- auto &prior = (FixedKVNode&)(*get_prior_instance());
+ ceph_assert(!root_block);
parent_tracker = prior.parent_tracker;
auto &parent = parent_tracker->parent;
assert(parent);
}
virtual ~FixedKVInternalNode() {
- if (!this->pin.is_root()
- && this->is_valid()
- && !this->is_pending()) {
- ceph_assert(this->parent_tracker);
- auto &parent = this->parent_tracker->parent;
- ceph_assert(parent);
- auto off = parent->lower_bound_offset(this->get_meta().begin);
- assert(parent->get_key_from_idx(off) == get_node_meta().begin);
- assert(parent->children[off] == this);
- parent->children[off] = nullptr;
+ if (this->is_valid() && !this->is_pending()) {
+ if (this->pin.is_root()) {
+ ceph_assert(this->root_block);
+ unlink_phy_tree_root_node<NODE_KEY>(this->root_block);
+ } else {
+ ceph_assert(this->parent_tracker);
+ auto &parent = this->parent_tracker->parent;
+ ceph_assert(parent);
+ auto off = parent->lower_bound_offset(this->get_meta().begin);
+ assert(parent->get_key_from_idx(off) == this->get_meta().begin);
+ assert(parent->children[off] == this);
+ parent->children[off] = nullptr;
+ }
}
}
if (this->my_tracker) {
out << ", my_tracker->parent=" << (void*)this->my_tracker->parent.get();
}
- return out;
+ return out << ", root_block=" << (void*)this->root_block.get();
}
ceph::bufferlist get_delta() {
}
virtual ~FixedKVLeafNode() {
- if (!this->pin.is_root()
- && this->is_valid()
- && !this->is_pending()) {
- ceph_assert(this->parent_tracker);
- auto &parent = this->parent_tracker->parent;
- ceph_assert(parent);
- auto off = parent->lower_bound_offset(this->get_meta().begin);
- assert(parent->get_key_from_idx(off) == get_node_meta().begin);
- assert(parent->children[off] == this);
- parent->children[off] = nullptr;
+ if (this->is_valid() && !this->is_pending()) {
+ if (this->pin.is_root()) {
+ ceph_assert(this->root_block);
+ unlink_phy_tree_root_node<NODE_KEY>(this->root_block);
+ } else {
+ ceph_assert(this->parent_tracker);
+ auto &parent = this->parent_tracker->parent;
+ ceph_assert(parent);
+ auto off = parent->lower_bound_offset(this->get_meta().begin);
+ assert(parent->get_key_from_idx(off) == this->get_meta().begin);
+ assert(parent->children[off] == this);
+ parent->children[off] = nullptr;
+ }
}
}
return r.lba_root;
}
+template <>
+const get_phy_tree_root_node_ret get_phy_tree_root_node<
+ crimson::os::seastore::lba_manager::btree::LBABtree>(
+ const RootBlockRef &root_block, op_context_t<laddr_t> c)
+{
+ auto lba_root = root_block->lba_root_node;
+ if (lba_root) {
+ ceph_assert(lba_root->is_initial_pending()
+ == root_block->is_pending());
+ return {true,
+ trans_intr::make_interruptible(
+ c.cache.get_extent_viewable_by_trans(c.trans, lba_root))};
+ } else if (root_block->is_pending()) {
+ auto &prior = static_cast<RootBlock&>(*root_block->get_prior_instance());
+ lba_root = prior.lba_root_node;
+ if (lba_root) {
+ return {true,
+ trans_intr::make_interruptible(
+ c.cache.get_extent_viewable_by_trans(c.trans, lba_root))};
+ } else {
+ return {false,
+ trans_intr::make_interruptible(
+ seastar::make_ready_future<
+ CachedExtentRef>(CachedExtentRef()))};
+ }
+ } else {
+ return {false,
+ trans_intr::make_interruptible(
+ seastar::make_ready_future<
+ CachedExtentRef>(CachedExtentRef()))};
+ }
+}
+
+template <typename ROOT>
+void link_phy_tree_root_node(RootBlockRef &root_block, ROOT* lba_root) {
+ root_block->lba_root_node = lba_root;
+ ceph_assert(lba_root != nullptr);
+ lba_root->root_block = root_block;
+}
+
+template void link_phy_tree_root_node(
+ RootBlockRef &root_block, lba_manager::btree::LBAInternalNode* lba_root);
+template void link_phy_tree_root_node(
+ RootBlockRef &root_block, lba_manager::btree::LBALeafNode* lba_root);
+template void link_phy_tree_root_node(
+ RootBlockRef &root_block, lba_manager::btree::LBANode* lba_root);
+
+template <>
+void unlink_phy_tree_root_node<laddr_t>(RootBlockRef &root_block) {
+ root_block->lba_root_node = nullptr;
+}
+
}
namespace crimson::os::seastore::lba_manager::btree {
LOG_PREFIX(BtreeLBAManager::mkfs);
INFOT("start", t);
return cache.get_root(t).si_then([this, &t](auto croot) {
- croot->get_root().lba_root = LBABtree::mkfs(get_context(t));
+ assert(croot->is_mutation_pending());
+ croot->get_root().lba_root = LBABtree::mkfs(croot, get_context(t));
return mkfs_iertr::now();
}).handle_error_interruptible(
mkfs_iertr::pass_further{},
if (!iter.is_end() &&
iter.get_key() == logn->get_laddr() &&
iter.get_val().paddr == logn->get_paddr()) {
+ assert(!iter.get_leaf_node()->is_pending());
+ iter.get_leaf_node()->link_child(logn.get(), iter.get_leaf_pos());
logn->set_pin(iter.get_pin());
ceph_assert(iter.get_val().len == e->get_length());
if (c.pins) {