From f253ae82322d2273a1c95f4423f6da373d5ff1d5 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Thu, 18 Sep 2025 15:12:04 +0200 Subject: [PATCH] dnsdist: Reduce complexity of `TCPConnectionToBackend::handleIO` Signed-off-by: Remi Gacogne --- pdns/dnsdistdist/dnsdist-tcp-downstream.cc | 155 +++++++++++---------- pdns/dnsdistdist/dnsdist-tcp-downstream.hh | 1 + 2 files changed, 81 insertions(+), 75 deletions(-) diff --git a/pdns/dnsdistdist/dnsdist-tcp-downstream.cc b/pdns/dnsdistdist/dnsdist-tcp-downstream.cc index 0e126bcf8..93bc20c32 100644 --- a/pdns/dnsdistdist/dnsdist-tcp-downstream.cc +++ b/pdns/dnsdistdist/dnsdist-tcp-downstream.cc @@ -305,6 +305,85 @@ IOState TCPConnectionToBackend::sendQuery(std::shared_ptr& conn, const struct timeval& now, IOStateGuard& ioGuard, IOState& iostate, bool& reconnected, bool& connectionDied) +{ + DEBUGLOG("connection died, number of failures is "<d_downstreamFailures<<", retries is "<d_ds->d_config.d_retries); + + if (conn->d_downstreamFailures < conn->d_ds->d_config.d_retries) { + + conn->d_ioState.reset(); + ioGuard.release(); + + try { + if (conn->reconnect()) { + conn->d_ioState = make_unique(*conn->d_mplexer, conn->d_handler->getDescriptor()); + + /* we need to resend the queries that were in flight, if any */ + if (conn->d_state == State::sendingQueryToBackend) { + /* we need to edit this query so it has the correct ID */ + auto query = std::move(conn->d_currentQuery); + uint16_t id = conn->d_highestStreamID; + prepareQueryForSending(query.d_query, id, ConnectionState::needProxy); + conn->d_currentQuery = std::move(query); + } + + /* if we notify the sender it might terminate us so we need to move these first */ + auto pendingResponses = std::move(conn->d_pendingResponses); + conn->d_pendingResponses.clear(); + for (auto& pending : pendingResponses) { + --conn->d_ds->outstanding; + + if (pending.second.d_query.isXFR() && pending.second.d_query.d_xfrStarted) { + /* this one can't be restarted, sorry */ + DEBUGLOG("A XFR for which a response has already been sent cannot be restarted"); + try { + TCPResponse response(std::move(pending.second.d_query)); + pending.second.d_sender->notifyIOError(now, std::move(response)); + } + catch (const std::exception& e) { + vinfolog("Got an exception while notifying: %s", e.what()); + } + catch (...) { + vinfolog("Got exception while notifying"); + } + } + else { + conn->d_pendingQueries.push_back(std::move(pending.second)); + } + } + conn->d_currentPos = 0; + + if (conn->d_state == State::sendingQueryToBackend) { + iostate = IOState::NeedWrite; + // resume sending query + } + else { + if (conn->d_pendingQueries.empty()) { + throw std::runtime_error("TCP connection to a backend in state " + std::to_string((int)conn->d_state) + " with no pending queries"); + } + + iostate = queueNextQuery(conn); + } + + reconnected = true; + connectionDied = false; + } + } + catch (const std::exception& e) { + // reconnect might throw on failure, let's ignore that, we just need to know + // it failed + } + } + + if (!reconnected) { + /* reconnect failed, we give up */ + DEBUGLOG("reconnect failed, we give up"); + ++conn->d_ds->tcpGaveUp; + conn->notifyAllQueriesFailed(now, FailureReason::gaveUp); + } +} + + void TCPConnectionToBackend::handleIO(std::shared_ptr& conn, const struct timeval& now) { if (conn->d_handler == nullptr) { @@ -422,81 +501,7 @@ void TCPConnectionToBackend::handleIO(std::shared_ptr& c } if (connectionDied) { - - DEBUGLOG("connection died, number of failures is "<d_downstreamFailures<<", retries is "<d_ds->d_config.d_retries); - - if (conn->d_downstreamFailures < conn->d_ds->d_config.d_retries) { - - conn->d_ioState.reset(); - ioGuard.release(); - - try { - if (conn->reconnect()) { - conn->d_ioState = make_unique(*conn->d_mplexer, conn->d_handler->getDescriptor()); - - /* we need to resend the queries that were in flight, if any */ - if (conn->d_state == State::sendingQueryToBackend) { - /* we need to edit this query so it has the correct ID */ - auto query = std::move(conn->d_currentQuery); - uint16_t id = conn->d_highestStreamID; - prepareQueryForSending(query.d_query, id, ConnectionState::needProxy); - conn->d_currentQuery = std::move(query); - } - - /* if we notify the sender it might terminate us so we need to move these first */ - auto pendingResponses = std::move(conn->d_pendingResponses); - conn->d_pendingResponses.clear(); - for (auto& pending : pendingResponses) { - --conn->d_ds->outstanding; - - if (pending.second.d_query.isXFR() && pending.second.d_query.d_xfrStarted) { - /* this one can't be restarted, sorry */ - DEBUGLOG("A XFR for which a response has already been sent cannot be restarted"); - try { - TCPResponse response(std::move(pending.second.d_query)); - pending.second.d_sender->notifyIOError(now, std::move(response)); - } - catch (const std::exception& e) { - vinfolog("Got an exception while notifying: %s", e.what()); - } - catch (...) { - vinfolog("Got exception while notifying"); - } - } - else { - conn->d_pendingQueries.push_back(std::move(pending.second)); - } - } - conn->d_currentPos = 0; - - if (conn->d_state == State::sendingQueryToBackend) { - iostate = IOState::NeedWrite; - // resume sending query - } - else { - if (conn->d_pendingQueries.empty()) { - throw std::runtime_error("TCP connection to a backend in state " + std::to_string((int)conn->d_state) + " with no pending queries"); - } - - iostate = queueNextQuery(conn); - } - - reconnected = true; - connectionDied = false; - } - } - catch (const std::exception& e) { - // reconnect might throw on failure, let's ignore that, we just need to know - // it failed - } - } - - if (!reconnected) { - /* reconnect failed, we give up */ - DEBUGLOG("reconnect failed, we give up"); - ++conn->d_ds->tcpGaveUp; - conn->notifyAllQueriesFailed(now, FailureReason::gaveUp); - } + handleReconnectionAttempt(conn, now, ioGuard, iostate, reconnected, connectionDied); } if (conn->d_ioState) { diff --git a/pdns/dnsdistdist/dnsdist-tcp-downstream.hh b/pdns/dnsdistdist/dnsdist-tcp-downstream.hh index ae46bd6b9..308c073c8 100644 --- a/pdns/dnsdistdist/dnsdist-tcp-downstream.hh +++ b/pdns/dnsdistdist/dnsdist-tcp-downstream.hh @@ -275,6 +275,7 @@ private: static void handleIO(std::shared_ptr& conn, const struct timeval& now); static void handleIOCallback(int fd, FDMultiplexer::funcparam_t& param); + static void handleReconnectionAttempt(std::shared_ptr& conn, const struct timeval& now, IOStateGuard& ioGuard, IOState& iostate, bool& reconnected, bool& connectionDied); static IOState queueNextQuery(std::shared_ptr& conn); static IOState sendQuery(std::shared_ptr& conn, const struct timeval& now); static bool isXFRFinished(const TCPResponse& response, TCPQuery& query); -- 2.47.3