segment_info_set_t does extra things not relevant to these structures.
Signed-off-by: Samuel Just <sjust@redhat.com>
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
*
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;
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;
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(
};
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) {
// 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);
}
}
}
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;
}
}
};
- 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
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();
}
}
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;