db/hints: Handle arbitrary directories in resource manager

Before these changes, resource manager only handled
the case when directories it browsed represented
valid host IDs. However, since before migrating
hinted handoff to using host IDs we still name
directories after IP addresses, that would lead
to exceptins that shouldn't happen.

We make resource manager handle directories
of arbitrary names correctly.
This commit is contained in:
Dawid Medrek
2024-03-22 15:30:17 +01:00
parent ee84e810ca
commit 58784cd8db
4 changed files with 53 additions and 19 deletions

View File

@@ -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();

View File

@@ -133,7 +133,16 @@ private:
hint_stats _stats;
seastar::metrics::metric_groups _metrics;
std::unordered_set<endpoint_id> _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<std::variant<locator::host_id, gms::inet_address>> _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<locator::host_id, gms::inet_address>& 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<locator::host_id, gms::inet_address>& key) const {
return _eps_with_pending_hints.contains(key);
}

View File

@@ -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 <boost/range/algorithm/for_each.hpp>
@@ -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<std::variant<locator::host_id, gms::inet_address>> 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<directory_entry_type::regular>(),
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<std::variant<locator::host_id, gms::inet_address>> {
try {
const auto hid_or_ep = locator::host_id_or_endpoint{de.name};
if (hid_or_ep.has_host_id()) {
return std::variant<locator::host_id, gms::inet_address>(hid_or_ep.id());
} else {
return std::variant<locator::host_id, gms::inet_address>(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();
}

View File

@@ -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<std::variant<locator::host_id, gms::inet_address>> maybe_ep_key);
};
class resource_manager {