From e6a39e218fac5d1a54a5f0aeea79ee96a268f72b Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Thu, 7 Oct 2021 23:17:23 -0700 Subject: [PATCH] crimson/os/seastore/segment_cleaner: rework SpaceTracker* to use a simpler segment map type segment_info_set_t does extra things not relevant to these structures. Signed-off-by: Samuel Just --- src/crimson/os/seastore/seastore_types.h | 177 +++++++++++++++++++++ src/crimson/os/seastore/segment_cleaner.cc | 22 ++- src/crimson/os/seastore/segment_cleaner.h | 95 +++++------ 3 files changed, 224 insertions(+), 70 deletions(-) diff --git a/src/crimson/os/seastore/seastore_types.h b/src/crimson/os/seastore/seastore_types.h index 9ea13afa5d1..6280efa21b4 100644 --- a/src/crimson/os/seastore/seastore_types.h +++ b/src/crimson/os/seastore/seastore_types.h @@ -212,6 +212,183 @@ using record_delta_idx_t = uint32_t; constexpr record_delta_idx_t NULL_DELTA_IDX = std::numeric_limits::max(); +/** + * segment_map_t + * + * Compact templated mapping from a segment_id_t to a value type. + */ +template +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::lower_bound(*this, 0, 0); + } + auto begin() const { + return iterator::lower_bound(*this, 0, 0); + } + + auto end() { + return iterator::end_iterator(*this); + } + auto end() const { + return iterator::end_iterator(*this); + } + + auto device_begin(device_id_t id) { + auto ret = iterator::lower_bound(*this, id, 0); + assert(ret->first.device_id() == id); + return ret; + } + auto device_end(device_id_t id) { + return iterator::lower_bound(*this, id + 1, 0); + } + + size_t size() const { + return total_segments; + } + +private: + template + 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 + >> 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& operator++() { + assert(!is_end()); + ++device_segment_id; + find_valid(); + return *this; + } + + bool operator==(iterator rit) { + return (device_id == rit.device_id && + device_segment_id == rit.device_segment_id); + } + + bool operator!=(iterator rit) { + return !(*this == rit); + } + + template = 0> + const std::pair *operator->() { + assert(!is_end()); + return &*current; + } + template = 0> + std::pair *operator->() { + assert(!is_end()); + return &*current; + } + template = 0> + const std::pair &operator*() { + assert(!is_end()); + return *current; + } + template = 0> + std::pair &operator*() { + assert(!is_end()); + return *current; + } + }; + + /** + * device_to_segments + * + * device -> segment -> T mapping. device_to_segments[d].size() > 0 iff + * device has been added. + */ + std::vector> device_to_segments; + + /// total number of added segments + size_t total_segments = 0; +}; + /** * paddr_t * diff --git a/src/crimson/os/seastore/segment_cleaner.cc b/src/crimson/os/seastore/segment_cleaner.cc index c50dc6fb4a1..5e0360cc3a3 100644 --- a/src/crimson/os/seastore/segment_cleaner.cc +++ b/src/crimson/os/seastore/segment_cleaner.cc @@ -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( diff --git a/src/crimson/os/seastore/segment_cleaner.h b/src/crimson/os/seastore/segment_cleaner.h index cae8628b75c..cea136c27eb 100644 --- a/src/crimson/os/seastore/segment_cleaner.h +++ b/src/crimson/os/seastore/segment_cleaner.h @@ -365,21 +365,17 @@ public: }; using SpaceTrackerIRef = std::unique_ptr; -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 live_bytes_by_segment; + segment_map_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 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& 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_usage; + segment_map_t segment_usage; + std::vector block_size_by_segment_manager; public: - SpaceTrackerDetailed( - std::vector sms) + SpaceTrackerDetailed(const SpaceTrackerDetailed &) = default; + SpaceTrackerDetailed(std::vector 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_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; -- 2.39.5