search_position_t merge(NodeExtentMutable& mut, NodeImpl& _right_node,
match_stage_t merge_stage, node_offset_t merge_size) override {
- // TODO
- ceph_abort("not implemented");
+ assert(NODE_TYPE == _right_node.node_type());
+ assert(FIELD_TYPE == _right_node.field_type());
+ auto& right_node = dynamic_cast<NodeLayoutT&>(_right_node);
+ if (unlikely(logger().is_enabled(seastar::log_level::debug))) {
+ {
+ std::ostringstream sos;
+ dump(sos);
+ logger().debug("OTree::Layout::Merge: -- left node dump\n{}", sos.str());
+ }
+ {
+ std::ostringstream sos;
+ right_node.dump(sos);
+ logger().debug("OTree::Layout::Merge: -- right node dump\n{}", sos.str());
+ }
+ }
+
+ assert(!is_level_tail());
+ assert(!is_keys_empty());
+ auto& left_node_stage = extent.read();
+ position_t left_last_pos;
+ STAGE_T::template get_largest_slot<true, false, false>(
+ left_node_stage, &left_last_pos, nullptr, nullptr);
+
+ typename STAGE_T::template StagedAppender<KeyT::VIEW> left_appender;
+ left_appender.init_tail(&mut, left_node_stage, merge_stage);
+
+ assert(!right_node.is_keys_empty());
+ auto& right_node_stage = right_node.extent.read();
+ typename STAGE_T::StagedIterator right_append_at;
+ right_append_at.set(right_node_stage);
+
+ auto pos_end = position_t::end();
+ STAGE_T::template append_until<KeyT::VIEW>(
+ right_append_at, left_appender, pos_end, STAGE);
+ assert(right_append_at.is_end());
+ left_appender.wrap();
+
+ if (right_node.is_level_tail()) {
+ node_stage_t::update_is_level_tail(mut, left_node_stage, true);
+ build_name();
+ }
+
+ if (unlikely(logger().is_enabled(seastar::log_level::debug))) {
+ std::ostringstream sos;
+ dump(sos);
+ logger().debug("OTree::Layout::Merge: -- merged node dump\n{}", sos.str());
+ }
+ assert(merge_size == filled_size());
+ return normalize(std::move(left_last_pos));
}
ertr::future<NodeExtentMutable>
auto append_at = split_at;
// TODO(cross-node string dedup)
typename STAGE_T::template StagedAppender<KEY_TYPE> right_appender;
- right_appender.init(&right_mut, right_mut.get_write());
+ right_appender.init_empty(&right_mut, right_mut.get_write());
const value_t* p_value = nullptr;
if (!is_insert_left) {
// right node: append [start(append_at), insert_pos)
NodeExtentMutable& mut,
const node_stage_t& node_stage) {
assert(!node_stage.is_level_tail());
- // TODO
- ceph_abort("not implemented");
+ if constexpr (NODE_TYPE == node_type_t::INTERNAL) {
+ auto [r_stage, r_last_pos] = update_last_to_tail(mut, node_stage);
+ std::ignore = r_stage;
+ return r_last_pos;
+ } else {
+ node_stage_t::update_is_level_tail(mut, node_stage, true);
+ // no need to calculate the last pos
+ return position_t::end();
+ }
}
private:
#define APPEND_T ITER_T::Appender<KT>
+template <node_type_t NODE_TYPE>
+template <KeyT KT>
+APPEND_T::Appender(NodeExtentMutable* p_mut,
+ const item_iterator_t& iter,
+ bool open) : p_mut{p_mut}
+{
+ assert(!iter.has_next());
+ if (open) {
+ p_append = const_cast<char*>(iter.get_key().p_start());
+ p_offset_while_open = const_cast<char*>(iter.item_range.p_end);
+ } else {
+ // XXX: this doesn't need to advance the iter to last
+ p_append = const_cast<char*>(iter.p_items_start);
+ }
+}
+
template <node_type_t NODE_TYPE>
template <KeyT KT>
bool APPEND_T::append(const ITER_T& src, index_t& items)
public:
Appender(NodeExtentMutable* p_mut, char* p_append)
: p_mut{p_mut}, p_append{p_append} {}
+ Appender(NodeExtentMutable*, const item_iterator_t&, bool open);
bool append(const item_iterator_t<NODE_TYPE>& src, index_t& items);
char* wrap() { return p_append; }
std::tuple<NodeExtentMutable*, char*> open_nxt(const key_get_type&);
#define APPEND_T node_extent_t<FieldType, NODE_TYPE>::Appender<KT>
+template <typename FieldType, node_type_t NODE_TYPE>
+template <KeyT KT>
+APPEND_T::Appender(NodeExtentMutable* p_mut, const node_extent_t& node, bool open)
+ : p_mut{p_mut}, p_start{p_mut->get_write()}
+{
+ assert(p_start == node.p_start());
+ assert(node.keys());
+ if (open) {
+ // seek as open_nxt()
+ if constexpr (FIELD_TYPE == field_type_t::N0 ||
+ FIELD_TYPE == field_type_t::N1) {
+ p_append_left = p_start + node.fields().get_key_start_offset(node.keys() - 1);
+ p_append_left += sizeof(typename FieldType::key_t);
+ p_append_right = p_start + node.fields().get_item_end_offset(node.keys() - 1);
+ } else if constexpr (FIELD_TYPE == field_type_t::N2) {
+ ceph_abort("not implemented");
+ } else {
+ ceph_abort("impossible path");
+ }
+ num_keys = node.keys() - 1;
+ } else {
+ if constexpr (std::is_same_v<FieldType, internal_fields_3_t>) {
+ ceph_abort("not implemented");
+ } else {
+ p_append_left = p_start + node.fields().get_key_start_offset(node.keys());
+ p_append_right = p_start + node.fields().get_item_end_offset(node.keys());
+ }
+ num_keys = node.keys();
+ }
+}
+
template <typename FieldType, node_type_t NODE_TYPE>
template <KeyT KT>
void APPEND_T::append(const node_extent_t& src, index_t from, index_t items)
assert(from + items <= src.keys());
num_keys += items;
if constexpr (std::is_same_v<FieldType, internal_fields_3_t>) {
- ceph_abort("impossible path");
+ ceph_abort("not implemented");
} else {
// append left part forwards
node_offset_t offset_left_start = src.fields().get_key_start_offset(from);
p_append_left = p_start + FieldType::HEADER_SIZE;
p_append_right = p_start + FieldType::SIZE;
}
+ Appender(NodeExtentMutable*, const node_extent_t&, bool open = false);
void append(const node_extent_t& src, index_t from, index_t items);
void append(const full_key_t<KT>&, const value_input_t&, const value_t*&);
char* wrap();
return container_t::erase_at(mut, container, _index, p_left_bound);
}
+ template <KeyT KT>
+ typename container_t::template Appender<KT>
+ get_appender(NodeExtentMutable* p_mut) {
+ assert(_index + 1 == container.keys());
+ return typename container_t::template Appender<KT>(p_mut, container);
+ }
+
+ template <KeyT KT>
+ typename container_t::template Appender<KT>
+ get_appender_opened(NodeExtentMutable* p_mut) {
+ if constexpr (!IS_BOTTOM) {
+ assert(_index + 1 == container.keys());
+ return typename container_t::template Appender<KT>(p_mut, container, true);
+ } else {
+ ceph_abort("impossible path");
+ }
+ }
+
void encode(const char* p_node_start, ceph::bufferlist& encoded) const {
container.encode(p_node_start, encoded);
ceph::encode(_index, encoded);
return container_t::erase(mut, container, p_left_bound);
}
+ template <KeyT KT>
+ typename container_t::template Appender<KT>
+ get_appender(NodeExtentMutable* p_mut) {
+ return typename container_t::template Appender<KT>(p_mut, container, false);
+ }
+
+ template <KeyT KT>
+ typename container_t::template Appender<KT>
+ get_appender_opened(NodeExtentMutable* p_mut) {
+ if constexpr (!IS_BOTTOM) {
+ return typename container_t::template Appender<KT>(p_mut, container, true);
+ } else {
+ ceph_abort("impossible path");
+ }
+ }
+
void encode(const char* p_node_start, ceph::bufferlist& encoded) const {
container.encode(p_node_start, encoded);
uint8_t is_end = _is_end;
* (!IS_BOTTOM) trim_at(mut, trimmed) -> trim_size
* erase:
* erase(mut, p_left_bound) -> erase_size
+ * merge:
+ * get_appender(p_mut) -> Appender
+ * (!IS_BOTTOM)get_appender_opened(p_mut) -> Appender
* denc:
* encode(p_node_start, encoded)
* decode(p_node_start, delta) -> iterator_t
char* p_insert = const_cast<char*>(range.p_end);
const value_t* p_value = nullptr;
StagedAppender<KT> appender;
- appender.init(&mut, p_insert);
+ appender.init_empty(&mut, p_insert);
appender.append(key, value, p_value);
[[maybe_unused]] const char* p_insert_front = appender.wrap();
assert(p_insert_front == range.p_start);
bool is_end() const { return iter->is_end(); }
bool in_progress() const {
assert(valid());
+ assert(!is_end());
if constexpr (!IS_BOTTOM) {
if (this->_nxt.valid()) {
if (this->_nxt.index() == 0) {
}
bool in_progress() const { return require_wrap_nxt; }
// TODO: pass by reference
- void init(NodeExtentMutable* p_mut, char* p_start) {
+ void init_empty(NodeExtentMutable* p_mut, char* p_start) {
assert(!valid());
appender = typename container_t::template Appender<KT>(p_mut, p_start);
_index = 0;
}
+ void init_tail(NodeExtentMutable* p_mut,
+ const container_t& container,
+ match_stage_t stage) {
+ assert(!valid());
+ auto iter = iterator_t(container);
+ iter.seek_last();
+ if (stage == STAGE) {
+ appender = iter.template get_appender<KT>(p_mut);
+ _index = iter.index() + 1;
+ if constexpr (!IS_BOTTOM) {
+ assert(!this->_nxt.valid());
+ }
+ } else {
+ assert(stage < STAGE);
+ if constexpr (!IS_BOTTOM) {
+ appender = iter.template get_appender_opened<KT>(p_mut);
+ _index = iter.index();
+ require_wrap_nxt = true;
+ auto nxt_container = iter.get_nxt_container();
+ this->_nxt.init_tail(p_mut, nxt_container, stage);
+ } else {
+ ceph_abort("impossible path");
+ }
+ }
+ }
// possible to make src_iter end if to_index == INDEX_END
void append_until(StagedIterator& src_iter, index_t& to_index) {
assert(!require_wrap_nxt);
if constexpr (!IS_BOTTOM) {
require_wrap_nxt = true;
auto [p_mut, p_append] = appender->open_nxt(paritial_key);
- this->_nxt.init(p_mut, p_append);
+ this->_nxt.init_empty(p_mut, p_append);
return this->_nxt;
} else {
ceph_abort("impossible path");
if constexpr (!IS_BOTTOM) {
require_wrap_nxt = true;
auto [p_mut, p_append] = appender->open_nxt(key);
- this->_nxt.init(p_mut, p_append);
+ this->_nxt.init_empty(p_mut, p_append);
return this->_nxt;
} else {
ceph_abort("impossible path");
// cannot append the current item as-a-whole
index_t to_index_nxt = INDEX_END;
NXT_STAGE_T::template _append_range<KT>(
- src_iter.nxt(), appender.open_nxt(src_iter.get_key()), to_index_nxt);
+ src_iter.get_nxt(), appender.open_nxt(src_iter.get_key()), to_index_nxt);
++src_iter;
appender.wrap_nxt();
} else {
static std::tuple<match_stage_t, node_offset_t> evaluate_merge(
const full_key_t<KeyT::VIEW>& left_pivot_index,
const container_t& right_container) {
- // TODO
- ceph_abort("not implemented");
+ auto r_iter = iterator_t(right_container);
+ r_iter.seek_at(0);
+ node_offset_t compensate = r_iter.header_size();
+ auto cmp = compare_to<KeyT::VIEW>(left_pivot_index, r_iter.get_key());
+ if (cmp == MatchKindCMP::EQ) {
+ if constexpr (!IS_BOTTOM) {
+ // the index is equal, compensate and look at the lower stage
+ compensate += r_iter.size_to_nxt();
+ auto r_nxt_container = r_iter.get_nxt_container();
+ auto [ret_stage, ret_compensate] = NXT_STAGE_T::evaluate_merge(
+ left_pivot_index, r_nxt_container);
+ compensate += ret_compensate;
+ return {ret_stage, compensate};
+ } else {
+ ceph_abort("impossible path: left_pivot_key == right_first_key");
+ }
+ } else if (cmp == MatchKindCMP::LT) {
+ // ok, do merge here
+ return {STAGE, compensate};
+ } else {
+ ceph_abort("impossible path: left_pivot_key < right_first_key");
+ }
}
};
// explicit deduction guide
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
+template <KeyT KT>
+void leaf_sub_items_t::Appender<KT>::append(
+ const leaf_sub_items_t& src, index_t from, index_t items)
+{
+ if (p_append) {
+ // append from empty
+ assert(cnt <= APPENDER_LIMIT);
+ assert(from <= src.keys());
+ if (items == 0) {
+ return;
+ }
+ if (op_src) {
+ assert(*op_src == src);
+ } else {
+ op_src = src;
+ }
+ assert(from < src.keys());
+ assert(from + items <= src.keys());
+ appends[cnt] = range_items_t{from, items};
+ ++cnt;
+ } else {
+ // append from existing
+ assert(op_dst.has_value());
+ assert(!p_appended);
+ assert(from == 0);
+ assert(items);
+ assert(items == src.keys());
+
+ num_keys_t num_keys = op_dst->keys();
+ node_offset_t compensate = op_dst->get_offset(num_keys - 1).value;
+ const char* p_items_start = op_dst->p_start();
+ const char* p_items_end = op_dst->p_items_end;
+
+ // update dst num_keys
+ num_keys += items;
+ p_mut->copy_in_absolute((char*)op_dst->p_num_keys, num_keys);
+
+ // shift dst items
+ std::size_t src_offsets_size = sizeof(node_offset_t) * items;
+ p_mut->shift_absolute(p_items_start,
+ p_items_end - p_items_start,
+ -(int)src_offsets_size);
+
+ // fill offsets from src
+ node_offset_t offset;
+ char* p_cur_offset = const_cast<char*>(p_items_end);
+ for (auto i = from; i < from + items; ++i) {
+ offset = src.get_offset(i).value + compensate;
+ p_cur_offset -= sizeof(node_offset_t);
+ p_mut->copy_in_absolute(p_cur_offset, offset);
+ }
+
+ // fill items from src
+ auto p_src_items_start = src.get_item_end(from + items);
+ std::size_t src_items_size = src.get_item_end(from) - p_src_items_start;
+ p_appended = const_cast<char*>(p_items_start) - src_offsets_size - src_items_size;
+ p_mut->copy_in_absolute(p_appended, p_src_items_start, src_items_size);
+ }
+}
+
template <KeyT KT>
char* leaf_sub_items_t::Appender<KT>::wrap()
{
+ if (op_dst.has_value()) {
+ // append from existing
+ assert(p_appended);
+ return p_appended;
+ }
+ // append from empty
+ assert(p_append);
auto p_cur = p_append;
num_keys_t num_keys = 0;
for (auto i = 0u; i < cnt; ++i) {
public:
Appender(NodeExtentMutable* p_mut, char* p_append)
: p_mut{p_mut}, p_append{p_append} {}
+ Appender(NodeExtentMutable* p_mut, const internal_sub_items_t& sub_items)
+ : p_mut{p_mut},
+ p_append{(char*)(sub_items.p_first_item + 1 - sub_items.keys())} {
+ assert(sub_items.keys());
+ }
void append(const internal_sub_items_t& src, index_t from, index_t items);
void append(const full_key_t<KT>&, const laddr_t&, const laddr_packed_t*&);
char* wrap() { return p_append; }
Appender(NodeExtentMutable* p_mut, char* p_append)
: p_mut{p_mut}, p_append{p_append} {
}
-
- void append(const leaf_sub_items_t& src, index_t from, index_t items) {
- assert(cnt <= APPENDER_LIMIT);
- assert(from <= src.keys());
- if (items == 0) {
- return;
- }
- if (op_src) {
- assert(*op_src == src);
- } else {
- op_src = src;
- }
- assert(from < src.keys());
- assert(from + items <= src.keys());
- appends[cnt] = range_items_t{from, items};
- ++cnt;
+ Appender(NodeExtentMutable* p_mut, const leaf_sub_items_t& sub_items)
+ : p_mut{p_mut} , op_dst(sub_items) {
+ assert(sub_items.keys());
}
+
+ void append(const leaf_sub_items_t& src, index_t from, index_t items);
void append(const full_key_t<KT>& key,
const value_config_t& value, const value_header_t*& p_value) {
+ // append from empty
+ assert(p_append);
assert(pp_value == nullptr);
assert(cnt <= APPENDER_LIMIT);
appends[cnt] = kv_item_t{&key, value};
char* wrap();
private:
+ NodeExtentMutable* p_mut;
+ // append from empty
std::optional<leaf_sub_items_t> op_src;
const value_header_t** pp_value = nullptr;
- NodeExtentMutable* p_mut;
- char* p_append;
+ char* p_append = nullptr;
var_t appends[APPENDER_LIMIT];
index_t cnt = 0;
+ // append from existing
+ std::optional<leaf_sub_items_t> op_dst;
+ char* p_appended = nullptr;
};
template <node_type_t> struct _sub_items_t;