From 2da036b7382b19d51587672cbc5f5bc185940ea7 Mon Sep 17 00:00:00 2001 From: Xuehan Xu Date: Fri, 20 May 2022 17:23:03 +0800 Subject: [PATCH] crimson/os/seastore/segment_cleaner: add dedicated backref trimming process Space reclamation needs to merge backrefs up to the point where the latest release of extents within the scope of the reclamation process happened. When the journal size is large, that merge may generate a transaction record with size exceeds the max record size threshold. So we need have a backref trimming process that merge most of the backrefs before the space reclamation happens. This commit also fixes issue: https://tracker.ceph.com/issues/55692, by repeating the inflight backrefs trimming transaction when it's invalidated by other trans on the ROOT block Fixes: https://tracker.ceph.com/issues/55692 Signed-off-by: Xuehan Xu --- src/crimson/os/seastore/segment_cleaner.cc | 73 ++++++++++++++-------- src/crimson/os/seastore/segment_cleaner.h | 28 ++++++++- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/crimson/os/seastore/segment_cleaner.cc b/src/crimson/os/seastore/segment_cleaner.cc index c0edd31fc69b4..05b42318859ef 100644 --- a/src/crimson/os/seastore/segment_cleaner.cc +++ b/src/crimson/os/seastore/segment_cleaner.cc @@ -710,6 +710,15 @@ SegmentCleaner::gc_cycle_ret SegmentCleaner::do_gc_cycle() "GCProcess::run encountered invalid error in gc_trim_journal" } ); + } else if (gc_should_trim_backref()) { + return gc_trim_backref(get_backref_tail() + ).safe_then([](auto) { + return seastar::now(); + }).handle_error( + crimson::ct_error::assert_all{ + "GCProcess::run encountered invalid error in gc_trim_backref" + } + ); } else if (gc_should_reclaim_space()) { return gc_reclaim_space( ).handle_error( @@ -722,35 +731,45 @@ SegmentCleaner::gc_cycle_ret SegmentCleaner::do_gc_cycle() } } -SegmentCleaner::gc_trim_journal_ret SegmentCleaner::gc_trim_journal() -{ - return ecb->with_transaction_intr( - Transaction::src_t::TRIM_BACKREF, - "trim_backref", - [this](auto &t) { - return seastar::do_with( - get_dirty_tail(), - [this, &t](auto &limit) { - return trim_backrefs(t, limit).si_then( - [this, &t, &limit](auto trim_backrefs_to) - -> ExtentCallbackInterface::submit_transaction_direct_iertr::future< - journal_seq_t> { - if (trim_backrefs_to != JOURNAL_SEQ_NULL) { - return ecb->submit_transaction_direct( - t, std::make_optional(trim_backrefs_to) - ).si_then([trim_backrefs_to=std::move(trim_backrefs_to)]() mutable { - return seastar::make_ready_future< - journal_seq_t>(std::move(trim_backrefs_to)); - }); - } - return seastar::make_ready_future(std::move(limit)); +SegmentCleaner::gc_trim_backref_ret +SegmentCleaner::gc_trim_backref(journal_seq_t limit) { + return seastar::do_with( + journal_seq_t(), + [this, limit=std::move(limit)](auto &seq) mutable { + return repeat_eagain([this, limit=std::move(limit), &seq] { + return ecb->with_transaction_intr( + Transaction::src_t::TRIM_BACKREF, + "trim_backref", + [this, limit](auto &t) { + return trim_backrefs( + t, + limit + ).si_then([this, &t, limit](auto trim_backrefs_to) + -> ExtentCallbackInterface::submit_transaction_direct_iertr::future< + journal_seq_t> { + if (trim_backrefs_to != JOURNAL_SEQ_NULL) { + return ecb->submit_transaction_direct( + t, std::make_optional(trim_backrefs_to) + ).si_then([trim_backrefs_to=std::move(trim_backrefs_to)]() mutable { + return seastar::make_ready_future< + journal_seq_t>(std::move(trim_backrefs_to)); + }); + } + return seastar::make_ready_future(std::move(limit)); + }); + }).safe_then([&seq](auto trim_backrefs_to) { + seq = std::move(trim_backrefs_to); }); + }).safe_then([&seq] { + return gc_trim_backref_ertr::make_ready_future< + journal_seq_t>(std::move(seq)); }); - }).handle_error( - crimson::ct_error::eagain::handle([](auto) { - ceph_abort("unexpected eagain"); - }), - crimson::ct_error::pass_further_all() + }); +} + +SegmentCleaner::gc_trim_journal_ret SegmentCleaner::gc_trim_journal() +{ + return gc_trim_backref(get_dirty_tail() ).safe_then([this](auto seq) { return repeat_eagain([this, seq=std::move(seq)]() mutable { return ecb->with_transaction_intr( diff --git a/src/crimson/os/seastore/segment_cleaner.h b/src/crimson/os/seastore/segment_cleaner.h index 786d667098845..f244f2689db95 100644 --- a/src/crimson/os/seastore/segment_cleaner.h +++ b/src/crimson/os/seastore/segment_cleaner.h @@ -479,6 +479,10 @@ public: /// Number of maximum journal segments to block user transactions. size_t max_journal_segments = 0; + /// Number of journal segments the transactions in which can + /// have their corresponding backrefs unmerged + size_t target_backref_inflight_segments = 0; + /// Ratio of maximum available space to disable reclaiming. double available_ratio_gc_max = 0; /// Ratio of minimum available space to force reclaiming. @@ -511,6 +515,7 @@ public: return config_t{ 12, // target_journal_segments 16, // max_journal_segments + 2, // target_backref_inflight_segments .9, // available_ratio_gc_max .2, // available_ratio_hard_limit .8, // reclaim_ratio_hard_limit @@ -525,6 +530,7 @@ public: return config_t{ 2, // target_journal_segments 4, // max_journal_segments + 2, // target_backref_inflight_segments .9, // available_ratio_gc_max .2, // available_ratio_hard_limit .8, // reclaim_ratio_hard_limit @@ -922,6 +928,17 @@ private: return ret; } + journal_seq_t get_backref_tail() const { + auto ret = segments.get_journal_head(); + ceph_assert(ret != JOURNAL_SEQ_NULL); + if (ret.segment_seq >= config.target_backref_inflight_segments) { + ret.segment_seq -= config.target_backref_inflight_segments; + } else { + ret.segment_seq = 0; + ret.offset = P_ADDR_MIN; + } + return ret; + } // GC status helpers std::optional next_reclaim_pos; @@ -1021,6 +1038,10 @@ private: using gc_trim_journal_ret = gc_trim_journal_ertr::future<>; gc_trim_journal_ret gc_trim_journal(); + using gc_trim_backref_ertr = gc_ertr; + using gc_trim_backref_ret = gc_trim_backref_ertr::future; + gc_trim_backref_ret gc_trim_backref(journal_seq_t limit); + using gc_reclaim_space_ertr = gc_ertr; using gc_reclaim_space_ret = gc_reclaim_space_ertr::future<>; gc_reclaim_space_ret gc_reclaim_space(); @@ -1223,6 +1244,9 @@ private: return get_dirty_tail() > journal_tail_target; } + bool gc_should_trim_backref() const { + return get_backref_tail() > alloc_info_replay_from; + } /** * gc_should_run * @@ -1231,7 +1255,9 @@ private: bool gc_should_run() const { if (disable_trim) return false; ceph_assert(init_complete); - return gc_should_reclaim_space() || gc_should_trim_journal(); + return gc_should_reclaim_space() + || gc_should_trim_journal() + || gc_should_trim_backref(); } void init_mark_segment_closed( -- 2.39.5