diff --git a/db/hints/manager.cc b/db/hints/manager.cc index 445efff8e6..62dbe3137a 100644 --- a/db/hints/manager.cc +++ b/db/hints/manager.cc @@ -237,10 +237,9 @@ void manager::forbid_hints() { } void manager::forbid_hints_for_eps_with_pending_hints() { - manager_logger.trace("space_watchdog: Going to block hints to: {}", _eps_with_pending_hints); - - for (auto& [_, ep_man] : _ep_managers) { - if (has_ep_with_pending_hints(ep_man.end_point_key())) { + for (auto& [host_id, ep_man] : _ep_managers) { + const auto ip = *_hint_directory_manager.get_mapping(host_id); + if (has_ep_with_pending_hints(host_id) || has_ep_with_pending_hints(ip)) { ep_man.forbid_hints(); } else { ep_man.allow_hints(); diff --git a/db/hints/manager.hh b/db/hints/manager.hh index 7740565390..97827351bf 100644 --- a/db/hints/manager.hh +++ b/db/hints/manager.hh @@ -133,7 +133,16 @@ private: hint_stats _stats; seastar::metrics::metric_groups _metrics; - std::unordered_set _eps_with_pending_hints; + + // We need to keep a variant here. Before migrating hinted handoff to using host ID, hint directories will + // still represent IP addresses. But after the migration, they will start representing host IDs. + // We need to handle either case. + // + // It's especially important when dealing with the scenario when there is an IP directory, but there is + // no mapping for in locator::token_metadata. Since we sometimes have to save a directory like that + // in this set as well, this variant is necessary. + std::unordered_set> _eps_with_pending_hints; + seastar::named_semaphore _drain_lock = {1, named_semaphore_exception_factory{"drain lock"}}; // For now, this never changes. @@ -227,7 +236,7 @@ public: return it->second.hints_in_progress(); } - void add_ep_with_pending_hints(endpoint_id key) { + void add_ep_with_pending_hints(const std::variant& key) { _eps_with_pending_hints.insert(key); } @@ -236,7 +245,7 @@ public: _eps_with_pending_hints.reserve(_ep_managers.size()); } - bool has_ep_with_pending_hints(endpoint_id key) const { + bool has_ep_with_pending_hints(const std::variant& key) const { return _eps_with_pending_hints.contains(key); } diff --git a/db/hints/resource_manager.cc b/db/hints/resource_manager.cc index f9c6cc08c9..2ef6da8dbe 100644 --- a/db/hints/resource_manager.cc +++ b/db/hints/resource_manager.cc @@ -7,6 +7,8 @@ */ #include "resource_manager.hh" +#include "gms/inet_address.hh" +#include "locator/token_metadata.hh" #include "manager.hh" #include "log.hh" #include @@ -91,7 +93,8 @@ future<> space_watchdog::stop() noexcept { } // Called under the end_point_hints_manager::file_update_mutex() of the corresponding end_point_hints_manager instance. -future<> space_watchdog::scan_one_ep_dir(fs::path path, manager& shard_manager, endpoint_id ep_key) { +future<> space_watchdog::scan_one_ep_dir(fs::path path, manager& shard_manager, + std::optional> maybe_ep_key) { // It may happen that we get here and the directory has already been deleted in the context of manager::drain_for(). // In this case simply bail out. if (!co_await file_exists(path.native())) { @@ -99,10 +102,10 @@ future<> space_watchdog::scan_one_ep_dir(fs::path path, manager& shard_manager, } co_await lister::scan_dir(path, lister::dir_entry_types::of(), - coroutine::lambda([this, ep_key, &shard_manager] (fs::path dir, directory_entry de) -> future<> { + coroutine::lambda([this, maybe_ep_key, &shard_manager] (fs::path dir, directory_entry de) -> future<> { // Put the current end point ID to state.eps_with_pending_hints when we see the second hints file in its directory - if (_files_count == 1) { - shard_manager.add_ep_with_pending_hints(ep_key); + if (maybe_ep_key && _files_count == 1) { + shard_manager.add_ep_with_pending_hints(*maybe_ep_key); } ++_files_count; @@ -142,14 +145,35 @@ void space_watchdog::on_timer() { // not hintable). // If exists - let's take a file update lock so that files are not changed under our feet. Otherwise, simply // continue to enumeration - there is no one to change them. - const internal::endpoint_id ep{utils::UUID{de.name}}; + auto maybe_variant = std::invoke([&] () -> std::optional> { + try { + const auto hid_or_ep = locator::host_id_or_endpoint{de.name}; + if (hid_or_ep.has_host_id()) { + return std::variant(hid_or_ep.id()); + } else { + return std::variant(hid_or_ep.endpoint()); + } + } catch (...) { + return std::nullopt; + } + }); - if (shard_manager.have_ep_manager(ep)) { - return shard_manager.with_file_update_mutex_for(ep, [this, ep, &shard_manager, dir = std::move(dir), ep_name = std::move(de.name)] () mutable { - return scan_one_ep_dir(dir / ep_name, shard_manager, ep); + // Case 1: The directory is managed by an endpoint manager. + if (maybe_variant && shard_manager.have_ep_manager(*maybe_variant)) { + const auto variant = *maybe_variant; + return shard_manager.with_file_update_mutex_for(variant, [this, variant, &shard_manager, dir = std::move(dir), ep_name = std::move(de.name)] () mutable { + return scan_one_ep_dir(dir / ep_name, shard_manager, variant); }); - } else { - return scan_one_ep_dir(dir / de.name, shard_manager, ep); + } + // Case 2: The directory isn't managed by an endpoint manager, but it represents either an IP address, + // or a host ID. + else if (maybe_variant) { + return scan_one_ep_dir(dir / de.name, shard_manager, *maybe_variant); + } + // Case 3: The directory isn't managed by an endpoint manager, and it represents neither an IP address, + // nor a host ID. + else { + return scan_one_ep_dir(dir / de.name, shard_manager, {}); } }).get(); } diff --git a/db/hints/resource_manager.hh b/db/hints/resource_manager.hh index f57a3f9407..ec154fec36 100644 --- a/db/hints/resource_manager.hh +++ b/db/hints/resource_manager.hh @@ -21,6 +21,7 @@ #include "utils/updateable_value.hh" #include "enum_set.hh" #include "db/hints/internal/common.hh" +#include "gms/inet_address.hh" // Usually we don't define namespace aliases in our headers // but this one is already entrenched. @@ -112,9 +113,10 @@ private: /// /// \param path directory to scan /// \param shard_manager the hint manager managing the directory specified by `path` - /// \param ep_key endpoint ID corresponding to the scanned directory + /// \param maybe_ep_key endpoint ID corresponding to the scanned directory /// \return future that resolves when scanning is complete - future<> scan_one_ep_dir(fs::path path, manager& shard_manager, endpoint_id ep_key); + future<> scan_one_ep_dir(fs::path path, manager& shard_manager, + std::optional> maybe_ep_key); }; class resource_manager {