mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 07:23:53 +01:00
ircd::net::dns::resolver: Improve timeout cycle; avoid false positives under load.
This commit is contained in:
parent
27d0c25f9b
commit
04f6e9692a
2 changed files with 52 additions and 15 deletions
|
@ -46,6 +46,7 @@ struct ircd::net::dns::resolver
|
|||
steady_point send_last; // Time of last send
|
||||
std::deque<uint16_t> sendq; // Queue of frames for rate-limiting
|
||||
ip::udp::socket ns; // A pollable activity object
|
||||
bool recv_idle {false}; // Timeout worker won't run if false
|
||||
|
||||
// util
|
||||
void add_server(const ipport &);
|
||||
|
@ -67,6 +68,7 @@ struct ircd::net::dns::resolver
|
|||
void handle_reply(const header &, const const_buffer &body, tag &);
|
||||
void handle_reply(const ipport &, const header &, const const_buffer &body);
|
||||
void handle(const ipport &, const mutable_buffer &);
|
||||
void handle_interrupt(ctx::ctx *const &) noexcept;
|
||||
std::tuple<net::ipport, mutable_buffer> recv_recv(const mutable_buffer &);
|
||||
void recv_worker();
|
||||
ctx::context recv_context;
|
||||
|
|
|
@ -286,9 +286,12 @@ ircd::net::dns::resolver::timeout_worker()
|
|||
{
|
||||
while(1)
|
||||
{
|
||||
// Dock here until somebody submits a request into the tag map. Also
|
||||
// wait until recv_idle is asserted which indicates the UDP queue has
|
||||
// been exhausted.
|
||||
dock.wait([this]
|
||||
{
|
||||
return !tags.empty();
|
||||
return !tags.empty() && recv_idle;
|
||||
});
|
||||
|
||||
check_timeouts(milliseconds(timeout));
|
||||
|
@ -526,37 +529,69 @@ catch(const std::exception &e)
|
|||
std::tuple<ircd::net::ipport, ircd::mutable_buffer>
|
||||
ircd::net::dns::resolver::recv_recv(const mutable_buffer &buf)
|
||||
{
|
||||
static const ip::udp::socket::message_flags flags
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
const asio::mutable_buffers_1 bufs
|
||||
{
|
||||
buf
|
||||
};
|
||||
|
||||
const auto interruption{[this](ctx::ctx *const &)
|
||||
{
|
||||
if(this->ns.is_open())
|
||||
this->ns.cancel();
|
||||
}};
|
||||
|
||||
// First try a non-blocking receive to find and return anything in the
|
||||
// queue. If this comes back as -EAGAIN we'll assert recv_idle and then
|
||||
// conduct the normal blocking receive.
|
||||
boost::system::error_code ec;
|
||||
ip::udp::endpoint ep;
|
||||
size_t recv; continuation
|
||||
size_t recv
|
||||
{
|
||||
continuation::asio_predicate, interruption, [this, &bufs, &recv, &ep]
|
||||
(auto &yield)
|
||||
{
|
||||
recv = ns.async_receive_from(bufs, ep, yield);
|
||||
}
|
||||
ns.receive_from(bufs, ep, flags, ec)
|
||||
};
|
||||
|
||||
assert(!ec || recv == 0);
|
||||
assert(!ec || ec == boost::system::errc::resource_unavailable_try_again);
|
||||
|
||||
// branch on any ec, not just -EAGAIN; this time it can throw...
|
||||
if(likely(ec))
|
||||
{
|
||||
const scope_restore recv_idle
|
||||
{
|
||||
this->recv_idle, true
|
||||
};
|
||||
|
||||
const auto interruption
|
||||
{
|
||||
std::bind(&resolver::handle_interrupt, this, ph::_1)
|
||||
};
|
||||
|
||||
continuation
|
||||
{
|
||||
continuation::asio_predicate, interruption, [this, &bufs, &recv, &ep]
|
||||
(auto &yield)
|
||||
{
|
||||
recv = ns.async_receive_from(bufs, ep, yield);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return
|
||||
{
|
||||
make_ipport(ep),
|
||||
mutable_buffer
|
||||
make_ipport(ep), mutable_buffer
|
||||
{
|
||||
data(buf), recv
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::resolver::handle_interrupt(ctx::ctx *const &interruptor)
|
||||
noexcept
|
||||
{
|
||||
if(!ns.is_open())
|
||||
ns.cancel();
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::resolver::handle(const ipport &from,
|
||||
const mutable_buffer &buf)
|
||||
|
|
Loading…
Reference in a new issue