virtual const onode_layout_t &get_layout() const = 0;
virtual onode_layout_t &get_mutable_layout(Transaction &t) = 0;
virtual ~Onode() = default;
+ virtual laddr_t get_hint() const = 0;
};
status = status_t::DELETED;
}
+ laddr_t get_hint() const final {
+ return Value::get_hint();
+ }
~FLTreeOnode() final {}
};
eagain_ifuture<> Node::mkfs(context_t c, RootNodeTracker& root_tracker)
{
LOG_PREFIX(OTree::Node::mkfs);
- return LeafNode::allocate_root(c, root_tracker
+ return LeafNode::allocate_root(c, L_ADDR_MIN, root_tracker
).si_then([c, FNAME](auto ret) {
INFOT("allocated root {}", c.t, ret->get_name());
});
return ret;
}
-eagain_ifuture<> Node::upgrade_root(context_t c)
+eagain_ifuture<> Node::upgrade_root(context_t c, laddr_t hint)
{
LOG_PREFIX(OTree::Node::upgrade_root);
assert(impl->field_type() == field_type_t::N0);
auto super_to_move = deref_super();
return InternalNode::allocate_root(
- c, impl->level(), impl->laddr(), std::move(super_to_move)
+ c, hint, impl->level(), impl->laddr(), std::move(super_to_move)
).si_then([this, c, FNAME](auto new_root) {
as_child(search_position_t::end(), new_root);
INFOT("upgraded from {} to {}",
// so use rebuild_extent() as a workaround to rebuild the node from a
// fresh extent, thus no need to generate delta.
auto left_addr = left_for_merge->impl->laddr();
- return left_for_merge->rebuild_extent(c
+ return left_for_merge->rebuild_extent(c, L_ADDR_MIN
).si_then([c, update_index_after_merge,
left_addr,
merge_stage = merge_stage,
});
}
-eagain_ifuture<NodeExtentMutable> Node::rebuild_extent(context_t c)
+eagain_ifuture<NodeExtentMutable> Node::rebuild_extent(context_t c, laddr_t hint)
{
LOG_PREFIX(OTree::Node::rebuild_extent);
DEBUGT("{} ...", c.t, get_name());
// note: laddr can be changed after rebuild, but we don't fix the parent
// mapping as it is part of the merge process.
- return impl->rebuild_extent(c);
+ return impl->rebuild_extent(c, hint);
}
eagain_ifuture<> Node::retire(context_t c, Ref<Node>&& this_ref)
}
eagain_ifuture<Ref<InternalNode>> InternalNode::allocate_root(
- context_t c, level_t old_root_level,
+ context_t c, laddr_t hint, level_t old_root_level,
laddr_t old_root_addr, Super::URef&& super)
{
// support tree height up to 256
ceph_assert(old_root_level < MAX_LEVEL);
- return InternalNode::allocate(c, field_type_t::N0, true, old_root_level + 1
+ return InternalNode::allocate(c, hint, field_type_t::N0, true, old_root_level + 1
).si_then([c, old_root_addr,
super = std::move(super)](auto fresh_node) mutable {
auto root = fresh_node.node;
assert(impl->is_level_tail());
assert(impl->field_type() == field_type_t::N0);
Ref<const Node> this_ref = this;
- return InternalNode::allocate(c_other, field_type_t::N0, true, impl->level()
+ return InternalNode::allocate(c_other, L_ADDR_MIN, field_type_t::N0, true, impl->level()
).si_then([this, c_other, &tracker_other](auto fresh_other) {
impl->test_copy_to(fresh_other.mut);
auto cloned_root = fresh_other.node;
// proceed to split with insert
// assume I'm already ref-counted by caller
- return (is_root() ? upgrade_root(c) : eagain_iertr::now()
- ).si_then([this, c] {
+ auto hint = insert_key.get_hint();
+ return (is_root() ? upgrade_root(c, hint) : eagain_iertr::now()
+ ).si_then([this, c, hint] {
return InternalNode::allocate(
- c, impl->field_type(), impl->is_level_tail(), impl->level());
+ c, hint, impl->field_type(), impl->is_level_tail(), impl->level());
}).si_then([this, insert_key, insert_child, insert_pos,
insert_stage=insert_stage, insert_size=insert_size,
outdated_child, c, FNAME](auto fresh_right) mutable {
}
eagain_ifuture<InternalNode::fresh_node_t> InternalNode::allocate(
- context_t c, field_type_t field_type, bool is_level_tail, level_t level)
+ context_t c, laddr_t hint, field_type_t field_type, bool is_level_tail, level_t level)
{
- return InternalNodeImpl::allocate(c, field_type, is_level_tail, level
+ return InternalNodeImpl::allocate(c, hint, field_type, is_level_tail, level
).si_then([](auto&& fresh_impl) {
auto node = Ref<InternalNode>(new InternalNode(
fresh_impl.impl.get(), std::move(fresh_impl.impl)));
assert(impl->is_level_tail());
assert(impl->field_type() == field_type_t::N0);
Ref<const Node> this_ref = this;
- return LeafNode::allocate(c_other, field_type_t::N0, true
+ return LeafNode::allocate(c_other, L_ADDR_MIN, field_type_t::N0, true
).si_then([this, c_other, &tracker_other](auto fresh_other) {
impl->test_copy_to(fresh_other.mut);
auto cloned_root = fresh_other.node;
}
// split and insert
Ref<Node> this_ref = this;
- return (is_root() ? upgrade_root(c) : eagain_iertr::now()
- ).si_then([this, c] {
- return LeafNode::allocate(c, impl->field_type(), impl->is_level_tail());
+ auto hint = key.get_hint();
+ return (is_root() ? upgrade_root(c, hint) : eagain_iertr::now()
+ ).si_then([this, c, hint] {
+ return LeafNode::allocate(c, hint, impl->field_type(), impl->is_level_tail());
}).si_then([this_ref = std::move(this_ref), this, c, &key, vconf, FNAME,
insert_pos, insert_stage=insert_stage, insert_size=insert_size](auto fresh_right) mutable {
auto right_node = fresh_right.node;
}
eagain_ifuture<Ref<LeafNode>> LeafNode::allocate_root(
- context_t c, RootNodeTracker& root_tracker)
+ context_t c, laddr_t hint, RootNodeTracker& root_tracker)
{
LOG_PREFIX(OTree::LeafNode::allocate_root);
- return LeafNode::allocate(c, field_type_t::N0, true
+ return LeafNode::allocate(c, hint, field_type_t::N0, true
).si_then([c, &root_tracker, FNAME](auto fresh_node) {
auto root = fresh_node.node;
return c.nm.get_super(c.t, root_tracker
}
eagain_ifuture<LeafNode::fresh_node_t> LeafNode::allocate(
- context_t c, field_type_t field_type, bool is_level_tail)
+ context_t c, laddr_t hint, field_type_t field_type, bool is_level_tail)
{
- return LeafNodeImpl::allocate(c, field_type, is_level_tail
+ return LeafNodeImpl::allocate(c, hint, field_type, is_level_tail
).si_then([](auto&& fresh_impl) {
auto node = Ref<LeafNode>(new LeafNode(
fresh_impl.impl.get(), std::move(fresh_impl.impl)));
make_root(c, std::move(_super));
}
void as_root(Super::URef&& _super);
- eagain_ifuture<> upgrade_root(context_t);
+ eagain_ifuture<> upgrade_root(context_t, laddr_t);
Super::URef deref_super();
eagain_ifuture<> erase_node(context_t, Ref<Node>&&);
template <bool FORCE_MERGE = false>
eagain_ifuture<> fix_parent_index(context_t, Ref<Node>&&, bool);
- eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t);
+ eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t, laddr_t);
eagain_ifuture<> retire(context_t, Ref<Node>&&);
void make_tail(context_t);
void track_make_tail(const search_position_t&);
static eagain_ifuture<Ref<InternalNode>> allocate_root(
- context_t, level_t, laddr_t, Super::URef&&);
+ context_t, laddr_t, level_t, laddr_t, Super::URef&&);
protected:
eagain_ifuture<Ref<tree_cursor_t>> lookup_smallest(context_t) override;
return std::make_pair(Ref<Node>(node), mut);
}
};
- static eagain_ifuture<fresh_node_t> allocate(context_t, field_type_t, bool, level_t);
+ static eagain_ifuture<fresh_node_t> allocate(context_t, laddr_t, field_type_t, bool, level_t);
private:
/**
context_t, const key_hobj_t&, value_config_t,
const search_position_t&, const MatchHistory&,
match_stat_t mstat);
- static eagain_ifuture<Ref<LeafNode>> allocate_root(context_t, RootNodeTracker&);
+ static eagain_ifuture<Ref<LeafNode>> allocate_root(context_t, laddr_t, RootNodeTracker&);
friend class Node;
private:
return std::make_pair(Ref<Node>(node), mut);
}
};
- static eagain_ifuture<fresh_node_t> allocate(context_t, field_type_t, bool);
+ static eagain_ifuture<fresh_node_t> allocate(context_t, laddr_t, field_type_t, bool);
private:
/**
std::memcpy(to.get_write(), extent->get_read(), get_length());
}
- eagain_ifuture<NodeExtentMutable> rebuild(context_t c) {
+ eagain_ifuture<NodeExtentMutable> rebuild(context_t c, laddr_t hint) {
LOG_PREFIX(OTree::Extent::rebuild);
assert(!is_retired());
if (state == nextent_state_t::FRESH) {
}
assert(!extent->is_initial_pending());
auto alloc_size = get_length();
- return c.nm.alloc_extent(c.t, alloc_size
+ return c.nm.alloc_extent(c.t, hint, alloc_size
).handle_error_interruptible(
eagain_iertr::pass_further{},
crimson::ct_error::input_output_error::handle(
using alloc_iertr = base_iertr;
virtual alloc_iertr::future<NodeExtentRef> alloc_extent(
- Transaction&, extent_len_t) = 0;
+ Transaction&, laddr_t hint, extent_len_t) = 0;
using retire_iertr = base_iertr::extend<
crimson::ct_error::enoent>;
}
alloc_iertr::future<NodeExtentRef> alloc_extent(
- Transaction& t, extent_len_t len) override {
+ Transaction& t, laddr_t hint, extent_len_t len) override {
TRACET("allocating {}B ...", t, len);
if constexpr (SYNC) {
return alloc_extent_sync(t, len);
}
alloc_iertr::future<NodeExtentRef> alloc_extent(
- Transaction& t, extent_len_t len) override {
+ Transaction& t, laddr_t hint, extent_len_t len) override {
TRACET("allocating {}B ...", t, len);
if constexpr (INJECT_EAGAIN) {
if (trigger_eagain()) {
return alloc_iertr::make_ready_future<NodeExtentRef>();
}
}
- return tm.alloc_extent<SeastoreNodeExtent>(t, addr_min, len
+ return tm.alloc_extent<SeastoreNodeExtent>(t, hint, len
).si_then([len, &t](auto extent) {
DEBUGT("allocated {}B at {:#x} -- {}",
t, extent->get_length(), extent->get_laddr(), *extent);
// XXX: branchless allocation
eagain_ifuture<InternalNodeImpl::fresh_impl_t>
InternalNodeImpl::allocate(
- context_t c, field_type_t type, bool is_level_tail, level_t level)
+ context_t c, laddr_t hint, field_type_t type, bool is_level_tail, level_t level)
{
if (type == field_type_t::N0) {
- return InternalNode0::allocate(c, is_level_tail, level);
+ return InternalNode0::allocate(c, hint, is_level_tail, level);
} else if (type == field_type_t::N1) {
- return InternalNode1::allocate(c, is_level_tail, level);
+ return InternalNode1::allocate(c, hint, is_level_tail, level);
} else if (type == field_type_t::N2) {
- return InternalNode2::allocate(c, is_level_tail, level);
+ return InternalNode2::allocate(c, hint, is_level_tail, level);
} else if (type == field_type_t::N3) {
- return InternalNode3::allocate(c, is_level_tail, level);
+ return InternalNode3::allocate(c, hint, is_level_tail, level);
} else {
ceph_abort("impossible path");
}
eagain_ifuture<LeafNodeImpl::fresh_impl_t>
LeafNodeImpl::allocate(
- context_t c, field_type_t type, bool is_level_tail)
+ context_t c, laddr_t hint, field_type_t type, bool is_level_tail)
{
if (type == field_type_t::N0) {
- return LeafNode0::allocate(c, is_level_tail, 0);
+ return LeafNode0::allocate(c, hint, is_level_tail, 0);
} else if (type == field_type_t::N1) {
- return LeafNode1::allocate(c, is_level_tail, 0);
+ return LeafNode1::allocate(c, hint, is_level_tail, 0);
} else if (type == field_type_t::N2) {
- return LeafNode2::allocate(c, is_level_tail, 0);
+ return LeafNode2::allocate(c, hint, is_level_tail, 0);
} else if (type == field_type_t::N3) {
- return LeafNode3::allocate(c, is_level_tail, 0);
+ return LeafNode3::allocate(c, hint, is_level_tail, 0);
} else {
ceph_abort("impossible path");
}
virtual std::tuple<match_stage_t, search_position_t> erase(const search_position_t&) = 0;
virtual std::tuple<match_stage_t, std::size_t> evaluate_merge(NodeImpl&) = 0;
virtual search_position_t merge(NodeExtentMutable&, NodeImpl&, match_stage_t, extent_len_t) = 0;
- virtual eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t) = 0;
+ virtual eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t, laddr_t) = 0;
virtual eagain_ifuture<> retire_extent(context_t) = 0;
virtual search_position_t make_tail() = 0;
return {std::move(impl), mut};
}
};
- static eagain_ifuture<fresh_impl_t> allocate(context_t, field_type_t, bool, level_t);
+ static eagain_ifuture<fresh_impl_t> allocate(context_t, laddr_t, field_type_t, bool, level_t);
static InternalNodeImplURef load(NodeExtentRef, field_type_t);
return {std::move(impl), mut};
}
};
- static eagain_ifuture<fresh_impl_t> allocate(context_t, field_type_t, bool);
+ static eagain_ifuture<fresh_impl_t> allocate(context_t, laddr_t, field_type_t, bool);
static LeafNodeImplURef load(NodeExtentRef, field_type_t);
}
static eagain_ifuture<typename parent_t::fresh_impl_t> allocate(
- context_t c, bool is_level_tail, level_t level) {
+ context_t c, laddr_t hint, bool is_level_tail, level_t level) {
LOG_PREFIX(OTree::Layout::allocate);
extent_len_t extent_size;
if constexpr (NODE_TYPE == node_type_t::LEAF) {
} else {
extent_size = c.vb.get_internal_node_size();
}
- return c.nm.alloc_extent(c.t, extent_size
+ return c.nm.alloc_extent(c.t, hint, extent_size
).handle_error_interruptible(
eagain_iertr::pass_further{},
crimson::ct_error::input_output_error::handle(
}
eagain_ifuture<NodeExtentMutable>
- rebuild_extent(context_t c) override {
- return extent.rebuild(c).si_then([this] (auto mut) {
+ rebuild_extent(context_t c, laddr_t hint) override {
+ return extent.rebuild(c, hint).si_then([this] (auto mut) {
// addr may change
build_name();
return mut;
template <KeyT type>
using full_key_t = typename _full_key_type<type>::type;
+static laddr_t get_lba_hint(shard_t shard, pool_t pool, crush_hash_t crush)
+{
+ if (shard == shard_id_t::NO_SHARD) {
+ return (uint64_t)(pool & 0xFF)<<56 | (uint64_t)(crush)<<24;
+ } else {
+ return (uint64_t)(shard & 0X7F)<<56 | (uint64_t)(pool& 0xFF)<<48 |
+ (uint64_t)(crush)<<16;
+ }
+}
+
struct node_offset_packed_t {
node_offset_t value;
} __attribute__((packed));
crush_hash_t crush() const {
return ghobj.hobj.get_hash();
}
+ laddr_t get_hint() const {
+ return get_lba_hint(shard(), pool(), crush());
+ }
std::string_view nspace() const {
// TODO(cross-node string dedup)
return ghobj.hobj.nspace;
crush_hash_t crush() const {
return crush_packed().crush;
}
+ laddr_t get_hint() const {
+ return get_lba_hint(shard(), pool(), crush());
+ }
std::string_view nspace() const {
// TODO(cross-node string dedup)
return ns_oid_view().nspace.to_string_view();
return p_cursor->prepare_mutate_value_payload(get_context(t));
}
+laddr_t Value::get_hint() const
+{
+ return p_cursor->get_key_view(vb.get_header_magic()).get_hint();
+}
+
std::unique_ptr<ValueDeltaRecorder>
build_value_recorder_by_type(ceph::bufferlist& encoded,
const value_magic_t& magic)
return read_value_header()->payload_size;
}
+ laddr_t get_hint() const;
+
bool operator==(const Value& v) const { return p_cursor == v.p_cursor; }
bool operator!=(const Value& v) const { return !(*this == v); }
private:
const value_header_t* read_value_header() const;
- context_t get_context(Transaction& t) { return {nm, vb, t}; }
+ context_t get_context(Transaction& t) {
+ return {nm, vb, t};
+ }
std::pair<NodeExtentMutable&, ValueDeltaRecorder*>
do_prepare_mutate_payload(Transaction&);