Skip to content

Commit ae55bea

Browse files
authored
Merge pull request ceph#63515 from xxhdx1985126/wip-seastore-start-stop-trim_dirty
crimson/os/seastore/async_cleaner: set different threshold for starting and stopping trimming dirty Reviewed-by: Yingxin Cheng <[email protected]>
2 parents 620c802 + a8348df commit ae55bea

File tree

2 files changed

+138
-57
lines changed

2 files changed

+138
-57
lines changed

src/crimson/os/seastore/async_cleaner.cc

Lines changed: 101 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,13 @@ void JournalTrimmerImpl::config_t::validate() const
342342
{
343343
ceph_assert(max_journal_bytes <= DEVICE_OFF_MAX);
344344
ceph_assert(max_journal_bytes > target_journal_dirty_bytes);
345+
ceph_assert(target_journal_dirty_bytes >= min_journal_dirty_bytes);
346+
ceph_assert(target_journal_dirty_bytes > rewrite_dirty_bytes_per_cycle);
345347
ceph_assert(max_journal_bytes > target_journal_alloc_bytes);
346-
ceph_assert(rewrite_dirty_bytes_per_cycle > 0);
347-
ceph_assert(rewrite_backref_bytes_per_cycle > 0);
348+
ceph_assert(rewrite_dirty_bytes_per_trans > 0);
349+
ceph_assert(rewrite_dirty_bytes_per_cycle >=
350+
rewrite_dirty_bytes_per_trans);
351+
ceph_assert(max_backref_bytes_per_cycle > 0);
348352
}
349353

350354
JournalTrimmerImpl::config_t
@@ -354,23 +358,28 @@ JournalTrimmerImpl::config_t::get_default(
354358
assert(roll_size);
355359
std::size_t target_dirty_bytes = 0;
356360
std::size_t target_alloc_bytes = 0;
361+
std::size_t min_dirty_bytes = 0;
357362
std::size_t max_journal_bytes = 0;
358363
if (type == backend_type_t::SEGMENTED) {
359-
target_dirty_bytes = 12 * roll_size;
364+
min_dirty_bytes = 12 * roll_size;
360365
target_alloc_bytes = 2 * roll_size;
366+
target_dirty_bytes = 14 * roll_size;
361367
max_journal_bytes = 16 * roll_size;
362368
} else {
363369
assert(type == backend_type_t::RANDOM_BLOCK);
364-
target_dirty_bytes = roll_size / 4;
370+
min_dirty_bytes = roll_size / 4;
365371
target_alloc_bytes = roll_size / 4;
372+
target_dirty_bytes = roll_size / 3;
366373
max_journal_bytes = roll_size / 2;
367374
}
368375
return config_t{
369376
target_dirty_bytes,
370377
target_alloc_bytes,
378+
min_dirty_bytes,
371379
max_journal_bytes,
372-
1<<17,// rewrite_dirty_bytes_per_cycle
373-
1<<24 // rewrite_backref_bytes_per_cycle
380+
1<<26,// rewrite_dirty_bytes_per_cycle, 64MB
381+
1<<17,// rewrite_dirty_bytes_per_trans, 128KB
382+
1<<24 // max_backref_bytes_per_cycle, 16MB
374383
};
375384
}
376385

@@ -381,23 +390,30 @@ JournalTrimmerImpl::config_t::get_test(
381390
assert(roll_size);
382391
std::size_t target_dirty_bytes = 0;
383392
std::size_t target_alloc_bytes = 0;
393+
std::size_t min_dirty_bytes = 0;
384394
std::size_t max_journal_bytes = 0;
385395
if (type == backend_type_t::SEGMENTED) {
386-
target_dirty_bytes = 2 * roll_size;
396+
min_dirty_bytes = 2 * roll_size;
387397
target_alloc_bytes = 2 * roll_size;
398+
target_dirty_bytes = 3 * roll_size;
388399
max_journal_bytes = 4 * roll_size;
389400
} else {
390401
assert(type == backend_type_t::RANDOM_BLOCK);
391-
target_dirty_bytes = roll_size / 36;
402+
min_dirty_bytes = roll_size / 36;
392403
target_alloc_bytes = roll_size / 4;
404+
target_dirty_bytes = roll_size / 24;
393405
max_journal_bytes = roll_size / 2;
394406
}
395407
return config_t{
396408
target_dirty_bytes,
397409
target_alloc_bytes,
410+
min_dirty_bytes,
398411
max_journal_bytes,
399-
1<<17,// rewrite_dirty_bytes_per_cycle
400-
1<<24 // rewrite_backref_bytes_per_cycle
412+
(target_dirty_bytes > 1<<26)
413+
? 1<<25
414+
: target_dirty_bytes / 2, // rewrite_dirty_bytes_per_cycle
415+
1<<17,// rewrite_dirty_bytes_per_trans, 128KB
416+
1<<24 // max_backref_bytes_per_cycle, 16MB
401417
};
402418
}
403419

@@ -514,6 +530,31 @@ journal_seq_t JournalTrimmerImpl::get_tail_limit() const
514530
return ret;
515531
}
516532

533+
journal_seq_t JournalTrimmerImpl::get_dirty_tail_min_target() const
534+
{
535+
assert(background_callback->is_ready());
536+
auto ret = journal_head.add_offset(
537+
backend_type,
538+
-static_cast<device_off_t>(config.min_journal_dirty_bytes),
539+
roll_start,
540+
roll_size);
541+
return ret;
542+
}
543+
544+
journal_seq_t JournalTrimmerImpl::get_dirty_tail_target_per_cycle() const
545+
{
546+
assert(background_callback->is_ready());
547+
auto journal_dirty_bytes = get_journal_dirty_bytes();
548+
assert(journal_dirty_bytes >= get_dirty_bytes_to_trim());
549+
auto ret = journal_head.add_offset(
550+
backend_type,
551+
-static_cast<device_off_t>(
552+
journal_dirty_bytes - get_dirty_bytes_to_trim()),
553+
roll_start,
554+
roll_size);
555+
return ret;
556+
}
557+
517558
journal_seq_t JournalTrimmerImpl::get_dirty_tail_target() const
518559
{
519560
assert(background_callback->is_ready());
@@ -579,7 +620,7 @@ seastar::future<> JournalTrimmerImpl::trim() {
579620
}
580621
},
581622
[this] {
582-
if (should_trim_dirty()) {
623+
if (should_start_trim_dirty()) {
583624
return trim_dirty(
584625
).handle_error(
585626
crimson::ct_error::assert_all{
@@ -618,7 +659,7 @@ JournalTrimmerImpl::trim_alloc()
618659
return backref_manager.merge_cached_backrefs(
619660
t,
620661
target,
621-
config.rewrite_backref_bytes_per_cycle
662+
config.max_backref_bytes_per_cycle
622663
).si_then([this, FNAME, &t](auto trim_alloc_to)
623664
-> ExtentCallbackInterface::submit_transaction_direct_iertr::future<>
624665
{
@@ -646,46 +687,55 @@ JournalTrimmerImpl::trim_dirty()
646687

647688
auto& shard_stats = extent_callback->get_shard_stats();
648689
++(shard_stats.trim_dirty_num);
649-
++(shard_stats.pending_bg_num);
650690

651-
return repeat_eagain([this, FNAME, &shard_stats] {
652-
++(shard_stats.repeat_trim_dirty_num);
691+
auto target = get_dirty_tail_target_per_cycle();
692+
return ::crimson::repeat([this, FNAME, &shard_stats, target] {
693+
if (should_stop_trim_dirty(target)) {
694+
return trim_ertr::make_ready_future<
695+
seastar::stop_iteration>(seastar::stop_iteration::yes);
696+
}
697+
++(shard_stats.pending_bg_num);
698+
return repeat_eagain([this, FNAME, &shard_stats, target] {
699+
++(shard_stats.repeat_trim_dirty_num);
653700

654-
return extent_callback->with_transaction_intr(
655-
Transaction::src_t::TRIM_DIRTY,
656-
"trim_dirty",
657-
CACHE_HINT_NOCACHE,
658-
[this, FNAME](auto &t)
659-
{
660-
auto target = get_dirty_tail_target();
661-
DEBUGT("start, dirty_tail={}, target={}",
662-
t, journal_dirty_tail, target);
663-
return extent_callback->get_next_dirty_extents(
664-
t,
665-
target,
666-
config.rewrite_dirty_bytes_per_cycle
667-
).si_then([this, FNAME, &t](auto dirty_list) {
668-
DEBUGT("rewrite {} dirty extents", t, dirty_list.size());
669-
return seastar::do_with(
670-
std::move(dirty_list),
671-
[this, &t](auto &dirty_list)
672-
{
673-
return trans_intr::do_for_each(
674-
dirty_list,
675-
[this, &t](auto &e) {
676-
return extent_callback->rewrite_extent(
677-
t, e, INIT_GENERATION, NULL_TIME);
678-
});
679-
});
680-
}).si_then([this, &t] {
681-
return extent_callback->submit_transaction_direct(t);
701+
return extent_callback->with_transaction_intr(
702+
Transaction::src_t::TRIM_DIRTY,
703+
"trim_dirty",
704+
CACHE_HINT_NOCACHE,
705+
[this, FNAME, target](auto &t)
706+
{
707+
DEBUGT("start, dirty_tail={}, target={}",
708+
t, journal_dirty_tail, target);
709+
return extent_callback->get_next_dirty_extents(
710+
t,
711+
target,
712+
config.rewrite_dirty_bytes_per_trans
713+
).si_then([this, FNAME, &t](auto dirty_list) {
714+
DEBUGT("rewrite {} dirty extents", t, dirty_list.size());
715+
return seastar::do_with(
716+
std::move(dirty_list),
717+
[this, &t](auto &dirty_list)
718+
{
719+
return trans_intr::do_for_each(
720+
dirty_list,
721+
[this, &t](auto &e) {
722+
return extent_callback->rewrite_extent(
723+
t, e, INIT_GENERATION, NULL_TIME);
724+
});
725+
});
726+
}).si_then([this, &t] {
727+
return extent_callback->submit_transaction_direct(t);
728+
});
682729
});
730+
}).safe_then([] {
731+
return seastar::stop_iteration::no;
732+
}).finally([this, FNAME, &shard_stats] {
733+
DEBUG("finish, dirty_tail={}", journal_dirty_tail);
734+
735+
assert(shard_stats.pending_bg_num);
736+
--(shard_stats.pending_bg_num);
737+
return seastar::stop_iteration::no;
683738
});
684-
}).finally([this, FNAME, &shard_stats] {
685-
DEBUG("finish, dirty_tail={}", journal_dirty_tail);
686-
687-
assert(shard_stats.pending_bg_num);
688-
--(shard_stats.pending_bg_num);
689739
});
690740
}
691741

@@ -708,7 +758,7 @@ std::ostream &operator<<(
708758
os << "JournalTrimmer(";
709759
if (stats.trimmer.background_callback->is_ready()) {
710760
os << "should_block_io_on_trim=" << stats.trimmer.should_block_io_on_trim()
711-
<< ", should_(trim_dirty=" << stats.trimmer.should_trim_dirty()
761+
<< ", should_(trim_dirty=" << stats.trimmer.should_start_trim_dirty()
712762
<< ", trim_alloc=" << stats.trimmer.should_trim_alloc() << ")";
713763
} else {
714764
os << "not-ready";
@@ -719,7 +769,8 @@ std::ostream &operator<<(
719769
<< ", dirty_tail=" << stats.trimmer.get_dirty_tail();
720770
if (stats.trimmer.background_callback->is_ready()) {
721771
os << ", alloc_tail_target=" << stats.trimmer.get_alloc_tail_target()
722-
<< ", dirty_tail_target=" << stats.trimmer.get_dirty_tail_target()
772+
<< ", dirty_tail_min_target=" << stats.trimmer.get_dirty_tail_min_target()
773+
<< ", dirty_tail_target=" << stats.trimmer.get_dirty_tail_target()
723774
<< ", tail_limit=" << stats.trimmer.get_tail_limit();
724775
}
725776
}

src/crimson/os/seastore/async_cleaner.h

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -502,17 +502,23 @@ using JournalTrimmerImplRef = std::unique_ptr<JournalTrimmerImpl>;
502502
class JournalTrimmerImpl : public JournalTrimmer {
503503
public:
504504
struct config_t {
505-
/// Number of minimum bytes to stop trimming dirty.
505+
/// Number of minimum bytes to start trimming dirty,
506+
// this must be larger than or equal to min_journal_dirty_bytes,
507+
// otherwise trim_dirty may never happen.
506508
std::size_t target_journal_dirty_bytes = 0;
507509
/// Number of minimum bytes to stop trimming allocation
508510
/// (having the corresponding backrefs unmerged)
509511
std::size_t target_journal_alloc_bytes = 0;
512+
/// Number of minimum dirty bytes of the journal.
513+
std::size_t min_journal_dirty_bytes = 0;
510514
/// Number of maximum bytes to block user transactions.
511515
std::size_t max_journal_bytes = 0;
512516
/// Number of bytes to rewrite dirty per cycle
513517
std::size_t rewrite_dirty_bytes_per_cycle = 0;
514-
/// Number of bytes to rewrite backref per cycle
515-
std::size_t rewrite_backref_bytes_per_cycle = 0;
518+
/// Number of bytes to rewrite dirty per transaction
519+
std::size_t rewrite_dirty_bytes_per_trans = 0;
520+
/// Maximum number of bytes of new backref extents per cycle
521+
std::size_t max_backref_bytes_per_cycle = 0;
516522

517523
void validate() const;
518524

@@ -560,8 +566,8 @@ class JournalTrimmerImpl : public JournalTrimmer {
560566
journal_seq_t dirty_tail, journal_seq_t alloc_tail) final;
561567

562568
std::size_t get_trim_size_per_cycle() const final {
563-
return config.rewrite_backref_bytes_per_cycle +
564-
config.rewrite_dirty_bytes_per_cycle;
569+
return config.max_backref_bytes_per_cycle +
570+
get_dirty_bytes_to_trim();
565571
}
566572

567573
backend_type_t get_backend_type() const {
@@ -584,7 +590,7 @@ class JournalTrimmerImpl : public JournalTrimmer {
584590
}
585591

586592
bool should_trim() const {
587-
return should_trim_alloc() || should_trim_dirty();
593+
return should_trim_alloc() || should_start_trim_dirty();
588594
}
589595

590596
bool should_block_io_on_trim() const {
@@ -627,10 +633,14 @@ class JournalTrimmerImpl : public JournalTrimmer {
627633
friend std::ostream &operator<<(std::ostream &, const stat_printer_t &);
628634

629635
private:
630-
bool should_trim_dirty() const {
636+
bool should_start_trim_dirty() const {
631637
return get_dirty_tail_target() > journal_dirty_tail;
632638
}
633639

640+
bool should_stop_trim_dirty(const journal_seq_t &target) const {
641+
return target <= journal_dirty_tail;
642+
}
643+
634644
bool should_trim_alloc() const {
635645
return get_alloc_tail_target() > journal_alloc_tail;
636646
}
@@ -642,10 +652,30 @@ class JournalTrimmerImpl : public JournalTrimmer {
642652
trim_ertr::future<> trim_alloc();
643653

644654
journal_seq_t get_tail_limit() const;
655+
journal_seq_t get_dirty_tail_min_target() const;
645656
journal_seq_t get_dirty_tail_target() const;
657+
journal_seq_t get_dirty_tail_target_per_cycle() const;
646658
journal_seq_t get_alloc_tail_target() const;
647659
std::size_t get_dirty_journal_size() const;
648660
std::size_t get_alloc_journal_size() const;
661+
std::size_t get_journal_dirty_bytes() const {
662+
return journal_head.relative_to(
663+
backend_type,
664+
journal_dirty_tail,
665+
roll_start,
666+
roll_size);
667+
}
668+
std::size_t get_max_dirty_bytes_to_trim() const {
669+
auto journal_dirty_bytes = get_journal_dirty_bytes();
670+
if (journal_dirty_bytes <= config.min_journal_dirty_bytes) {
671+
return 0;
672+
}
673+
return journal_dirty_bytes - config.min_journal_dirty_bytes;
674+
}
675+
std::size_t get_dirty_bytes_to_trim() const {
676+
return std::min(get_max_dirty_bytes_to_trim(),
677+
config.rewrite_dirty_bytes_per_cycle);
678+
}
649679
void register_metrics();
650680

651681
ExtentCallbackInterface *extent_callback = nullptr;

0 commit comments

Comments
 (0)