diff --git a/src/v/cloud_storage/cache_service.cc b/src/v/cloud_storage/cache_service.cc index b676386c5c8c1..d253097bec318 100644 --- a/src/v/cloud_storage/cache_service.cc +++ b/src/v/cloud_storage/cache_service.cc @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -36,6 +37,11 @@ using namespace std::chrono_literals; +namespace { +// Matches log segments optionally containing a numeric term suffix +const re2::RE2 segment_expr{R"#(.*\.log(\.\d+)?)#"}; +} // namespace + namespace cloud_storage { static constexpr auto access_timer_period = 60s; @@ -568,7 +574,7 @@ ss::future cache::trim_fast( std::optional tx_file; std::optional index_file; - if (std::string_view(file_stat.path).ends_with(".log")) { + if (RE2::FullMatch(file_stat.path.data(), segment_expr)) { // If this was a legacy whole-segment item, delete the index // and tx file along with the segment tx_file = fmt::format("{}.tx", file_stat.path); diff --git a/src/v/cloud_storage/tests/cache_test.cc b/src/v/cloud_storage/tests/cache_test.cc index 71ea2526565f3..fa84f4eb6ee9d 100644 --- a/src/v/cloud_storage/tests/cache_test.cc +++ b/src/v/cloud_storage/tests/cache_test.cc @@ -500,3 +500,41 @@ FIXTURE_TEST(test_exhaustive_trim_runs_after_fast_trim, cache_test_fixture) { return !std::filesystem::exists(path); })); } + +FIXTURE_TEST(test_log_segment_cleanup, cache_test_fixture) { + std::vector objects{ + CACHE_DIR / "test.log.1", + CACHE_DIR / "test.log.1.index", + CACHE_DIR / "test.log.1.tx", + CACHE_DIR / "test.log", + CACHE_DIR / "test.log.index", + CACHE_DIR / "test.log.tx"}; + for (const auto& obj : objects) { + std::ofstream f{obj}; + f.flush(); + } + + // An un-removable file makes sure the fast trim will have to remove the two + // segment files. + { + std::ofstream f{CACHE_DIR / "accesstime"}; + f.flush(); + } + + BOOST_REQUIRE( + std::all_of(objects.cbegin(), objects.cend(), [](const auto& path) { + return std::filesystem::exists(path); + })); + + clean_up_at_start().get(); + + // With this limit all of the index+tx files should not have to be removed, + // but fast trim will remove all of these files after removing the two + // segments. + trim_cache(std::nullopt, 4); + + BOOST_REQUIRE( + std::all_of(objects.cbegin(), objects.cend(), [](const auto& path) { + return !std::filesystem::exists(path); + })); +}