Continue name resolution fixing, add unit test
name_lookup() now returns all results given by getnameinfo(). When searching for a server, finding one matching address in the lookup-results is enough for a match. Also, added a test for name_lookup(). The test is minimal on its own, as hardcoded test cases are not generally valid.
This commit is contained in:
@ -1005,34 +1005,32 @@ bool MariaDBMonitor::is_candidate_valid(MariaDBServer* cand, RequireRunning req_
|
||||
return is_valid;
|
||||
};
|
||||
|
||||
string MariaDBMonitor::DNSResolver::resolve_server(const string& host)
|
||||
MariaDBMonitor::DNSResolver::StringSet MariaDBMonitor::DNSResolver::resolve_server(const string& host)
|
||||
{
|
||||
auto now = mxb::Clock::now();
|
||||
const auto MAX_AGE = mxb::Duration((double)5*60); // Refresh interval for cache entries.
|
||||
auto recent_time = now - MAX_AGE;
|
||||
DNSResolver::StringSet rval;
|
||||
|
||||
string rval;
|
||||
auto iter = m_mapping.find(host);
|
||||
|
||||
if (iter == m_mapping.end() || iter->second.timestamp < recent_time)
|
||||
{
|
||||
// Map did not have a record, or it was too old. In either case, generate a new one.
|
||||
string addr;
|
||||
DNSResolver::StringSet addresses;
|
||||
string error_msg;
|
||||
bool dns_success = mxb::name_lookup(host, &addr, &error_msg);
|
||||
bool dns_success = mxb::name_lookup(host, &addresses, &error_msg);
|
||||
if (!dns_success)
|
||||
{
|
||||
MXB_ERROR("Could not resolve host '%s'. %s", host.c_str(), error_msg.c_str());
|
||||
}
|
||||
// If dns failed, addr will be empty. Add the element anyway to prevent repeated lookups.
|
||||
MapElement newelem = {addr, now};
|
||||
m_mapping[host] = newelem;
|
||||
rval = addr;
|
||||
// If dns failed, the array will be empty. Add/replace the element anyway to prevent repeated lookups.
|
||||
m_mapping[host] = {addresses, now};
|
||||
rval = std::move(addresses);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return recent value.
|
||||
rval = iter->second.address;
|
||||
rval = iter->second.addresses;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
@ -124,21 +124,27 @@ MariaDBServer* MariaDBMonitor::get_server(const EndPoint& search_ep)
|
||||
{
|
||||
// Phase 2: Was not found with simple string compare. Try DNS resolving for endpoints with
|
||||
// matching ports.
|
||||
string target_addr = m_resolver.resolve_server(search_ep.host());
|
||||
if (!target_addr.empty())
|
||||
DNSResolver::StringSet target_addresses = m_resolver.resolve_server(search_ep.host());
|
||||
if (!target_addresses.empty())
|
||||
{
|
||||
for (auto server : m_servers)
|
||||
{
|
||||
if (server->m_server_base->server->port == search_ep.port())
|
||||
SERVER* srv = server->m_server_base->server;
|
||||
if (srv->port == search_ep.port())
|
||||
{
|
||||
string server_addr = m_resolver.resolve_server(server->m_server_base->server->address);
|
||||
if (server_addr == target_addr)
|
||||
auto server_addresses = m_resolver.resolve_server(srv->address);
|
||||
// The number of elements in the arrays is rarely over 1.
|
||||
for (auto& address : server_addresses)
|
||||
{
|
||||
found = server;
|
||||
break;
|
||||
if (target_addresses.count(address) > 0)
|
||||
{
|
||||
found = server;
|
||||
goto breakout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakout:;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
|
@ -172,12 +172,13 @@ private:
|
||||
class DNSResolver
|
||||
{
|
||||
public:
|
||||
std::string resolve_server(const std::string& host);
|
||||
using StringSet = std::unordered_set<std::string>;
|
||||
StringSet resolve_server(const std::string& host);
|
||||
|
||||
private:
|
||||
struct MapElement
|
||||
{
|
||||
std::string address;
|
||||
StringSet addresses; // A hostname can map to multiple addresses
|
||||
mxb::TimePoint timestamp;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user