]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/onode-staged-tree: implement layout-level merge
authorYingxin Cheng <yingxin.cheng@intel.com>
Wed, 14 Apr 2021 01:39:50 +0000 (09:39 +0800)
committerYingxin Cheng <yingxin.cheng@intel.com>
Thu, 29 Apr 2021 08:03:37 +0000 (16:03 +0800)
Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
src/crimson/os/seastore/onode_manager/staged-fltree/node_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_layout_replayable.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/item_iterator_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/item_iterator_stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/node_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/node_stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/sub_items_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/sub_items_stage.h

index 949faa5a6fd1fe562defafc1fd6d8815dc9e92b6..9097c4bf7546cb9c0a763c097d015cfe8de6fc7e 100644 (file)
@@ -205,8 +205,55 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
 
   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>
@@ -601,7 +648,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
     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)
index df54e8f7c73a90d1847f4c4a34317f923249c596..ece058111f452134e97837fad93df336e53bc0bd 100644 (file)
@@ -94,8 +94,15 @@ struct NodeLayoutReplayableT {
       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:
index b322caa3db677254074212683fe64723f5a0da74..5d399c3ccb210919a4909f44c0cec03e7c2132ea 100644 (file)
@@ -101,6 +101,22 @@ ITER_TEMPLATE(node_type_t::INTERNAL);
 
 #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)
index cdfa642723996e6786634c133a311a589214396f..581298459076cc5fa9b590be3c5a9433b5b0b565 100644 (file)
@@ -169,6 +169,7 @@ class item_iterator_t<NODE_TYPE>::Appender {
  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&);
index b617023b83d74b7a8507a137329de6e61361cb5a..20d5ac893955c26dcbbb52ba21e0caa4dffca5ff 100644 (file)
@@ -204,6 +204,37 @@ NODE_TEMPLATE(leaf_fields_3_t, node_type_t::LEAF);
 
 #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)
@@ -221,7 +252,7 @@ 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);
index 14f022714b17409d40e1463b1811f41c14dd7b6e..d0786ee48fef2ee64398a16715f1cf8e1c6ae6eb 100644 (file)
@@ -201,6 +201,7 @@ class node_extent_t<FieldType, NODE_TYPE>::Appender {
     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();
index c3f270ef744e6d12abbaa05a5c23eb189cf4f4ab..a6f439ca63bfe1af1dcd5bf01eeca0bf462c41e4 100644 (file)
@@ -456,6 +456,24 @@ struct staged {
       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);
@@ -776,6 +794,22 @@ struct staged {
       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;
@@ -847,6 +881,9 @@ struct staged {
    *   (!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
@@ -1266,7 +1303,7 @@ struct staged {
     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);
@@ -1524,6 +1561,7 @@ struct staged {
     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) {
@@ -1883,11 +1921,36 @@ struct staged {
     }
     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);
@@ -1933,7 +1996,7 @@ struct staged {
       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");
@@ -1945,7 +2008,7 @@ struct staged {
       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");
@@ -1997,7 +2060,7 @@ struct staged {
         // 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 {
@@ -2232,8 +2295,28 @@ struct staged {
   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");
+    }
   }
 };
 
index 84e6b49c5a215beadc62538f28d93d9a1762660b..729cab4c3e7407a9d997fb2fbfb5fb47dc090921 100644 (file)
@@ -195,9 +195,76 @@ template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
 // 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) {
index 51c67bf35c2d778e1c63ac9dafd83eb44a043f14..aedd5f0fa410cc919cb2b2e9f1df92050401c645 100644 (file)
@@ -126,6 +126,11 @@ class internal_sub_items_t::Appender {
  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; }
@@ -304,25 +309,16 @@ class leaf_sub_items_t::Appender {
   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};
@@ -332,12 +328,16 @@ class leaf_sub_items_t::Appender {
   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;