+
+ static std::tuple<match_stage_t, position_t> erase(
+ NodeExtentMutable& mut,
+ const node_stage_t& node_stage,
+ const position_t& _erase_pos) {
+ if (_erase_pos.is_end()) {
+ // must be internal node
+ assert(node_stage.is_level_tail());
+ // return erase_stage, last_pos
+ return update_last_to_tail(mut, node_stage);
+ }
+
+ assert(node_stage.keys() != 0);
+ position_t erase_pos = _erase_pos;
+ auto erase_stage = STAGE_T::erase(mut, node_stage, erase_pos);
+ // return erase_stage, next_pos
+ return {erase_stage, erase_pos};
+ }
+
+ static position_t make_tail(
+ NodeExtentMutable& mut,
+ const node_stage_t& node_stage) {
+ assert(!node_stage.is_level_tail());
+ 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:
+ static std::tuple<match_stage_t, position_t> update_last_to_tail(
+ NodeExtentMutable& mut,
+ const node_stage_t& node_stage) {
+ if constexpr (NODE_TYPE == node_type_t::INTERNAL) {
+ assert(node_stage.keys() != 0);
+ position_t last_pos;
+ laddr_t last_value;
+ {
+ const laddr_packed_t* p_last_value;
+ STAGE_T::template get_largest_slot<true, false, true>(
+ node_stage, &last_pos, nullptr, &p_last_value);
+ last_value = p_last_value->value;
+ }
+
+ auto erase_pos = last_pos;
+ auto erase_stage = STAGE_T::erase(mut, node_stage, erase_pos);
+ assert(erase_pos.is_end());
+
+ node_stage_t::update_is_level_tail(mut, node_stage, true);
+ auto p_last_value = const_cast<laddr_packed_t*>(
+ node_stage.get_end_p_laddr());
+ mut.copy_in_absolute(p_last_value, last_value);
+ // return erase_stage, last_pos
+ return {erase_stage, last_pos};
+ } else {
+ ceph_abort("impossible path");
+ }
+ }