]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore/segment_cleaner: exclude utilizations from empty/open segments
authorYingxin Cheng <yingxin.cheng@intel.com>
Sat, 7 May 2022 11:15:12 +0000 (19:15 +0800)
committerYingxin Cheng <yingxin.cheng@intel.com>
Fri, 13 May 2022 07:51:20 +0000 (15:51 +0800)
Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
src/crimson/os/seastore/segment_cleaner.cc
src/crimson/os/seastore/segment_cleaner.h

index ae3535f2d633d1b9a5be42283c06b2c4dd0ace35..637d4f4c829af982919604fa015c1cb8ba6e5d70 100644 (file)
@@ -409,15 +409,16 @@ SegmentCleaner::SegmentCleaner(
 void SegmentCleaner::register_metrics()
 {
   namespace sm = seastar::metrics;
-  stats.segment_util.buckets.resize(11);
-  for (int i = 0; i < 11; i++) {
+  stats.segment_util.buckets.resize(UTIL_BUCKETS);
+  std::size_t i;
+  for (i = 0; i < UTIL_BUCKETS; ++i) {
     stats.segment_util.buckets[i].upper_bound = ((double)(i + 1)) / 10;
-    if (!i) {
-      stats.segment_util.buckets[i].count = segments.get_num_segments();
-    } else {
-      stats.segment_util.buckets[i].count = 0;
-    }
+    stats.segment_util.buckets[i].count = 0;
   }
+  // NOTE: by default the segments are empty
+  i = get_bucket_index(UTIL_STATE_EMPTY);
+  stats.segment_util.buckets[i].count = segments.get_num_segments();
+
   metrics.add_group("segment_cleaner", {
     sm::make_counter("segments_number",
                     [this] { return segments.get_num_segments(); },
@@ -510,7 +511,10 @@ segment_id_t SegmentCleaner::allocate_segment(
     auto seg_id = it->first;
     auto& segment_info = it->second;
     if (segment_info.is_empty()) {
+      auto old_usage = calc_utilization(seg_id);
       segments.mark_open(seg_id, seq, type);
+      auto new_usage = calc_utilization(seg_id);
+      adjust_segment_util(old_usage, new_usage);
       INFO("opened, should_block_on_gc {}, projected_avail_ratio {}, "
            "reclaim_ratio {}",
            should_block_on_gc(),
@@ -591,7 +595,10 @@ void SegmentCleaner::update_journal_tail_committed(journal_seq_t committed)
 void SegmentCleaner::close_segment(segment_id_t segment)
 {
   LOG_PREFIX(SegmentCleaner::close_segment);
+  auto old_usage = calc_utilization(segment);
   segments.mark_closed(segment);
+  auto new_usage = calc_utilization(segment);
+  adjust_segment_util(old_usage, new_usage);
   INFO("closed, should_block_on_gc {}, projected_avail_ratio {}, "
        "reclaim_ratio {}",
        should_block_on_gc(),
@@ -1124,7 +1131,11 @@ SegmentCleaner::maybe_release_segment(Transaction &t)
     INFOT("releasing segment {}", t, to_release);
     return sm_group->release_segment(to_release
     ).safe_then([this, FNAME, &t, to_release] {
+      auto old_usage = calc_utilization(to_release);
+      ceph_assert(old_usage == 0);
       segments.mark_empty(to_release);
+      auto new_usage = calc_utilization(to_release);
+      adjust_segment_util(old_usage, new_usage);
       INFOT("released, should_block_on_gc {}, projected_avail_ratio {}, "
            "reclaim_ratio {}",
            t,
index 6979d9d38d2b31e216286f0d23dcff3f533b3bb5..b3e842ed548906621348393a921616f8e1ec4323 100644 (file)
@@ -749,9 +749,11 @@ public:
   release_ertr::future<> maybe_release_segment(Transaction &t);
 
   void adjust_segment_util(double old_usage, double new_usage) {
-    assert(stats.segment_util.buckets[std::floor(old_usage * 10)].count > 0);
-    stats.segment_util.buckets[std::floor(old_usage * 10)].count--;
-    stats.segment_util.buckets[std::floor(new_usage * 10)].count++;
+    auto old_index = get_bucket_index(old_usage);
+    auto new_index = get_bucket_index(new_usage);
+    assert(stats.segment_util.buckets[old_index].count > 0);
+    stats.segment_util.buckets[old_index].count--;
+    stats.segment_util.buckets[new_index].count++;
   }
 
   void mark_space_used(
@@ -766,12 +768,12 @@ public:
       return;
 
     stats.used_bytes += len;
-    auto old_usage = space_tracker->calc_utilization(seg_addr.get_segment_id());
+    auto old_usage = calc_utilization(seg_addr.get_segment_id());
     [[maybe_unused]] auto ret = space_tracker->allocate(
       seg_addr.get_segment_id(),
       seg_addr.get_segment_off(),
       len);
-    auto new_usage = space_tracker->calc_utilization(seg_addr.get_segment_id());
+    auto new_usage = calc_utilization(seg_addr.get_segment_id());
     adjust_segment_util(old_usage, new_usage);
 
     // use the last extent's last modified time for the calculation of the projected
@@ -809,12 +811,12 @@ public:
       seg_addr.get_segment_id(),
       addr,
       len);
-    auto old_usage = space_tracker->calc_utilization(seg_addr.get_segment_id());
+    auto old_usage = calc_utilization(seg_addr.get_segment_id());
     [[maybe_unused]] auto ret = space_tracker->release(
       seg_addr.get_segment_id(),
       seg_addr.get_segment_off(),
       len);
-    auto new_usage = space_tracker->calc_utilization(seg_addr.get_segment_id());
+    auto new_usage = calc_utilization(seg_addr.get_segment_id());
     adjust_segment_util(old_usage, new_usage);
     maybe_wake_gc_blocked_io();
     assert(ret >= 0);
@@ -865,11 +867,36 @@ public:
   using work_iertr = ExtentCallbackInterface::extent_mapping_iertr;
 
 private:
+  /*
+   * 10 buckets for the number of closed segments by usage
+   * 2 extra buckets for the number of open and empty segments
+   */
+  static constexpr double UTIL_STATE_OPEN = 1.05;
+  static constexpr double UTIL_STATE_EMPTY = 1.15;
+  static constexpr std::size_t UTIL_BUCKETS = 12;
+  static std::size_t get_bucket_index(double util) {
+    auto index = std::floor(util * 10);
+    assert(index < UTIL_BUCKETS);
+    return index;
+  }
+  double calc_utilization(segment_id_t id) const {
+    auto& info = segments[id];
+    if (info.is_open()) {
+      return UTIL_STATE_OPEN;
+    } else if (info.is_empty()) {
+      return UTIL_STATE_EMPTY;
+    } else {
+      auto ret = space_tracker->calc_utilization(id);
+      assert(ret >= 0 && ret < 1);
+      return ret;
+    }
+  }
 
   // journal status helpers
 
   double calc_gc_benefit_cost(segment_id_t id) const {
-    double util = space_tracker->calc_utilization(id);
+    double util = calc_utilization(id);
+    ceph_assert(util >= 0 && util < 1);
     auto cur_time = seastar::lowres_system_clock::now();
     auto segment = segments[id];
     assert(cur_time >= segment.last_modified);
@@ -888,13 +915,14 @@ private:
         ++it) {
       auto _id = it->first;
       const auto& segment_info = it->second;
-      double benefit_cost = calc_gc_benefit_cost(_id);
       if (segment_info.is_closed() &&
-         !segment_info.is_in_journal(journal_tail_committed) &&
-         benefit_cost > max_benefit_cost) {
-       id = _id;
-       seq = segment_info.seq;
-       max_benefit_cost = benefit_cost;
+         !segment_info.is_in_journal(journal_tail_committed)) {
+        double benefit_cost = calc_gc_benefit_cost(_id);
+        if (benefit_cost > max_benefit_cost) {
+          id = _id;
+          seq = segment_info.seq;
+          max_benefit_cost = benefit_cost;
+        }
       }
     }
     if (id != NULL_SEG_ID) {
@@ -1273,7 +1301,10 @@ private:
       segment_seq_t seq,
       segment_type_t s_type) {
     ceph_assert(!init_complete);
+    auto old_usage = calc_utilization(segment);
     segments.init_closed(segment, seq, s_type);
+    auto new_usage = calc_utilization(segment);
+    adjust_segment_util(old_usage, new_usage);
     if (s_type == segment_type_t::OOL) {
       ool_segment_seq_allocator->set_next_segment_seq(seq);
     }