crimson/os/seastore/segment_cleaner: move implementations to cc

Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
This commit is contained in:
Yingxin Cheng 2022-05-20 10:30:11 +08:00
parent 0d45ecaf87
commit 90276e9fae
2 changed files with 218 additions and 199 deletions

View File

@ -1231,4 +1231,215 @@ void SegmentCleaner::complete_init()
gc_process.start();
}
void SegmentCleaner::mark_space_used(
paddr_t addr,
extent_len_t len,
time_point last_modified,
time_point last_rewritten,
bool init_scan)
{
LOG_PREFIX(SegmentCleaner::mark_space_used);
if (addr.get_addr_type() != addr_types_t::SEGMENT) {
return;
}
auto& seg_addr = addr.as_seg_paddr();
if (!init_scan && !init_complete) {
return;
}
stats.used_bytes += len;
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 = 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
// time the segments' live extents are to stay unmodified; this is an approximation
// of the sprite lfs' segment "age".
segments.update_last_modified_rewritten(
seg_addr.get_segment_id(), last_modified, last_rewritten);
gc_process.maybe_wake_on_space_used();
assert(ret > 0);
DEBUG("segment {} new len: {}~{}, live_bytes: {}",
seg_addr.get_segment_id(),
addr,
len,
space_tracker->get_usage(seg_addr.get_segment_id()));
}
void SegmentCleaner::mark_space_free(
paddr_t addr,
extent_len_t len,
bool force)
{
LOG_PREFIX(SegmentCleaner::mark_space_free);
if (!init_complete && !force) {
return;
}
if (addr.get_addr_type() != addr_types_t::SEGMENT) {
return;
}
ceph_assert(stats.used_bytes >= len);
stats.used_bytes -= len;
auto& seg_addr = addr.as_seg_paddr();
DEBUG("segment {} free len: {}~{}",
seg_addr.get_segment_id(), addr, len);
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 = calc_utilization(seg_addr.get_segment_id());
adjust_segment_util(old_usage, new_usage);
maybe_wake_gc_blocked_io();
assert(ret >= 0);
DEBUG("segment {} free len: {}~{}, live_bytes: {}",
seg_addr.get_segment_id(),
addr,
len,
space_tracker->get_usage(seg_addr.get_segment_id()));
}
journal_seq_t SegmentCleaner::get_next_gc_target() const
{
LOG_PREFIX(SegmentCleaner::get_next_gc_target);
segment_id_t id = NULL_SEG_ID;
segment_seq_t seq = NULL_SEG_SEQ;
double max_benefit_cost = 0;
for (auto& [_id, segment_info] : segments) {
if (segment_info.is_closed() &&
!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) {
DEBUG("segment {} seq {}, benefit_cost {}",
id, seq, max_benefit_cost);
return journal_seq_t{seq, paddr_t::make_seg_paddr(id, 0)};
} else {
ceph_assert(get_segments_reclaimable() == 0);
// see gc_should_reclaim_space()
ceph_abort("impossible!");
return JOURNAL_SEQ_NULL;
}
}
void SegmentCleaner::log_gc_state(const char *caller) const
{
LOG_PREFIX(SegmentCleaner::log_gc_state);
if (LOCAL_LOGGER.is_enabled(seastar::log_level::debug) &&
!disable_trim) {
DEBUG(
"caller {}, "
"empty {}, "
"open {}, "
"closed {}, "
"in_journal {}, "
"total {}B, "
"available {}B, "
"unavailable {}B, "
"unavailable_used {}B, "
"unavailable_unused {}B; "
"reclaim_ratio {}, "
"available_ratio {}, "
"should_block_on_gc {}, "
"gc_should_reclaim_space {}, "
"journal_head {}, "
"journal_tail_target {}, "
"journal_tail_commit {}, "
"dirty_tail {}, "
"dirty_tail_limit {}, "
"gc_should_trim_journal {}, ",
caller,
segments.get_num_empty(),
segments.get_num_open(),
segments.get_num_closed(),
get_segments_in_journal(),
segments.get_total_bytes(),
segments.get_available_bytes(),
segments.get_unavailable_bytes(),
stats.used_bytes,
get_unavailable_unused_bytes(),
get_reclaim_ratio(),
segments.get_available_ratio(),
should_block_on_gc(),
gc_should_reclaim_space(),
segments.get_journal_head(),
journal_tail_target,
journal_tail_committed,
get_dirty_tail(),
get_dirty_tail_limit(),
gc_should_trim_journal()
);
}
}
seastar::future<>
SegmentCleaner::reserve_projected_usage(std::size_t projected_usage)
{
if (disable_trim) {
return seastar::now();
}
ceph_assert(init_complete);
// The pipeline configuration prevents another IO from entering
// prepare until the prior one exits and clears this.
ceph_assert(!blocked_io_wake);
++stats.io_count;
bool is_blocked = false;
if (should_block_on_trim()) {
is_blocked = true;
++stats.io_blocked_count_trim;
}
if (should_block_on_reclaim()) {
is_blocked = true;
++stats.io_blocked_count_reclaim;
}
if (is_blocked) {
++stats.io_blocking_num;
++stats.io_blocked_count;
stats.io_blocked_sum += stats.io_blocking_num;
}
return seastar::do_until(
[this] {
log_gc_state("await_hard_limits");
return !should_block_on_gc();
},
[this] {
blocked_io_wake = seastar::promise<>();
return blocked_io_wake->get_future();
}
).then([this, projected_usage, is_blocked] {
ceph_assert(!blocked_io_wake);
stats.projected_used_bytes += projected_usage;
++stats.projected_count;
stats.projected_used_bytes_sum += stats.projected_used_bytes;
if (is_blocked) {
assert(stats.io_blocking_num > 0);
--stats.io_blocking_num;
}
});
}
void SegmentCleaner::release_projected_usage(std::size_t projected_usage)
{
if (disable_trim) return;
ceph_assert(init_complete);
ceph_assert(stats.projected_used_bytes >= projected_usage);
stats.projected_used_bytes -= projected_usage;
return maybe_wake_gc_blocked_io();
}
}

View File

@ -10,7 +10,6 @@
#include "osd/osd_types.h"
#include "crimson/common/log.h"
#include "crimson/os/seastore/backref_manager.h"
#include "crimson/os/seastore/cached_extent.h"
#include "crimson/os/seastore/seastore_types.h"
@ -780,77 +779,12 @@ public:
extent_len_t len,
time_point last_modified = time_point(),
time_point last_rewritten = time_point(),
bool init_scan = false) {
if (addr.get_addr_type() != addr_types_t::SEGMENT)
return;
auto& seg_addr = addr.as_seg_paddr();
if (!init_scan && !init_complete)
return;
stats.used_bytes += len;
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 = 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
// time the segments' live extents are to stay unmodified; this is an approximation
// of the sprite lfs' segment "age".
segments.update_last_modified_rewritten(
seg_addr.get_segment_id(), last_modified, last_rewritten);
gc_process.maybe_wake_on_space_used();
assert(ret > 0);
crimson::get_logger(ceph_subsys_seastore_cleaner).debug(
"{} segment {} new len: {}~{}, live_bytes: {}",
__func__,
seg_addr.get_segment_id(),
addr,
len,
space_tracker->get_usage(seg_addr.get_segment_id()));
}
bool init_scan = false);
void mark_space_free(
paddr_t addr,
extent_len_t len,
const bool force = false) {
if (!init_complete && !force)
return;
if (addr.get_addr_type() != addr_types_t::SEGMENT)
return;
ceph_assert(stats.used_bytes >= len);
stats.used_bytes -= len;
auto& seg_addr = addr.as_seg_paddr();
crimson::get_logger(ceph_subsys_seastore_cleaner).debug(
"{} segment {} free len: {}~{}",
__func__,
seg_addr.get_segment_id(),
addr,
len);
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 = calc_utilization(seg_addr.get_segment_id());
adjust_segment_util(old_usage, new_usage);
maybe_wake_gc_blocked_io();
assert(ret >= 0);
crimson::get_logger(ceph_subsys_seastore_cleaner).debug(
"{} segment {} free len: {}~{}, live_bytes: {}",
__func__,
seg_addr.get_segment_id(),
addr,
len,
space_tracker->get_usage(seg_addr.get_segment_id()));
}
bool force = false);
SpaceTrackerIRef get_empty_space_tracker() const {
return space_tracker->make_empty();
@ -933,39 +867,7 @@ private:
return (1 - util) * age / (1 + util);
}
journal_seq_t get_next_gc_target() const {
segment_id_t id = NULL_SEG_ID;
segment_seq_t seq = NULL_SEG_SEQ;
double max_benefit_cost = 0;
for (auto it = segments.begin();
it != segments.end();
++it) {
auto _id = it->first;
const auto& segment_info = it->second;
if (segment_info.is_closed() &&
!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) {
crimson::get_logger(ceph_subsys_seastore_cleaner).debug(
"SegmentCleaner::get_next_gc_target: segment {} seq {}, benefit_cost {}",
id,
seq,
max_benefit_cost);
return journal_seq_t{seq, paddr_t::make_seg_paddr(id, 0)};
} else {
ceph_assert(get_segments_reclaimable() == 0);
// see gc_should_reclaim_space()
ceph_abort("impossible!");
return JOURNAL_SEQ_NULL;
}
}
journal_seq_t get_next_gc_target() const;
/**
* rewrite_dirty
@ -1256,107 +1158,13 @@ private:
return should_block_on_trim() || should_block_on_reclaim();
}
void log_gc_state(const char *caller) const {
auto &logger = crimson::get_logger(ceph_subsys_seastore_cleaner);
if (logger.is_enabled(seastar::log_level::debug) &&
!disable_trim) {
logger.debug(
"SegmentCleaner::log_gc_state({}): "
"empty {}, "
"open {}, "
"closed {}, "
"in_journal {}, "
"total {}B, "
"available {}B, "
"unavailable {}B, "
"unavailable_used {}B, "
"unavailable_unused {}B; "
"reclaim_ratio {}, "
"available_ratio {}, "
"should_block_on_gc {}, "
"gc_should_reclaim_space {}, "
"journal_head {}, "
"journal_tail_target {}, "
"journal_tail_commit {}, "
"dirty_tail {}, "
"dirty_tail_limit {}, "
"gc_should_trim_journal {}, ",
caller,
segments.get_num_empty(),
segments.get_num_open(),
segments.get_num_closed(),
get_segments_in_journal(),
segments.get_total_bytes(),
segments.get_available_bytes(),
segments.get_unavailable_bytes(),
stats.used_bytes,
get_unavailable_unused_bytes(),
get_reclaim_ratio(),
segments.get_available_ratio(),
should_block_on_gc(),
gc_should_reclaim_space(),
segments.get_journal_head(),
journal_tail_target,
journal_tail_committed,
get_dirty_tail(),
get_dirty_tail_limit(),
gc_should_trim_journal()
);
}
}
void log_gc_state(const char *caller) const;
public:
seastar::future<> reserve_projected_usage(size_t projected_usage) {
if (disable_trim) {
return seastar::now();
}
ceph_assert(init_complete);
// The pipeline configuration prevents another IO from entering
// prepare until the prior one exits and clears this.
ceph_assert(!blocked_io_wake);
++stats.io_count;
bool is_blocked = false;
if (should_block_on_trim()) {
is_blocked = true;
++stats.io_blocked_count_trim;
}
if (should_block_on_reclaim()) {
is_blocked = true;
++stats.io_blocked_count_reclaim;
}
if (is_blocked) {
++stats.io_blocking_num;
++stats.io_blocked_count;
stats.io_blocked_sum += stats.io_blocking_num;
}
return seastar::do_until(
[this] {
log_gc_state("await_hard_limits");
return !should_block_on_gc();
},
[this] {
blocked_io_wake = seastar::promise<>();
return blocked_io_wake->get_future();
}
).then([this, projected_usage, is_blocked] {
ceph_assert(!blocked_io_wake);
stats.projected_used_bytes += projected_usage;
++stats.projected_count;
stats.projected_used_bytes_sum += stats.projected_used_bytes;
if (is_blocked) {
assert(stats.io_blocking_num > 0);
--stats.io_blocking_num;
}
});
}
seastar::future<> reserve_projected_usage(std::size_t projected_usage);
void release_projected_usage(size_t projected_usage);
void release_projected_usage(size_t projected_usage) {
if (disable_trim) return;
ceph_assert(init_complete);
ceph_assert(stats.projected_used_bytes >= projected_usage);
stats.projected_used_bytes -= projected_usage;
return maybe_wake_gc_blocked_io();
}
private:
void maybe_wake_gc_blocked_io() {
if (!init_complete) {