]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore/omap: optimize merge policy 47643/head
authorXinyu Huang <xinyu.huang@intel.com>
Wed, 17 Aug 2022 04:19:24 +0000 (04:19 +0000)
committerXinyu Huang <xinyu.huang@intel.com>
Wed, 17 Aug 2022 08:42:35 +0000 (08:42 +0000)
in some corner cases on single key erase sence,
for e.g. we have three nodes which are brothers:
1 2 3 4 5 | 6 7 8 | 9 10 11, node min size is 3.
When erasing 11 will trigger balance instead of
merge, the middle nodes will adjust to 6 7, this
will not ensure the all nodes above min size.
This corner case might not be harmful but if we
want to erase 10,11 at one time (range remove wip
need this), this will trigger balance in past
policy which will make both two nodes below min
size and we might need at least one more merge.
This is actually because we cannot ensure a node
to merge in tree is above min size.

Signed-off-by: Xinyu Huang <xinyu.huang@intel.com>
src/crimson/os/seastore/omap_manager/btree/omap_btree_node.h
src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc
src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.h
src/crimson/os/seastore/omap_manager/btree/string_kv_node_layout.h

index 5280e73c49622d197c7eb791eefd188bc519c0df..496baffd4a86bec5a7ff3e11e4bdb07d3f3d8aa6 100644 (file)
@@ -101,6 +101,7 @@ struct OMapNode : LogicalCachedExtent {
   virtual bool extent_will_overflow(
     size_t ksize,
     std::optional<size_t> vsize) const = 0;
+  virtual bool can_merge(OMapNodeRef right) const = 0;
   virtual bool extent_is_below_min() const = 0;
   virtual uint32_t get_node_size() = 0;
 
index cfe9a2f47550e6f56cdbfb62c5761aba5b64d504..890dd9232499ce4d625bd569dab7d7ba316e98db 100644 (file)
@@ -367,7 +367,7 @@ OMapInnerNode::merge_entry(
       std::make_pair(donor, entry) : std::make_pair(entry, donor);
     auto [liter, riter] = is_left ?
       std::make_pair(donor_iter, iter) : std::make_pair(iter, donor_iter);
-    if (donor->extent_is_below_min()) {
+    if (l->can_merge(r)) {
       DEBUGT("make_full_merge l {} r {}", oc.t, *l, *r);
       assert(entry->extent_is_below_min());
       return l->make_full_merge(oc, r
index a26b9af9e8848f1ddf079e8374c7616499391255..8a344f06a7dd0ef2131e833d9a43b8e0f3d8af07 100644 (file)
@@ -40,6 +40,9 @@ struct OMapInnerNode
   bool extent_will_overflow(size_t ksize, std::optional<size_t> vsize) const {
     return is_overflow(ksize);
   }
+  bool can_merge(OMapNodeRef right) const {
+    return !is_overflow(*right->cast<OMapInnerNode>());
+  }
   bool extent_is_below_min() const { return below_min(); }
   uint32_t get_node_size() { return get_size(); }
 
@@ -154,6 +157,9 @@ struct OMapLeafNode
     size_t ksize, std::optional<size_t> vsize) const {
     return is_overflow(ksize, *vsize);
   }
+  bool can_merge(OMapNodeRef right) const {
+    return !is_overflow(*right->cast<OMapLeafNode>());
+  }
   bool extent_is_below_min() const { return below_min(); }
   uint32_t get_node_size() { return get_size(); }
 
index 06a1dcb6465e1226e92bd25491ff5e16b2740577..7d449d018229c890c363e996293e694e58341de1 100644 (file)
@@ -660,6 +660,11 @@ public:
   bool is_overflow(size_t ksize) const {
     return free_space() < (sizeof(omap_inner_key_le_t) + ksize);
   }
+
+  bool is_overflow(const StringKVInnerNodeLayout &rhs) const {
+    return free_space() < rhs.used_space();
+  }
+
   bool below_min() const {
     return free_space() > (capacity() / 2);
   }
@@ -1267,6 +1272,11 @@ public:
   bool is_overflow(size_t ksize, size_t vsize) const {
     return free_space() < (sizeof(omap_leaf_key_le_t) + ksize + vsize);
   }
+
+  bool is_overflow(const StringKVLeafNodeLayout &rhs) const {
+    return free_space() < rhs.used_space();
+  }
+
   bool below_min() const {
     return free_space() > (capacity() / 2);
   }