LOG_PREFIX(AsyncCleaner::mount);
const auto& sms = sm_group->get_segment_managers();
INFO("{} segment managers", sms.size());
- init_complete = false;
+ ceph_assert(state == cleaner_state_t::STOP);
+ state = cleaner_state_t::MOUNT;
stats = {};
journal_head = JOURNAL_SEQ_NULL;
journal_alloc_tail = JOURNAL_SEQ_NULL;
});
}
-void AsyncCleaner::complete_init()
+void AsyncCleaner::start_gc()
{
- LOG_PREFIX(AsyncCleaner::complete_init);
+ LOG_PREFIX(AsyncCleaner::start_gc);
+ ceph_assert(state == cleaner_state_t::SCAN_SPACE);
+ state = cleaner_state_t::READY;
if (disable_trim) {
- init_complete = true;
return;
}
- init_complete = true;
INFO("done, start GC, {}", gc_stat_printer_t{this, true});
ceph_assert(journal_head != JOURNAL_SEQ_NULL);
ceph_assert(journal_alloc_tail != JOURNAL_SEQ_NULL);
seastar::future<> AsyncCleaner::stop()
{
+ if (is_ready()) {
+ state = cleaner_state_t::HALT;
+ } else {
+ state = cleaner_state_t::STOP;
+ }
return gc_process.stop(
).then([this] {
LOG_PREFIX(AsyncCleaner::stop);
INFO("done, {}", gc_stat_printer_t{this, true});
+ // run_until_halt() can be called at HALT
});
}
void AsyncCleaner::mark_space_used(
paddr_t addr,
- extent_len_t len,
- bool init_scan)
+ extent_len_t len)
{
LOG_PREFIX(AsyncCleaner::mark_space_used);
if (addr.get_addr_type() != paddr_types_t::SEGMENT) {
}
auto& seg_addr = addr.as_seg_paddr();
- if (!init_scan && !init_complete) {
+ if (state < cleaner_state_t::SCAN_SPACE) {
return;
}
void AsyncCleaner::mark_space_free(
paddr_t addr,
- extent_len_t len,
- bool init_scan)
+ extent_len_t len)
{
LOG_PREFIX(AsyncCleaner::mark_space_free);
- if (!init_complete && !init_scan) {
+ if (state < cleaner_state_t::SCAN_SPACE) {
return;
}
if (addr.get_addr_type() != paddr_types_t::SEGMENT) {
if (disable_trim) {
return seastar::now();
}
- ceph_assert(init_complete);
+ ceph_assert(is_ready());
// The pipeline configuration prevents another IO from entering
// prepare until the prior one exits and clears this.
ceph_assert(!blocked_io_wake);
void AsyncCleaner::release_projected_usage(std::size_t projected_usage)
{
if (disable_trim) return;
- ceph_assert(init_complete);
+ ceph_assert(is_ready());
ceph_assert(stats.projected_used_bytes >= projected_usage);
stats.projected_used_bytes -= projected_usage;
return maybe_wake_gc_blocked_io();
std::ostream &operator<<(std::ostream &os, AsyncCleaner::gc_stat_printer_t stats)
{
os << "gc_stats(";
- if (stats.cleaner->init_complete) {
+ if (stats.cleaner->is_ready()) {
os << "should_block_on_(trim=" << stats.cleaner->should_block_on_trim()
<< ", reclaim=" << stats.cleaner->should_block_on_reclaim() << ")"
<< ", should_(trim_dirty=" << stats.cleaner->gc_should_trim_dirty()
<< ", trim_alloc=" << stats.cleaner->gc_should_trim_alloc()
<< ", reclaim=" << stats.cleaner->gc_should_reclaim_space() << ")";
} else {
- os << "init";
+ os << "not-ready";
}
os << ", projected_avail_ratio=" << stats.cleaner->get_projected_available_ratio()
<< ", reclaim_ratio=" << stats.cleaner->get_reclaim_ratio()
os << ", journal_head=" << stats.cleaner->journal_head
<< ", alloc_tail=" << stats.cleaner->journal_alloc_tail
<< ", dirty_tail=" << stats.cleaner->journal_dirty_tail;
- if (stats.cleaner->init_complete) {
+ if (stats.cleaner->is_ready()) {
os << ", alloc_tail_target=" << stats.cleaner->get_alloc_tail_target()
<< ", dirty_tail_target=" << stats.cleaner->get_dirty_tail_target()
<< ", tail_limit=" << stats.cleaner->get_tail_limit();
bool equals(const SpaceTrackerI &other) const;
};
-
class AsyncCleaner : public SegmentProvider, public JournalTrimmer {
+ enum class cleaner_state_t {
+ STOP,
+ MOUNT,
+ SCAN_SPACE,
+ READY,
+ HALT,
+ } state = cleaner_state_t::STOP;
+
public:
/// Config
struct config_t {
SpaceTrackerIRef space_tracker;
segments_info_t segments;
- bool init_complete = false;
struct {
/**
using mount_ret = mount_ertr::future<>;
mount_ret mount();
+ bool is_ready() const {
+ return state >= cleaner_state_t::READY;
+ }
+
/*
* SegmentProvider interfaces
*/
void mark_space_used(
paddr_t addr,
- extent_len_t len,
- bool init_scan = false);
+ extent_len_t len);
void mark_space_free(
paddr_t addr,
- extent_len_t len,
- bool init_scan = false);
+ extent_len_t len);
SpaceTrackerIRef get_empty_space_tracker() const {
return space_tracker->make_empty();
}
- void complete_init();
+ void start_scan_space() {
+ ceph_assert(state == cleaner_state_t::MOUNT);
+ state = cleaner_state_t::SCAN_SPACE;
+ assert(debug_check_space(*get_empty_space_tracker()));
+ }
+
+ void start_gc();
store_statfs_t stat() const {
store_statfs_t st;
seastar::future<> stop();
seastar::future<> run_until_halt() {
+ ceph_assert(state == cleaner_state_t::HALT);
return gc_process.run_until_halt();
}
segment_id_t get_next_reclaim_segment() const;
journal_seq_t get_dirty_tail_target() const {
- assert(init_complete);
+ assert(is_ready());
auto ret = journal_head;
ceph_assert(ret != JOURNAL_SEQ_NULL);
if (ret.segment_seq >= config.target_journal_dirty_segments) {
}
journal_seq_t get_tail_limit() const {
- assert(init_complete);
+ assert(is_ready());
auto ret = journal_head;
ceph_assert(ret != JOURNAL_SEQ_NULL);
if (ret.segment_seq >= config.max_journal_segments) {
}
journal_seq_t get_alloc_tail_target() const {
- assert(init_complete);
+ assert(is_ready());
auto ret = journal_head;
ceph_assert(ret != JOURNAL_SEQ_NULL);
if (ret.segment_seq >= config.target_journal_alloc_segments) {
* Encapsulates whether block pending gc.
*/
bool should_block_on_trim() const {
- assert(init_complete);
+ assert(is_ready());
if (disable_trim) return false;
return get_tail_limit() > get_journal_tail();
}
bool should_block_on_reclaim() const {
- assert(init_complete);
+ assert(is_ready());
if (disable_trim) return false;
if (get_segments_reclaimable() == 0) {
return false;
}
bool should_block_on_gc() const {
- assert(init_complete);
+ assert(is_ready());
return should_block_on_trim() || should_block_on_reclaim();
}
private:
void maybe_wake_gc_blocked_io() {
- if (!init_complete) {
+ if (!is_ready()) {
return;
}
if (!should_block_on_gc() && blocked_io_wake) {
* Encapsulates logic for whether gc should be reclaiming segment space.
*/
bool gc_should_reclaim_space() const {
- assert(init_complete);
+ assert(is_ready());
if (disable_trim) return false;
if (get_segments_reclaimable() == 0) {
return false;
}
bool gc_should_trim_dirty() const {
- assert(init_complete);
+ assert(is_ready());
return get_dirty_tail_target() > journal_dirty_tail;
}
bool gc_should_trim_alloc() const {
- assert(init_complete);
+ assert(is_ready());
return get_alloc_tail_target() > journal_alloc_tail;
}
/**
*/
bool gc_should_run() const {
if (disable_trim) return false;
- ceph_assert(init_complete);
+ ceph_assert(is_ready());
return gc_should_reclaim_space()
|| gc_should_trim_dirty()
|| gc_should_trim_alloc();
segment_type_t s_type,
data_category_t category,
reclaim_gen_t generation) {
- ceph_assert(!init_complete);
+ ceph_assert(state == cleaner_state_t::MOUNT);
auto old_usage = calc_utilization(segment);
segments.init_closed(segment, seq, s_type, category, generation);
auto new_usage = calc_utilization(segment);
init_managers();
return transaction_manager->mkfs();
}).safe_then([this] {
+ init_managers();
return transaction_manager->mount();
}).safe_then([this] {
return repeat_eagain([this] {
void SeaStore::init_managers()
{
- ceph_assert(!transaction_manager);
- ceph_assert(!collection_manager);
- ceph_assert(!onode_manager);
+ transaction_manager.reset();
+ collection_manager.reset();
+ onode_manager.reset();
+
std::vector<Device*> sec_devices;
for (auto &dev : secondaries) {
sec_devices.emplace_back(dev.get());
return lba_manager->init_cached_extent(t, e);
}
}).si_then([this, &t] {
- assert(async_cleaner->debug_check_space(
- *async_cleaner->get_empty_space_tracker()));
+ async_cleaner->start_scan_space();
return backref_manager->scan_mapped_space(
t,
[this](
assert(laddr == L_ADDR_NULL);
backref_manager->cache_new_backref_extent(paddr, type);
cache->update_tree_extents_num(type, 1);
- async_cleaner->mark_space_used(paddr, len, true);
+ async_cleaner->mark_space_used(paddr, len);
} else if (laddr == L_ADDR_NULL) {
cache->update_tree_extents_num(type, -1);
- async_cleaner->mark_space_free(paddr, len, true);
+ async_cleaner->mark_space_free(paddr, len);
} else {
cache->update_tree_extents_num(type, 1);
- async_cleaner->mark_space_used(paddr, len, true);
+ async_cleaner->mark_space_used(paddr, len);
}
});
});
}).safe_then([this] {
return epm->open();
}).safe_then([FNAME, this] {
- async_cleaner->complete_init();
+ async_cleaner->start_gc();
INFO("completed");
}).handle_error(
mount_ertr::pass_further{},