]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore/segment_cleaner: rework SpaceTracker* to use a simpler segment...
authorSamuel Just <sjust@redhat.com>
Fri, 8 Oct 2021 06:17:23 +0000 (23:17 -0700)
committerXuehan Xu <xxhdx1985126@gmail.com>
Sun, 10 Oct 2021 06:22:10 +0000 (14:22 +0800)
segment_info_set_t does extra things not relevant to these structures.

Signed-off-by: Samuel Just <sjust@redhat.com>
src/crimson/os/seastore/seastore_types.h
src/crimson/os/seastore/segment_cleaner.cc
src/crimson/os/seastore/segment_cleaner.h

index 9ea13afa5d1835d6cc144f79b449bcb76453fc6c..6280efa21b430f9de49797ff047b6dfa58053115 100644 (file)
@@ -212,6 +212,183 @@ using record_delta_idx_t = uint32_t;
 constexpr record_delta_idx_t NULL_DELTA_IDX =
   std::numeric_limits<record_delta_idx_t>::max();
 
+/**
+ * segment_map_t
+ *
+ * Compact templated mapping from a segment_id_t to a value type.
+ */
+template <typename T>
+class segment_map_t {
+public:
+  segment_map_t() {
+    // initializes top vector with 0 length vectors to indicate that they
+    // are not yet present
+    device_to_segments.resize(DEVICE_ID_MAX);
+  }
+  void add_device(device_id_t device, size_t segments, const T& init) {
+    assert(device < DEVICE_ID_MAX);
+    assert(device_to_segments[device].size() == 0);
+    device_to_segments[device].resize(segments, init);
+    total_segments += segments;
+  }
+
+  T& operator[](segment_id_t id) {
+    assert(id.device_segment_id() < device_to_segments[id.device_id()].size());
+    return device_to_segments[id.device_id()][id.device_segment_id()];
+  }
+  const T& operator[](segment_id_t id) const {
+    assert(id.device_segment_id() < device_to_segments[id.device_id()].size());
+    return device_to_segments[id.device_id()][id.device_segment_id()];
+  }
+
+  auto begin() {
+    return iterator<false>::lower_bound(*this, 0, 0);
+  }
+  auto begin() const {
+    return iterator<true>::lower_bound(*this, 0, 0);
+  }
+
+  auto end() {
+    return iterator<false>::end_iterator(*this);
+  }
+  auto end() const {
+    return iterator<true>::end_iterator(*this);
+  }
+
+  auto device_begin(device_id_t id) {
+    auto ret = iterator<false>::lower_bound(*this, id, 0);
+    assert(ret->first.device_id() == id);
+    return ret;
+  }
+  auto device_end(device_id_t id) {
+    return iterator<false>::lower_bound(*this, id + 1, 0);
+  }
+
+  size_t size() const {
+    return total_segments;
+  }
+
+private:
+  template <bool is_const = false>
+  class iterator {
+    /// points at set being iterated over
+    std::conditional_t<
+      is_const,
+      const segment_map_t &,
+      segment_map_t &> parent;
+
+    /// points at current device, or DEVICE_ID_MAX if is_end()
+    device_id_t device_id;
+
+    /// segment at which we are pointing, 0 if is_end()
+    device_segment_id_t device_segment_id;
+
+    /// holds referent for operator* and operator-> when !is_end()
+    std::optional<
+      std::pair<
+        const segment_id_t,
+       std::conditional_t<is_const, const T&, T&>
+       >> current;
+
+    bool is_end() const {
+      return device_id == DEVICE_ID_MAX;
+    }
+
+    void find_valid() {
+      assert(!is_end());
+      auto &device_vec = parent.device_to_segments[device_id];
+      if (device_vec.size() == 0 ||
+         device_segment_id == device_vec.size()) {
+       while (++device_id < DEVICE_ID_MAX &&
+              parent.device_to_segments[device_id].size() == 0);
+       device_segment_id = 0;
+      }
+      if (is_end()) {
+       current = std::nullopt;
+      } else {
+       current.emplace(
+         segment_id_t{device_id, device_segment_id},
+         parent.device_to_segments[device_id][device_segment_id]
+       );
+      }
+    }
+
+    iterator(
+      decltype(parent) &parent,
+      device_id_t device_id,
+      device_segment_id_t device_segment_id)
+      : parent(parent), device_id(device_id),
+       device_segment_id(device_segment_id) {}
+
+  public:
+    static iterator lower_bound(
+      decltype(parent) &parent,
+      device_id_t device_id,
+      device_segment_id_t device_segment_id) {
+      if (device_id == DEVICE_ID_MAX) {
+       return end_iterator(parent);
+      } else {
+       auto ret = iterator{parent, device_id, device_segment_id};
+       ret.find_valid();
+       return ret;
+      }
+    }
+
+    static iterator end_iterator(
+      decltype(parent) &parent) {
+      return iterator{parent, DEVICE_ID_MAX, 0};
+    }
+
+    iterator<is_const>& operator++() {
+      assert(!is_end());
+      ++device_segment_id;
+      find_valid();
+      return *this;
+    }
+
+    bool operator==(iterator<is_const> rit) {
+      return (device_id == rit.device_id &&
+             device_segment_id == rit.device_segment_id);
+    }
+
+    bool operator!=(iterator<is_const> rit) {
+      return !(*this == rit);
+    }
+
+    template <bool c = is_const, std::enable_if_t<c, int> = 0>
+    const std::pair<const segment_id_t, const T&> *operator->() {
+      assert(!is_end());
+      return &*current;
+    }
+    template <bool c = is_const, std::enable_if_t<!c, int> = 0>
+    std::pair<const segment_id_t, T&> *operator->() {
+      assert(!is_end());
+      return &*current;
+    }
+    template <bool c = is_const, std::enable_if_t<c, int> = 0>
+    const std::pair<const segment_id_t, const T&> &operator*() {
+      assert(!is_end());
+      return *current;
+    }
+    template <bool c = is_const, std::enable_if_t<!c, int> = 0>
+    std::pair<const segment_id_t, T&> &operator*() {
+      assert(!is_end());
+      return *current;
+    }
+  };
+
+  /**
+   * device_to_segments
+   *
+   * device -> segment -> T mapping.  device_to_segments[d].size() > 0 iff
+   * device <d> has been added.
+   */
+  std::vector<std::vector<T>> device_to_segments;
+
+  /// total number of added segments
+  size_t total_segments = 0;
+};
+
 /**
  * paddr_t
  *
index c50dc6fb4a1b7ffcde35b0d976c94b967ed23f70..5e0360cc3a3bd99326a3623cf77a357b99b7d05c 100644 (file)
@@ -53,15 +53,14 @@ bool SpaceTrackerSimple::equals(const SpaceTrackerI &_other) const
   bool all_match = true;
   for (auto i = live_bytes_by_segment.begin(), j = other.live_bytes_by_segment.begin();
        i != live_bytes_by_segment.end(); ++i, ++j) {
-    assert(i->segment == j->segment);
-    if (i->live_bytes != j->live_bytes) {
+    if (i->second != j->second) {
       all_match = false;
       logger().debug(
        "{}: segment_id {} live bytes mismatch *this: {}, other: {}",
        __func__,
-       i->segment,
-       i->live_bytes,
-       j->live_bytes);
+       i->first,
+       i->second,
+       j->second);
     }
   }
   return all_match;
@@ -144,15 +143,14 @@ bool SpaceTrackerDetailed::equals(const SpaceTrackerI &_other) const
   bool all_match = true;
   for (auto i = segment_usage.begin(), j = other.segment_usage.begin();
        i != segment_usage.end(); ++i, ++j) {
-    assert(i->segment == j->segment);
-    if (i->segment_map.get_usage() != j->segment_map.get_usage()) {
+    if (i->second.get_usage() != j->second.get_usage()) {
       all_match = false;
       logger().error(
        "{}: segment_id {} live bytes mismatch *this: {}, other: {}",
        __func__,
-       i->segment,
-       i->segment_map.get_usage(),
-       j->segment_map.get_usage());
+       i->first,
+       i->second.get_usage(),
+       j->second.get_usage());
     }
   }
   return all_match;
@@ -170,8 +168,8 @@ void SpaceTrackerDetailed::SegmentMap::dump_usage(extent_len_t block_size) const
 void SpaceTrackerDetailed::dump_usage(segment_id_t id) const
 {
   logger().debug("SpaceTrackerDetailed::dump_usage {}", id);
-  segment_usage[id].segment_map.dump_usage(
-    segment_usage[id.device_id()]->block_size);
+  segment_usage[id].dump_usage(
+    block_size_by_segment_manager[id.device_id()]);
 }
 
 SegmentCleaner::SegmentCleaner(
index cae8628b75cbf00f246866d92cd8a70e25cf5fd2..cea136c27ebc4e51afbc767ac3d635cedd1a4c69 100644 (file)
@@ -365,21 +365,17 @@ public:
 };
 using SpaceTrackerIRef = std::unique_ptr<SpaceTrackerI>;
 
-struct segment_space_tracker_t {
-  segment_id_t segment = NULL_SEG_ID;
-  int64_t live_bytes = 0;
-};
-
 class SpaceTrackerSimple : public SpaceTrackerI {
   // Tracks live space for each segment
-  segment_info_set_t<segment_space_tracker_t> live_bytes_by_segment;
+  segment_map_t<int64_t> live_bytes_by_segment;
 
   int64_t update_usage(segment_id_t segment, int64_t delta) {
-    live_bytes_by_segment[segment].live_bytes += delta;
-    assert(live_bytes_by_segment[segment].live_bytes >= 0);
-    return live_bytes_by_segment[segment].live_bytes;
+    live_bytes_by_segment[segment] += delta;
+    assert(live_bytes_by_segment[segment] >= 0);
+    return live_bytes_by_segment[segment];
   }
 public:
+  SpaceTrackerSimple(const SpaceTrackerSimple &) = default;
   SpaceTrackerSimple(std::vector<SegmentManager*> sms) {
     for (auto sm : sms) {
       if (!sm) {
@@ -388,18 +384,10 @@ public:
        // may be null.
        continue;
       }
-      live_bytes_by_segment.add_segment_manager(
-       *sm,
-       segment_space_tracker_t{});
-    }
-  }
-  SpaceTrackerSimple(
-    const segment_info_set_t<segment_space_tracker_t>& live_bytes_by_segment)
-    : live_bytes_by_segment(live_bytes_by_segment) {
-    for (auto it = this->live_bytes_by_segment.begin();
-       it != this->live_bytes_by_segment.end();
-       ++it) {
-      it->live_bytes = 0;
+      live_bytes_by_segment.add_device(
+       sm->get_device_id(),
+       sm->get_num_segments(),
+       0);
     }
   }
 
@@ -418,21 +406,21 @@ public:
   }
 
   int64_t get_usage(segment_id_t segment) const final {
-    return live_bytes_by_segment[segment].live_bytes;
+    return live_bytes_by_segment[segment];
   }
 
   void dump_usage(segment_id_t) const final {}
 
   void reset() final {
-    for (auto it = live_bytes_by_segment.begin();
-       it != live_bytes_by_segment.end();
-       ++it)
-      it->live_bytes = 0;
+    for (auto &i : live_bytes_by_segment) {
+      i.second = 0;
+    }
   }
 
   SpaceTrackerIRef make_empty() const final {
-    return SpaceTrackerIRef(
-      new SpaceTrackerSimple(live_bytes_by_segment));
+    auto ret = SpaceTrackerIRef(new SpaceTrackerSimple(*this));
+    ret->reset();
+    return ret;
   }
 
   bool equals(const SpaceTrackerI &other) const;
@@ -476,20 +464,16 @@ class SpaceTrackerDetailed : public SpaceTrackerI {
       }
     }
   };
-  struct segment_tracker_t {
-    segment_tracker_t(size_t blocks)
-      : segment_map(blocks) {}
-    segment_id_t segment;
-    SegmentMap segment_map;
-  };
 
   // Tracks live space for each segment
-  segment_info_set_t<segment_tracker_t> segment_usage;
+  segment_map_t<SegmentMap> segment_usage;
+  std::vector<size_t> block_size_by_segment_manager;
 
 public:
-  SpaceTrackerDetailed(
-    std::vector<SegmentManager*> sms)
+  SpaceTrackerDetailed(const SpaceTrackerDetailed &) = default;
+  SpaceTrackerDetailed(std::vector<SegmentManager*> sms)
   {
+    block_size_by_segment_manager.resize(DEVICE_ID_MAX, 0);
     for (auto sm : sms) {
       // sms is a vector that is indexed by device id and
       // always has "max_device" elements, some of which
@@ -497,18 +481,12 @@ public:
       if (!sm) {
        continue;
       }
-      segment_usage.add_segment_manager(
-       *sm,
-       segment_tracker_t(
+      segment_usage.add_device(
+       sm->get_device_id(),
+       sm->get_num_segments(),
+       SegmentMap(
          sm->get_segment_size() / sm->get_block_size()));
-    }
-  }
-  SpaceTrackerDetailed(
-    const segment_info_set_t<segment_tracker_t>& segment_usage)
-    : segment_usage(segment_usage)
-  {
-    for (auto& tracker : this->segment_usage) {
-      tracker.segment_map.reset();
+      block_size_by_segment_manager[sm->get_device_id()] = sm->get_block_size();
     }
   }
 
@@ -516,39 +494,40 @@ public:
     segment_id_t segment,
     segment_off_t offset,
     extent_len_t len) final {
-    return segment_usage[segment].segment_map.allocate(
+    return segment_usage[segment].allocate(
       segment.device_segment_id(),
       offset,
       len,
-      segment_usage[segment.device_id()]->block_size);
+      block_size_by_segment_manager[segment.device_id()]);
   }
 
   int64_t release(
     segment_id_t segment,
     segment_off_t offset,
     extent_len_t len) final {
-    return segment_usage[segment].segment_map.release(
+    return segment_usage[segment].release(
       segment.device_segment_id(),
       offset,
       len,
-      segment_usage[segment.device_id()]->block_size);
+      block_size_by_segment_manager[segment.device_id()]);
   }
 
   int64_t get_usage(segment_id_t segment) const final {
-    return segment_usage[segment].segment_map.get_usage();
+    return segment_usage[segment].get_usage();
   }
 
   void dump_usage(segment_id_t seg) const final;
 
   void reset() final {
-    for (auto &i: segment_usage)
-      i.segment_map.reset();
+    for (auto &i: segment_usage) {
+      i.second.reset();
+    }
   }
 
   SpaceTrackerIRef make_empty() const final {
-    return SpaceTrackerIRef(
-      new SpaceTrackerDetailed(
-       segment_usage));
+    auto ret = SpaceTrackerIRef(new SpaceTrackerDetailed(*this));
+    ret->reset();
+    return ret;
   }
 
   bool equals(const SpaceTrackerI &other) const;