From: Zhang Song Date: Wed, 3 Sep 2025 08:10:54 +0000 (+0800) Subject: crimson/os/seastore: add test workload to promote/evict aggressively X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5314e38d39db000ab1a0bf84968a2e5e6d57e2d6;p=ceph.git crimson/os/seastore: add test workload to promote/evict aggressively Signed-off-by: Zhang Song Signed-off-by: Xuehan Xu --- diff --git a/src/common/options/crimson.yaml.in b/src/common/options/crimson.yaml.in index 1c7c3a18240d..1660d8fe03ac 100644 --- a/src/common/options/crimson.yaml.in +++ b/src/common/options/crimson.yaml.in @@ -154,6 +154,13 @@ options: desc: CPU cores on which POSIX threads alienized to seastar will run in cpuset(7) format flags: - startup +- name: seastore_logical_bucket_cache_test_stress + type: bool + level: dev + desc: Enable SeaStore Logical Bucket Cache stress mode. When enabled, SeaStore exercises cold-tier + cache paths by forcing promotion/demotion activity and probabilistic write-through behavior. + Intended for testing only. + default: false # Seastore options @@ -393,3 +400,18 @@ options: level: dev desc: Select write through policy when data length is greater than this value. default: 512_K +- name: seastore_test_workload_write_through_probability + type: float + level: dev + desc: The percentage of writes that are applied directly to slow devices + default: 0.5 +- name: seastore_test_workload_2Q_promote_probability + type: float + level: dev + desc: The probability of promoting the extents evicted from the warm_in queue to faster devices + default: 0.5 +- name: seastore_test_workload_force_process_background_tasks_period + type: uint + level: dev + desc: Seconds of the period to force process background tasks + default: 5 diff --git a/src/crimson/os/seastore/async_cleaner.cc b/src/crimson/os/seastore/async_cleaner.cc index d630a84b494a..9d515e13cd9b 100644 --- a/src/crimson/os/seastore/async_cleaner.cc +++ b/src/crimson/os/seastore/async_cleaner.cc @@ -603,10 +603,10 @@ std::size_t JournalTrimmerImpl::get_alloc_journal_size() const return static_cast(ret); } -seastar::future<> JournalTrimmerImpl::trim() { +seastar::future<> JournalTrimmerImpl::trim(bool force) { return seastar::when_all( - [this] { - if (should_trim_alloc()) { + [this, force] { + if (force || should_trim_alloc()) { return trim_alloc( ).handle_error( crimson::ct_error::assert_all( @@ -617,8 +617,8 @@ seastar::future<> JournalTrimmerImpl::trim() { return seastar::now(); } }, - [this] { - if (should_start_trim_dirty()) { + [this, force] { + if (force || should_start_trim_dirty()) { return trim_dirty( ).handle_error( crimson::ct_error::assert_all( diff --git a/src/crimson/os/seastore/async_cleaner.h b/src/crimson/os/seastore/async_cleaner.h index 3e1ee3e993c2..59f0311a72b2 100644 --- a/src/crimson/os/seastore/async_cleaner.h +++ b/src/crimson/os/seastore/async_cleaner.h @@ -375,6 +375,10 @@ public: Transaction &t, CachedExtentRef extent) = 0; + virtual promote_extent_ret promote_extents_from_disk( + Transaction &t, + paddr_t paddr) = 0; + /** * demote_region * @@ -666,7 +670,7 @@ public: reserved_usage -= usage; } - seastar::future<> trim(); + seastar::future<> trim(bool force); static JournalTrimmerImplRef create( store_index_t store_index, diff --git a/src/crimson/os/seastore/backref/btree_backref_manager.cc b/src/crimson/os/seastore/backref/btree_backref_manager.cc index e049d43362a8..2190d0327b86 100644 --- a/src/crimson/os/seastore/backref/btree_backref_manager.cc +++ b/src/crimson/os/seastore/backref/btree_backref_manager.cc @@ -1,6 +1,7 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- // vim: ts=8 sw=2 sts=2 expandtab +#include "crimson/common/coroutine.h" #include "crimson/os/seastore/backref/btree_backref_manager.h" SET_SUBSYS(seastore_backref); @@ -456,6 +457,50 @@ BtreeBackrefManager::scan_mapped_space( }); } +BtreeBackrefManager::scan_device_ret +BtreeBackrefManager::scan_device( + Transaction &t, + paddr_t paddr, + scan_device_func_t &f) +{ + LOG_PREFIX(BtreeBackrefManager::scan_device); + auto c = get_context(t); + auto croot = co_await cache.get_root(t); + auto btree = BackrefBtree(croot); + auto iter = co_await btree.lower_bound(c, paddr); + while (!iter.is_end()) { + auto key = iter.get_key(); + auto bentry = cache.get_cached_backref_entry(key); + if (bentry) { + assert(bentry->paddr == key); + DEBUGT("found in cache: {} {}", t, bentry->paddr, bentry->laddr); + } + if (bentry && bentry->laddr == L_ADDR_NULL) { + DEBUGT("{} is removed", t, bentry->paddr); + iter = co_await iter.next(c); + continue; + } + if (key.get_device_id() == paddr.get_device_id()) { + auto val = iter.get_val(); + if (bentry && bentry->laddr != val.laddr) { + DEBUGT("{} changed from {} to {}", + t, bentry->paddr, val.laddr, bentry->laddr); + iter = co_await iter.next(c); + continue; + } + DEBUGT("scanned {}, {}", t, key, val.laddr); + auto ret = co_await f(key, val.len, val.type, val.laddr); + if (ret == seastar::stop_iteration::yes) { + break; + } + } else if (key.get_device_id() > paddr.get_device_id()) { + break; + } + iter = co_await iter.next(c); + } + co_return; +} + base_iertr::future<> _init_cached_extent( op_context_t c, const CachedExtentRef &e, diff --git a/src/crimson/os/seastore/backref/btree_backref_manager.h b/src/crimson/os/seastore/backref/btree_backref_manager.h index b8b69af77d96..28d89afdc0c5 100644 --- a/src/crimson/os/seastore/backref/btree_backref_manager.h +++ b/src/crimson/os/seastore/backref/btree_backref_manager.h @@ -55,6 +55,11 @@ public: Transaction &t, scan_mapped_space_func_t &&f) final; + scan_device_ret scan_device( + Transaction &t, + paddr_t paddr, + scan_device_func_t &f) final; + init_cached_extent_ret init_cached_extent( Transaction &t, CachedExtentRef e) final; diff --git a/src/crimson/os/seastore/backref_manager.h b/src/crimson/os/seastore/backref_manager.h index 6b6f16761896..b2314e5e7895 100644 --- a/src/crimson/os/seastore/backref_manager.h +++ b/src/crimson/os/seastore/backref_manager.h @@ -139,6 +139,15 @@ public: Transaction &t, scan_mapped_space_func_t &&f) = 0; + using scan_device_ret = base_iertr::future<>; + using scan_device_func_t = std::function< + base_iertr::future( + paddr_t, extent_len_t, extent_types_t, laddr_t)>; + virtual scan_device_ret scan_device( + Transaction &t, + paddr_t start, + scan_device_func_t &f) = 0; + virtual ~BackrefManager() {} }; diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index 4208d899efbd..7c7d44d32ed2 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -36,6 +36,8 @@ Cache::Cache( delta_based_overwrite_enabled( crimson::common::get_conf( "seastore_data_delta_based_overwrite") > 0), + force_backref(crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress")), pinboard(create_extent_pinboard( crimson::common::get_conf( "seastore_cachepin_size_pershard"), diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index b33d8d59d1b5..d92e42802b3f 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -758,7 +758,7 @@ public: } bool can_drop_backref() const { - return epm.is_pure_rbm(); + return epm.is_pure_rbm() && !force_backref; } void update_read_ratio(Transaction &t) { @@ -1076,6 +1076,24 @@ private: return res; } + std::optional get_cached_backref_entry(paddr_t addr) { + auto it = backref_entry_mset.lower_bound( + addr, + backref_entry_t::cmp_t()); + if (it == backref_entry_mset.end()) { + return std::nullopt; + } + while (it->paddr == addr) { + auto &backref_entry = *it; + ++it; + if (it == backref_entry_mset.end() || + it->paddr != addr) { + return backref_entry; + } + } + return std::nullopt; + } + const backref_entry_mset_t& get_backref_entry_mset() { return backref_entry_mset; } @@ -1741,6 +1759,8 @@ private: transaction_id_t next_id = 0; + const bool force_backref = false; + /** * dirty * diff --git a/src/crimson/os/seastore/cached_extent.cc b/src/crimson/os/seastore/cached_extent.cc index 4854bc8055f4..70e9e1010351 100644 --- a/src/crimson/os/seastore/cached_extent.cc +++ b/src/crimson/os/seastore/cached_extent.cc @@ -415,8 +415,12 @@ void ExtentCommitter::commit_state() { prior.last_committed_crc = extent.last_committed_crc; prior.dirty_from = extent.dirty_from; prior.length = extent.length; - prior.loaded_length = extent.loaded_length; - prior.buffer_space = std::move(extent.buffer_space); + // XXX: at present, zero loaded_length extents here + // must have been created by promoting/demoting them. + if (likely(extent.loaded_length != 0)) { + assert(prior.loaded_length == extent.loaded_length); + prior.buffer_space = std::move(extent.buffer_space); + } // XXX: We can go ahead and change the prior's version because // transactions don't hold a local view of the version field, // unlike FixedKVLeafNode::modifications diff --git a/src/crimson/os/seastore/extent_pinboard.cc b/src/crimson/os/seastore/extent_pinboard.cc index e03ffbf618f8..e149d3b0bad0 100644 --- a/src/crimson/os/seastore/extent_pinboard.cc +++ b/src/crimson/os/seastore/extent_pinboard.cc @@ -269,8 +269,14 @@ void ExtentQueue::get_stats( class ExtentPromoter { public: - ExtentPromoter(size_t promotion_size, ExtentPlacementManager &epm) - : promotion_size(promotion_size), epm(epm) {} + ExtentPromoter( + size_t promotion_size, + ExtentPlacementManager &epm) + : promotion_size(promotion_size), + epm(epm), + test_workload(crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress")) + {} ~ExtentPromoter() { clear(); @@ -285,7 +291,13 @@ public: } size_t get_promotion_size() const { - return current_contents; + if (unlikely(test_workload)) { + return current_contents >= promotion_size + ? current_contents + : promotion_size; + } else { + return current_contents; + } } void set_background_callback(BackgroundListener *l) { @@ -297,7 +309,9 @@ public: } bool should_run_promote() const { - return enabled() && current_contents >= promotion_size; + return enabled() && + (current_contents >= promotion_size + || test_workload); } std::size_t get_promoted_size() const { @@ -348,32 +362,49 @@ public: LOG_PREFIX(ExtentPromoter::run_promote); std::size_t promote_size = 0; DEBUGT("start promote", t); - std::list extents; - for (auto &extent : list) { - DEBUGT("promote {} to the hot tier", t, extent); - ceph_assert(extent.is_stable_clean()); - ceph_assert(extent.get_pin_state() == extent_pin_state_t::PendingPromote); - extents.emplace_back(&extent); - } - for (auto &extent : extents) { - remove_extent(*extent, extent_pin_state_t::Fresh); - } - promoting_extents.insert( - promoting_extents.end(), - extents.begin(), - extents.end()); - for (auto it = promoting_extents.begin(); - it != promoting_extents.end();) { - auto &extent = *it; - if (!extent->is_valid()) { - it = promoting_extents.erase(it); - continue; + if (unlikely(test_workload && + current_contents < promotion_size && + // if promoting_extents is not empty, it means the last + // round of promotion was not a test workload and was + // interrupted, so this round shouldn't be a test workload + // too. + promoting_extents.empty())) { + auto id = epm.get_cold_device_id(); + paddr_t start = P_ADDR_NULL; + if (device_id_to_paddr_type(id) == paddr_types_t::SEGMENT) { + start = paddr_t::make_seg_paddr(id, 0, 0); + } else { + start = paddr_t::make_blk_paddr(id, 0); + } + co_await ecb->promote_extents_from_disk(t, start); + } else { + std::list extents; + for (auto &extent : list) { + DEBUGT("promote {} to the hot tier", t, extent); + ceph_assert(extent.is_stable_clean()); + ceph_assert(extent.get_pin_state() == extent_pin_state_t::PendingPromote); + extents.emplace_back(&extent); + } + for (auto &extent : extents) { + remove_extent(*extent, extent_pin_state_t::Fresh); + } + promoting_extents.insert( + promoting_extents.end(), + extents.begin(), + extents.end()); + for (auto it = promoting_extents.begin(); + it != promoting_extents.end();) { + auto &extent = *it; + if (!extent->is_valid()) { + it = promoting_extents.erase(it); + continue; + } + promote_size += extent->get_length(); + t.add_to_read_set(extent); + co_await trans_intr::make_interruptible(extent->wait_io()); + co_await ecb->promote_extent(t, extent); + it++; } - promote_size += extent->get_length(); - t.add_to_read_set(extent); - co_await trans_intr::make_interruptible(extent->wait_io()); - co_await ecb->promote_extent(t, extent); - it++; } // existing extents in lru will be retired after transaction submitted co_await ecb->submit_transaction_direct(t); @@ -407,6 +438,7 @@ private: size_t promoted_count = 0; size_t promoted_size = 0; + bool test_workload = false; }; class ExtentPinboardLRU : public ExtentPinboard { @@ -706,7 +738,11 @@ public: : warm_in(warm_in_capacity), warm_out(warm_out_capacity), hot(hot_capacity), - promoter(promotion_size, epm) + promoter(promotion_size, epm), + test_workload(crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress")), + TwoQ_promote_probability(crimson::common::get_conf( + "seastore_test_workload_2Q_promote_probability")) { LOG_PREFIX(ExtentPinboardTwoQ::ExtentPinboardTwoQ); INFO("created, warm_in_capacity=0x{:x}B, warm_out_capacity=0x{:x}B, " @@ -889,6 +925,12 @@ private: // to the warm out queue. continue; } + if (promoter.should_promote_extent(*extent) + && test_workload + && (double(std::rand() % 100) / 100.0) <= TwoQ_promote_probability) { + promoter.add_extent(*extent); + continue; + } auto lext = extent->cast(); auto laddr = lext->get_laddr(); auto end = extent->get_last_touch_end(); @@ -975,6 +1017,8 @@ private: // hit and miss indicates if an extent is linked when touching it uint64_t hit = 0; uint64_t miss = 0; + bool test_workload = false; + double TwoQ_promote_probability = 0; }; void ExtentPinboardTwoQ::get_stats( diff --git a/src/crimson/os/seastore/extent_placement_manager.cc b/src/crimson/os/seastore/extent_placement_manager.cc index 24c1e9d848ca..7ece18312ab9 100644 --- a/src/crimson/os/seastore/extent_placement_manager.cc +++ b/src/crimson/os/seastore/extent_placement_manager.cc @@ -1,6 +1,9 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- // vim: ts=8 sw=2 sts=2 expandtab expandtab +#include +#include + #include "crimson/os/seastore/extent_placement_manager.h" #include "crimson/common/errorator-utils.h" @@ -882,7 +885,8 @@ ExtentPlacementManager::BackgroundProcess::run() { assert(is_running()); while (is_running()) { - if (background_should_run()) { + if (background_should_run() + || force_run_background()) { log_state("run(background)"); co_await do_background_cycle(); // Edge-triggered: yield only when a blocked IO was actually woken, so the @@ -898,9 +902,13 @@ ExtentPlacementManager::BackgroundProcess::run() if (cold_cleaner) { cold_cleaner->maybe_adjust_thresholds(); } + maybe_reschedule_force_process(); } else { log_state("run(block)"); assert(!blocking_background); + if (unlikely(test_workload)) { + set_next_force_process(); + } blocking_background = seastar::promise<>(); co_await blocking_background->get_future(); // After waking (typically because arm_blocking_io_and_wake() kicked us), @@ -1042,12 +1050,24 @@ ExtentPlacementManager::BackgroundProcess::do_background_cycle() } } + bool force_trim = false; + bool should_abort_cleaner_usage = true; + if (unlikely(should_force_trim())) { + if (!proceed_trim) { + should_abort_cleaner_usage = false; + } + proceed_trim = true; + force_trim = true; + } + if (proceed_trim) { DEBUG("started trimming..."); - return trimmer->trim( - ).finally([this, trim_usage, FNAME] { + return trimmer->trim(force_trim + ).finally([this, trim_usage, should_abort_cleaner_usage, FNAME] { DEBUG("finished trimming"); - abort_cleaner_usage(trim_usage, {true, true}); + if (should_abort_cleaner_usage) { + abort_cleaner_usage(trim_usage, {true, true}); + } }); } else { assert(!proceed_trim); @@ -1082,11 +1102,25 @@ ExtentPlacementManager::BackgroundProcess::do_background_cycle() proceed_demote = true; } + bool abort_cold_cleaner_usage = true; + if (unlikely(should_force_clean())) { + if (!proceed_clean_main) { + abort_cold_cleaner_usage = false; + } + proceed_clean_main = main_cleaner->can_clean_space(); + if (has_cold_tier()) { + proceed_clean_cold = cold_cleaner->can_clean_space(); + } + if (logical_bucket) { + proceed_demote = logical_bucket->could_demote(); + } + } + if (!proceed_clean_main && !proceed_clean_cold && !proceed_demote) { ceph_abort_msg("no background process will start"); } return seastar::when_all( - [this, FNAME, proceed_clean_main, + [this, FNAME, proceed_clean_main, abort_cold_cleaner_usage, should_clean_main_for_trim, main_cold_usage] { if (!proceed_clean_main) { return seastar::now(); @@ -1101,9 +1135,11 @@ ExtentPlacementManager::BackgroundProcess::do_background_cycle() crimson::ct_error::assert_all( "do_background_cycle encountered invalid error in main clean_space" ) - ).finally([this, main_cold_usage, FNAME] { + ).finally([this, main_cold_usage, abort_cold_cleaner_usage, FNAME] { DEBUG("finished clean main"); - abort_cold_usage(main_cold_usage, true); + if (abort_cold_cleaner_usage) { + abort_cold_usage(main_cold_usage, true); + } }); }, [this, FNAME, proceed_clean_cold, @@ -1163,6 +1199,12 @@ seastar::future<> ExtentPlacementManager::BackgroundProcess::run_promote() ceph_assert(!blocking_promote); blocking_promote = seastar::promise<>(); return blocking_promote->get_future(); + }).then([this] { + if (unlikely(test_workload)) { + return seastar::sleep(std::chrono::seconds( + force_process_half_life)); + } + return seastar::now(); }).then([] { return seastar::stop_iteration::no; }); diff --git a/src/crimson/os/seastore/extent_placement_manager.h b/src/crimson/os/seastore/extent_placement_manager.h index 5cea7b0ccbf2..11463df8fb33 100644 --- a/src/crimson/os/seastore/extent_placement_manager.h +++ b/src/crimson/os/seastore/extent_placement_manager.h @@ -375,7 +375,11 @@ public: max_data_allocation_size(crimson::common::get_conf( "seastore_max_data_allocation_size")), write_through_size(crimson::common::get_conf( - "seastore_write_through_size")) + "seastore_write_through_size")), + test_workload(crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress")), + write_through_probability(crimson::common::get_conf( + "seastore_test_workload_write_through_probability")) { LOG_PREFIX(ExtentPlacementManager::ExtentPlacementManager); devices_by_id.resize(DEVICE_ID_MAX, nullptr); @@ -557,8 +561,14 @@ public: } write_policy_t get_write_policy(extent_types_t type, extent_len_t length) const { - if (has_cold_tier() && length >= write_through_size && is_data_type(type)) { - return write_policy_t::WRITE_THROUGH; + if (has_cold_tier() && is_data_type(type)) { + if (length >= write_through_size + || (test_workload + && (double(std::rand() % 100) / 100.0) <= + write_through_probability)) + { + return write_policy_t::WRITE_THROUGH; + } } return write_policy_t::WRITE_BACK; } @@ -726,6 +736,10 @@ public: return hot_tier_generations - 1; } + device_id_t get_cold_device_id() const { + return background_process.get_cold_device_id(); + } + private: rewrite_gen_t adjust_generation( data_category_t category, @@ -900,6 +914,18 @@ private: get_conf("seastore_logical_bucket_proceed_size_per_cycle")); logical_bucket->set_background_callback(this); } + LOG_PREFIX(BackgroundProcess::init); + test_workload = crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress"); + force_process_half_life = crimson::common::get_conf( + "seastore_test_workload_force_process_background_tasks_period"); + force_background_timer.set_callback([this] { wake_half_life(); }); + write_through_probability = crimson::common::get_conf( + "seastore_test_workload_write_through_probability"); + SUBINFO(seastore_epm, "crimson test workload supported, enabled: {}", test_workload); + if (test_workload) { + set_next_force_process(); + } } LogicalBucket *get_logical_bucket() { @@ -1016,6 +1042,12 @@ private: } } + + device_id_t get_cold_device_id() const { + assert(has_cold_tier()); + return *cold_cleaner->get_device_ids().begin(); + } + seastar::future<> reserve_projected_usage(io_usage_t usage); void release_projected_usage(const io_usage_t &usage) { @@ -1322,6 +1354,57 @@ private: state_t state = state_t::STOP; eviction_state_t eviction_state; + enum class ForceProcessState : uint8_t{ + STOP, + TRIM, + CLEAN, + }; + bool test_workload = false; + double write_through_probability = 0; + ForceProcessState force_process_state = ForceProcessState::STOP; + ForceProcessState last_process_state = ForceProcessState::STOP; + seastar::timer force_background_timer; + int force_process_half_life; + + void set_next_force_process() { + assert(test_workload); + force_background_timer.rearm( + seastar::steady_clock_type::now() + + std::chrono::seconds(force_process_half_life)); + } + + void wake_half_life() { + assert(test_workload); + if (last_process_state == ForceProcessState::TRIM) { + force_process_state = ForceProcessState::CLEAN; + } else { + force_process_state = ForceProcessState::TRIM; + } + + do_wake_background(); + } + + void maybe_reschedule_force_process() { + if (unlikely(test_workload && + force_process_state != ForceProcessState::STOP)) { + last_process_state = force_process_state; + force_process_state = ForceProcessState::STOP; + set_next_force_process(); + } + } + + bool should_force_trim() const { + return test_workload && force_process_state == ForceProcessState::TRIM; + } + + bool should_force_clean() const { + return test_workload && force_process_state == ForceProcessState::CLEAN; + } + + bool force_run_background() const { + return test_workload && force_process_state != ForceProcessState::STOP + && (logical_bucket && logical_bucket->could_demote()); + } friend class ::transaction_manager_test_t; }; @@ -1345,6 +1428,8 @@ private: SegmentSeqAllocatorRef ool_segment_seq_allocator; extent_len_t max_data_allocation_size = 0; std::size_t write_through_size = 0; + bool test_workload = false; + double write_through_probability = 0; friend class ::transaction_manager_test_t; friend class Cache; diff --git a/src/crimson/os/seastore/seastore.cc b/src/crimson/os/seastore/seastore.cc index d8992f148e8b..e367dea437c7 100644 --- a/src/crimson/os/seastore/seastore.cc +++ b/src/crimson/os/seastore/seastore.cc @@ -728,6 +728,23 @@ Device::access_ertr::future<> SeaStore::_mkfs(uuid_d new_osd_fsid) co_await rdir.close(); } + if (sds.empty() && crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress")) { + // lbc test workload enabled while no secondary devices indicated, create one + std::string path = fmt::format("{}/block.1", root); + co_await seastar::make_directory(path); + DeviceRef sec_dev = co_await Device::make_device(path, dtype, btype); + auto p_sec_dev = sec_dev.get(); + secondaries.emplace_back(std::move(sec_dev)); + co_await p_sec_dev->start(store_shard_nums); + magic_t magic = (magic_t)std::rand(); + device_id_t id = 0x1; + sds.emplace(id, device_spec_t{magic, dtype, btype, id}); + co_await p_sec_dev->mkfs( + device_config_t::create_secondary(new_osd_fsid, id, dtype, btype, magic) + ).handle_error(crimson::ct_error::assert_all("not possible")); + co_await set_secondaries(); + } device_id_t id = 0; device_type_t d_type = device->get_device_type(); backend_type_t b_type = device->get_backend_type(); diff --git a/src/crimson/os/seastore/transaction_manager.cc b/src/crimson/os/seastore/transaction_manager.cc index dedd6060b9ed..831ef725eabd 100644 --- a/src/crimson/os/seastore/transaction_manager.cc +++ b/src/crimson/os/seastore/transaction_manager.cc @@ -1331,6 +1331,59 @@ TransactionManager::promote_extent( t, *mapping.direct_cursor, std::move(promoted_extents)); } +TransactionManager::promote_extent_ret +TransactionManager::promote_extents_from_disk( + Transaction &t, + paddr_t paddr) +{ + using scan_device_func_t = BackrefManager::scan_device_func_t; + std::size_t size = 0; + scan_device_func_t func = [this, &t, &size]( + paddr_t paddr, extent_len_t length, extent_types_t type, laddr_t laddr) + -> base_iertr::future { + if (type != extent_types_t::OBJECT_DATA_BLOCK) { + co_return seastar::stop_iteration::no; + } + auto cursor = co_await lba_manager->get_cursor(t, laddr + ).handle_error_interruptible( + crimson::ct_error::enoent::handle([](auto e) { + // Another no_conflict transaction should have removed + // the mapping between the backref retrieval and the + // lba search, ignore it. + return seastar::make_ready_future(); + }), + crimson::ct_error::pass_further_all{} + ); + if (!cursor || cursor->is_end() || + !cursor->get_paddr().is_absolute() || + !cache->is_on_cold_tier(cursor->get_paddr())) { + // the mapping has been modified and the extent is + // either removed or already on the hot tier, skip it. + co_return seastar::stop_iteration::no; + } + assert(cursor->is_direct()); + assert(!cursor->has_shadow_paddr()); + auto extent = co_await read_cursor_by_type(t, std::move(cursor), type); + if (extent->is_stable_dirty()) { + // dirty extents shouldn't be promoted as is in + // the real world + co_return seastar::stop_iteration::no; + } + auto &pinboard = *cache->get_extent_pinboard(); + pinboard.remove(*extent); + extent->set_pin_state(extent_pin_state_t::Promoting); + co_await promote_extent(t, extent); + size += length; + if (size >= crimson::common::get_conf< + Option::size_t>("seastore_cache_promotion_size")) { + co_return seastar::stop_iteration::yes; + } else { + co_return seastar::stop_iteration::no; + } + }; + co_await backref_manager->scan_device(t, paddr, func); +} + TransactionManager::rewrite_extents_ret TransactionManager::rewrite_extents( Transaction &t, std::vector &extents, @@ -1655,7 +1708,10 @@ TransactionManagerRef make_transaction_manager( store_index, *backref_manager, trimmer_config, backend_type, roll_start, roll_size, - !pure_rbm_backend); + !pure_rbm_backend + || crimson::common::get_conf( + "seastore_logical_bucket_cache_test_stress") + ); AsyncCleanerRef cleaner; JournalRef journal; diff --git a/src/crimson/os/seastore/transaction_manager.h b/src/crimson/os/seastore/transaction_manager.h index 9ffb08719a6a..f1e350afddea 100644 --- a/src/crimson/os/seastore/transaction_manager.h +++ b/src/crimson/os/seastore/transaction_manager.h @@ -964,7 +964,11 @@ public: using ExtentCallbackInterface::promote_extent_ret; promote_extent_ret promote_extent( Transaction &t, - CachedExtentRef extent); + CachedExtentRef extent) final; + + promote_extent_ret promote_extents_from_disk( + Transaction &t, + paddr_t paddr) final; using ExtentCallbackInterface::demote_region_res_t; using ExtentCallbackInterface::demote_region_ret; diff --git a/src/test/crimson/seastore/test_transaction_manager.cc b/src/test/crimson/seastore/test_transaction_manager.cc index f5b5c9f77a37..e34d003a3e07 100644 --- a/src/test/crimson/seastore/test_transaction_manager.cc +++ b/src/test/crimson/seastore/test_transaction_manager.cc @@ -922,7 +922,7 @@ struct transaction_manager_test_t : if (run_clean) { return epm->run_background_work_until_halt(); } else { - return epm->background_process.trimmer->trim(); + return epm->background_process.trimmer->trim(false); } }).handle_error( crimson::ct_error::assert_all(