co-maps/libs/storage/pinger.cpp
2025-11-22 13:58:55 +01:00

70 lines
1.8 KiB
C++

#include "storage/pinger.hpp"
#include "platform/http_client.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/thread_pool_delayed.hpp"
#include <chrono>
namespace pinger
{
auto constexpr kTimeoutInSeconds = 4.0;
int64_t constexpr kInvalidPing = -1;
int64_t DoPing(std::string const & url)
{
using namespace std::chrono;
if (url.empty())
{
ASSERT(false, ("Metaserver returned an empty url."));
return kInvalidPing;
}
LOG(LDEBUG, ("Pinging server", url));
platform::HttpClient request(url);
request.SetHttpMethod("HEAD");
request.SetTimeout(kTimeoutInSeconds);
auto const begin = high_resolution_clock::now();
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
{
return duration_cast<milliseconds>(high_resolution_clock::now() - begin).count();
}
else
{
LOG(LWARNING, ("Ping to server", url, "failed with code =", request.ErrorCode(),
"; wasRedirected =", request.WasRedirected()));
}
return kInvalidPing;
}
} // namespace pinger
namespace storage
{
// static
Pinger::Endpoints Pinger::ExcludeUnavailableAndSortEndpoints(Endpoints const & urls)
{
auto const size = urls.size();
CHECK_GREATER(size, 0, ());
using EntryT = std::pair<int64_t, size_t>;
std::vector<EntryT> timeUrls(size, {pinger::kInvalidPing, 0});
{
base::DelayedThreadPool pool(size, base::DelayedThreadPool::Exit::ExecPending);
for (size_t i = 0; i < size; ++i)
pool.Push([&urls, &timeUrls, i] { timeUrls[i] = {pinger::DoPing(urls[i]), i}; });
}
std::sort(timeUrls.begin(), timeUrls.end(), [](EntryT const & e1, EntryT const & e2) { return e1.first < e2.first; });
Endpoints readyUrls;
for (auto const & [ping, index] : timeUrls)
if (ping >= 0)
readyUrls.push_back(urls[index]);
return readyUrls;
}
} // namespace storage