summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlake Oler <blake.oler@mongodb.com>2022-09-21 17:45:44 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-21 20:05:35 +0000
commit02948a5102d2be9f5b727045cf787fc7dda2fcb7 (patch)
tree04e2238886ea27354c6e991a5440bbe136a39703
parentbf191b0361e837a17c743941180a4d77de875a9d (diff)
downloadmongo-02948a5102d2be9f5b727045cf787fc7dda2fcb7.tar.gz
SERVER-64005 Add metric tracking listener socket backlog queue depth
-rw-r--r--src/mongo/db/commands/server_status_servers.cpp2
-rw-r--r--src/mongo/db/ftdc/ftdc_mongod.cpp3
-rw-r--r--src/mongo/db/ftdc/ftdc_mongos.cpp3
-rw-r--r--src/mongo/transport/transport_layer.h7
-rw-r--r--src/mongo/transport/transport_layer_asio.cpp128
-rw-r--r--src/mongo/transport/transport_layer_asio.h16
-rw-r--r--src/mongo/transport/transport_layer_asio_test.cpp86
-rw-r--r--src/mongo/transport/transport_layer_ftdc_collector.h50
-rw-r--r--src/mongo/transport/transport_layer_manager.cpp8
-rw-r--r--src/mongo/transport/transport_layer_manager.h3
-rw-r--r--src/mongo/util/net/sockaddr.cpp10
-rw-r--r--src/mongo/util/net/sockaddr.h1
12 files changed, 277 insertions, 40 deletions
diff --git a/src/mongo/db/commands/server_status_servers.cpp b/src/mongo/db/commands/server_status_servers.cpp
index 6e6a265c9e0..d5dd31ca347 100644
--- a/src/mongo/db/commands/server_status_servers.cpp
+++ b/src/mongo/db/commands/server_status_servers.cpp
@@ -95,7 +95,7 @@ public:
}
}
if (auto tl = svcCtx->getTransportLayer())
- tl->appendStats(&b);
+ tl->appendStatsForServerStatus(&b);
return b.obj();
}
diff --git a/src/mongo/db/ftdc/ftdc_mongod.cpp b/src/mongo/db/ftdc/ftdc_mongod.cpp
index 8da45771f19..6ccae55e539 100644
--- a/src/mongo/db/ftdc/ftdc_mongod.cpp
+++ b/src/mongo/db/ftdc/ftdc_mongod.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/storage/storage_options.h"
+#include "mongo/transport/transport_layer_ftdc_collector.h"
#include "mongo/util/assert_util.h"
namespace mongo {
@@ -128,6 +129,8 @@ void registerMongoDCollectors(FTDCController* controller) {
}
controller->addPeriodicCollector(std::make_unique<FTDCCollectionStatsCollector>());
+
+ controller->addPeriodicCollector(std::make_unique<transport::TransportLayerFTDCCollector>());
}
} // namespace
diff --git a/src/mongo/db/ftdc/ftdc_mongos.cpp b/src/mongo/db/ftdc/ftdc_mongos.cpp
index 53216762137..aeb457f38d7 100644
--- a/src/mongo/db/ftdc/ftdc_mongos.cpp
+++ b/src/mongo/db/ftdc/ftdc_mongos.cpp
@@ -45,6 +45,7 @@
#include "mongo/logv2/log.h"
#include "mongo/s/grid.h"
#include "mongo/stdx/thread.h"
+#include "mongo/transport/transport_layer_ftdc_collector.h"
#include "mongo/util/synchronized_value.h"
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kFTDC
@@ -111,6 +112,8 @@ void registerMongoSCollectors(FTDCController* controller) {
controller->addPeriodicCollector(std::make_unique<NetworkInterfaceStatsCollector>());
+ controller->addPeriodicCollector(std::make_unique<transport::TransportLayerFTDCCollector>());
+
// GetDefaultRWConcern
controller->addOnRotateCollector(std::make_unique<FTDCSimpleInternalCommandCollector>(
"getDefaultRWConcern",
diff --git a/src/mongo/transport/transport_layer.h b/src/mongo/transport/transport_layer.h
index 24afafe1f01..369226ad7a9 100644
--- a/src/mongo/transport/transport_layer.h
+++ b/src/mongo/transport/transport_layer.h
@@ -123,8 +123,11 @@ public:
*/
virtual Status setup() = 0;
- /** Allows a `TransportLayer` to contribute to a stats summary (e.g. `serverStatus`). */
- virtual void appendStats(BSONObjBuilder* bob) const {}
+ /** Allows a `TransportLayer` to contribute to a serverStatus readout. */
+ virtual void appendStatsForServerStatus(BSONObjBuilder* bob) const {}
+
+ /** Allows a `TransportLayer` to contribute to a FTDC readout. */
+ virtual void appendStatsForFTDC(BSONObjBuilder& bob) const {}
enum WhichReactor { kIngress, kEgress, kNewReactor };
virtual ReactorHandle getReactor(WhichReactor which) = 0;
diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp
index 2f1b90095d6..903792c47e5 100644
--- a/src/mongo/transport/transport_layer_asio.cpp
+++ b/src/mongo/transport/transport_layer_asio.cpp
@@ -123,7 +123,8 @@ boost::optional<Status> maybeTcpFastOpenStatus;
MONGO_FAIL_POINT_DEFINE(transportLayerASIOasyncConnectTimesOut);
MONGO_FAIL_POINT_DEFINE(transportLayerASIOdelayConnection);
-MONGO_FAIL_POINT_DEFINE(transportLayerASIOhangBeforeAccept);
+MONGO_FAIL_POINT_DEFINE(transportLayerASIOhangBeforeAcceptCallback);
+MONGO_FAIL_POINT_DEFINE(transportLayerASIOhangDuringAcceptCallback);
#ifdef MONGO_CONFIG_SSL
SSLConnectionContext::~SSLConnectionContext() = default;
@@ -392,6 +393,17 @@ TransportLayerASIO::TransportLayerASIO(const TransportLayerASIO::Options& opts,
TransportLayerASIO::~TransportLayerASIO() = default;
+struct TransportLayerASIO::AcceptorRecord {
+ AcceptorRecord(SockAddr address, GenericAcceptor acceptor)
+ : address(std::move(address)), acceptor(std::move(acceptor)) {}
+
+ SockAddr address;
+ GenericAcceptor acceptor;
+ // Tracks the amount of incoming connections waiting to be accepted by the server on this
+ // acceptor.
+ AtomicWord<int> backlogQueueDepth{0};
+};
+
class WrappedEndpoint {
public:
using Endpoint = asio::generic::stream_protocol::endpoint;
@@ -1262,24 +1274,29 @@ Status TransportLayerASIO::setup() {
}
}
#endif
+ auto endpoint = acceptor.local_endpoint(ec);
+ if (ec) {
+ return errorCodeToStatus(ec);
+ }
+ auto hostAndPort = endpointToHostAndPort(endpoint);
+
+ auto record = std::make_unique<AcceptorRecord>(SockAddr(addr->data(), addr->size()),
+ std::move(acceptor));
+
if (_listenerOptions.port == 0 && (addr.family() == AF_INET || addr.family() == AF_INET6)) {
if (_listenerPort != _listenerOptions.port) {
return Status(ErrorCodes::BadValue,
"Port 0 (ephemeral port) is not allowed when"
" listening on multiple IP interfaces");
}
- std::error_code ec;
- auto endpoint = acceptor.local_endpoint(ec);
- if (ec) {
- return errorCodeToStatus(ec);
- }
- _listenerPort = endpointToHostAndPort(endpoint).port();
+ _listenerPort = hostAndPort.port();
+ record->address.setPort(_listenerPort);
}
- _acceptors.emplace_back(SockAddr(addr->data(), addr->size()), std::move(acceptor));
+ _acceptorRecords.push_back(std::move(record));
}
- if (_acceptors.empty() && _listenerOptions.isIngress()) {
+ if (_acceptorRecords.empty() && _listenerOptions.isIngress()) {
return Status(ErrorCodes::SocketException, "No available addresses/ports to bind to");
}
@@ -1294,9 +1311,31 @@ Status TransportLayerASIO::setup() {
return Status::OK();
}
-void TransportLayerASIO::appendStats(BSONObjBuilder* bob) const {
- if (gFeatureFlagConnHealthMetrics.isEnabledAndIgnoreFCV())
+std::vector<std::pair<SockAddr, int>> TransportLayerASIO::getListenerSocketBacklogQueueDepths()
+ const {
+ std::vector<std::pair<SockAddr, int>> queueDepths;
+ for (auto&& record : _acceptorRecords) {
+ queueDepths.push_back({SockAddr(record->address), record->backlogQueueDepth.load()});
+ }
+ return queueDepths;
+}
+
+void TransportLayerASIO::appendStatsForServerStatus(BSONObjBuilder* bob) const {
+ if (gFeatureFlagConnHealthMetrics.isEnabledAndIgnoreFCV()) {
bob->append("listenerProcessingTime", _listenerProcessingTime.load().toBSON());
+ }
+}
+
+void TransportLayerASIO::appendStatsForFTDC(BSONObjBuilder& bob) const {
+ if (gFeatureFlagConnHealthMetrics.isEnabledAndIgnoreFCV()) {
+ BSONArrayBuilder queueDepthsArrayBuilder(
+ bob.subarrayStart("listenerSocketBacklogQueueDepths"));
+ for (const auto& record : _acceptorRecords) {
+ BSONObjBuilder{queueDepthsArrayBuilder.subobjStart()}.append(
+ record->address.toString(), record->backlogQueueDepth.load());
+ }
+ queueDepthsArrayBuilder.done();
+ }
}
void TransportLayerASIO::_runListener() noexcept {
@@ -1307,19 +1346,19 @@ void TransportLayerASIO::_runListener() noexcept {
return;
}
- for (auto& acceptor : _acceptors) {
+ for (auto& acceptorRecord : _acceptorRecords) {
asio::error_code ec;
- acceptor.second.listen(serverGlobalParams.listenBacklog, ec);
+ acceptorRecord->acceptor.listen(serverGlobalParams.listenBacklog, ec);
if (ec) {
LOGV2_FATAL(31339,
"Error listening for new connections on {listenAddress}: {error}",
"Error listening for new connections on listen address",
- "listenAddrs"_attr = acceptor.first,
+ "listenAddrs"_attr = acceptorRecord->address,
"error"_attr = ec.message());
}
- _acceptConnection(acceptor.second);
- LOGV2(23015, "Listening on", "address"_attr = acceptor.first.getAddr());
+ _acceptConnection(acceptorRecord->acceptor);
+ LOGV2(23015, "Listening on", "address"_attr = acceptorRecord->address.getAddr());
}
const char* ssl = "off";
@@ -1345,9 +1384,9 @@ void TransportLayerASIO::_runListener() noexcept {
// Loop through the acceptors and cancel their calls to async_accept. This will prevent new
// connections from being opened.
- for (auto& acceptor : _acceptors) {
- acceptor.second.cancel();
- auto& addr = acceptor.first;
+ for (auto& acceptorRecord : _acceptorRecords) {
+ acceptorRecord->acceptor.cancel();
+ auto& addr = acceptorRecord->address;
if (addr.getType() == AF_UNIX && !addr.isAnonymousUNIXSocket()) {
auto path = addr.getAddr();
LOGV2(
@@ -1376,7 +1415,7 @@ Status TransportLayerASIO::start() {
return Status::OK();
}
- invariant(_acceptors.empty());
+ invariant(_acceptorRecords.empty());
return Status::OK();
}
@@ -1428,11 +1467,25 @@ ReactorHandle TransportLayerASIO::getReactor(WhichReactor which) {
MONGO_UNREACHABLE;
}
+namespace {
+void handleConnectionAcceptASIOError(const asio::system_error& e) {
+ // Swallow connection reset errors. Connection reset errors classically present as
+ // asio::error::eof, but can bubble up as asio::error::invalid_argument when calling
+ // into socket.set_option().
+ if (e.code() != asio::error::eof && e.code() != asio::error::invalid_argument) {
+ LOGV2_WARNING(5746600,
+ "Error accepting new connection: {error}",
+ "Error accepting new connection",
+ "error"_attr = e.code().message());
+ }
+}
+} // namespace
+
void TransportLayerASIO::_acceptConnection(GenericAcceptor& acceptor) {
auto acceptCb = [this, &acceptor](const std::error_code& ec,
ASIOSession::GenericSocket peerSocket) mutable {
Timer timer;
- transportLayerASIOhangBeforeAccept.pauseWhileSet();
+ transportLayerASIOhangDuringAcceptCallback.pauseWhileSet();
if (auto lk = stdx::lock_guard(_mutex); _isShutdown) {
return;
@@ -1472,15 +1525,7 @@ void TransportLayerASIO::_acceptConnection(GenericAcceptor& acceptor) {
_sep->startSession(std::move(session));
}
} catch (const asio::system_error& e) {
- // Swallow connection reset errors. Connection reset errors classically present as
- // asio::error::eof, but can bubble up as asio::error::invalid_argument when calling
- // into socket.set_option().
- if (e.code() != asio::error::eof && e.code() != asio::error::invalid_argument) {
- LOGV2_WARNING(5746600,
- "Error accepting new connection: {error}",
- "Error accepting new connection",
- "error"_attr = e.code().message());
- }
+ handleConnectionAcceptASIOError(e);
} catch (const DBException& e) {
LOGV2_WARNING(23023,
"Error accepting new connection: {error}",
@@ -1494,9 +1539,32 @@ void TransportLayerASIO::_acceptConnection(GenericAcceptor& acceptor) {
_acceptConnection(acceptor);
};
+ transportLayerASIOhangBeforeAcceptCallback.pauseWhileSet();
+
+ _trySetListenerSocketBacklogQueueDepth(acceptor);
+
acceptor.async_accept(*_ingressReactor, std::move(acceptCb));
}
+void TransportLayerASIO::_trySetListenerSocketBacklogQueueDepth(
+ GenericAcceptor& acceptor) noexcept {
+#ifdef __linux__
+ try {
+ auto matchingRecord =
+ std::find_if(begin(_acceptorRecords), end(_acceptorRecords), [&](const auto& record) {
+ return acceptor.local_endpoint() == record->acceptor.local_endpoint();
+ });
+ invariant(matchingRecord != std::end(_acceptorRecords));
+
+ TcpInfoOption tcpi;
+ acceptor.get_option(tcpi);
+ (*matchingRecord)->backlogQueueDepth.store(tcpi->tcpi_unacked);
+ } catch (const asio::system_error& e) {
+ handleConnectionAcceptASIOError(e);
+ }
+#endif
+}
+
#ifdef MONGO_CONFIG_SSL
SSLParams::SSLModes TransportLayerASIO::_sslMode() const {
return static_cast<SSLParams::SSLModes>(getSSLGlobalParams().sslMode.load());
diff --git a/src/mongo/transport/transport_layer_asio.h b/src/mongo/transport/transport_layer_asio.h
index 797cabb5ba6..3258c28c0ad 100644
--- a/src/mongo/transport/transport_layer_asio.h
+++ b/src/mongo/transport/transport_layer_asio.h
@@ -74,7 +74,10 @@ extern FailPoint transportLayerASIOshortOpportunisticReadWrite;
// Cause an asyncConnect to timeout after it's successfully connected to the remote peer
extern FailPoint transportLayerASIOasyncConnectTimesOut;
-extern FailPoint transportLayerASIOhangBeforeAccept;
+extern FailPoint transportLayerASIOhangBeforeAcceptCallback;
+
+extern FailPoint transportLayerASIOhangDuringAcceptCallback;
+
/**
* A TransportLayer implementation based on ASIO networking primitives.
@@ -198,7 +201,9 @@ public:
void shutdown() final;
- void appendStats(BSONObjBuilder* bob) const override;
+ void appendStatsForServerStatus(BSONObjBuilder* bob) const override;
+
+ void appendStatsForFTDC(BSONObjBuilder& bob) const override;
int listenerPort() const {
return _listenerPort;
@@ -208,6 +213,8 @@ public:
return _listenerOptions.loadBalancerPort;
}
+ std::vector<std::pair<SockAddr, int>> getListenerSocketBacklogQueueDepths() const;
+
#ifdef __linux__
BatonHandle makeBaton(OperationContext* opCtx) const override;
#endif
@@ -251,6 +258,8 @@ private:
void _runListener() noexcept;
+ void _trySetListenerSocketBacklogQueueDepth(GenericAcceptor& acceptor) noexcept;
+
#ifdef MONGO_CONFIG_SSL
SSLParams::SSLModes _sslMode() const;
#endif
@@ -287,7 +296,8 @@ private:
synchronized_value<std::shared_ptr<const SSLConnectionContext>> _sslContext;
#endif
- std::vector<std::pair<SockAddr, GenericAcceptor>> _acceptors;
+ struct AcceptorRecord;
+ std::vector<std::unique_ptr<AcceptorRecord>> _acceptorRecords;
// Only used if _listenerOptions.async is false.
struct Listener {
diff --git a/src/mongo/transport/transport_layer_asio_test.cpp b/src/mongo/transport/transport_layer_asio_test.cpp
index 2a5c4677254..9d9c8536559 100644
--- a/src/mongo/transport/transport_layer_asio_test.cpp
+++ b/src/mongo/transport/transport_layer_asio_test.cpp
@@ -43,6 +43,7 @@
#include "mongo/db/concurrency/locker_noop_service_context_test_fixture.h"
#include "mongo/db/server_options.h"
#include "mongo/db/service_context_test_fixture.h"
+#include "mongo/idl/server_parameter_test_util.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/platform/basic.h"
@@ -319,9 +320,39 @@ public:
return *_tla;
}
+ void setUpHangDuringAcceptingFirstConnection() {
+ _hangDuringAcceptTimesEntered = _hangDuringAccept.setMode(FailPoint::alwaysOn);
+ }
+
+ void waitForHangDuringAcceptingFirstConnection() {
+ _hangDuringAccept.waitForTimesEntered(_hangDuringAcceptTimesEntered + 1);
+ }
+
+ void waitForHangDuringAcceptingNextConnection() {
+ _hangBeforeAcceptTimesEntered = _hangBeforeAccept.setMode(FailPoint::alwaysOn);
+ _hangDuringAccept.setMode(FailPoint::off);
+ _hangBeforeAccept.waitForTimesEntered(_hangBeforeAcceptTimesEntered + 1);
+
+ _hangDuringAcceptTimesEntered = _hangDuringAccept.setMode(FailPoint::alwaysOn);
+ _hangBeforeAccept.setMode(FailPoint::off);
+ _hangDuringAccept.waitForTimesEntered(_hangDuringAcceptTimesEntered + 1);
+ }
+
+ void stopHangDuringAcceptingConnection() {
+ _hangDuringAccept.setMode(FailPoint::off);
+ }
+
private:
+ RAIIServerParameterControllerForTest _featureFlagController{"featureFlagConnHealthMetrics",
+ true};
std::unique_ptr<transport::TransportLayerASIO> _tla;
MockSEP _sep;
+
+ FailPoint& _hangBeforeAccept = transport::transportLayerASIOhangBeforeAcceptCallback;
+ FailPoint& _hangDuringAccept = transport::transportLayerASIOhangDuringAcceptCallback;
+
+ FailPoint::EntryCountT _hangBeforeAcceptTimesEntered{0};
+ FailPoint::EntryCountT _hangDuringAcceptTimesEntered{0};
};
TEST(TransportLayerASIO, ListenerPortZeroTreatedAsEphemeral) {
@@ -361,7 +392,7 @@ TEST(TransportLayerASIO, TCPResetAfterConnectionIsSilentlySwallowed) {
tf.sep().setOnStartSession([&](auto&&) { sessionsCreated.fetchAndAdd(1); });
LOGV2(6109515, "connecting");
- auto& fp = transport::transportLayerASIOhangBeforeAccept;
+ auto& fp = transport::transportLayerASIOhangDuringAcceptCallback;
auto timesEntered = fp.setMode(FailPoint::alwaysOn);
ConnectionThread connectThread(tf.tla().listenerPort(), &setNoLinger);
fp.waitForTimesEntered(timesEntered + 1);
@@ -376,6 +407,59 @@ TEST(TransportLayerASIO, TCPResetAfterConnectionIsSilentlySwallowed) {
ASSERT_EQ(sessionsCreated.load(), 0);
}
+#ifdef __linux__
+/**
+ * Test that the server successfully captures the TCP socket queue depth, and places the value both
+ * into the TransportLayerASIO class and FTDC output.
+ */
+TEST(TransportLayerASIO, TCPCheckQueueDepth) {
+ // Set the listenBacklog to a parameter greater than the number of connection threads we intend
+ // to create.
+ serverGlobalParams.listenBacklog = 10;
+ TestFixture tf;
+
+ LOGV2(6400501, "Starting and hanging three connection threads");
+ tf.setUpHangDuringAcceptingFirstConnection();
+
+ ConnectionThread connectThread1(tf.tla().listenerPort());
+ ConnectionThread connectThread2(tf.tla().listenerPort());
+ ConnectionThread connectThread3(tf.tla().listenerPort());
+
+ tf.waitForHangDuringAcceptingFirstConnection();
+ connectThread1.wait();
+ connectThread2.wait();
+ connectThread3.wait();
+
+ LOGV2(6400502, "Processing one connection thread");
+
+ tf.waitForHangDuringAcceptingNextConnection();
+
+ const auto& depths = tf.tla().getListenerSocketBacklogQueueDepths();
+ ASSERT_EQ(depths.size(), 1);
+
+ auto depth = depths[0];
+ ASSERT_EQ(depth.first.getPort(), tf.tla().listenerPort());
+ ASSERT_EQ(depth.second, 2);
+
+
+ BSONObjBuilder tlaFTDCBuilder;
+ tf.tla().appendStatsForFTDC(tlaFTDCBuilder);
+ BSONObj tlaFTDCStats = tlaFTDCBuilder.obj();
+
+ const auto& queueDepthsArray =
+ tlaFTDCStats.getField("listenerSocketBacklogQueueDepths").Array();
+ ASSERT_EQ(queueDepthsArray.size(), 1);
+
+ const auto& queueDepthObj = queueDepthsArray[0].Obj();
+ ASSERT_EQ(HostAndPort(queueDepthObj.firstElementFieldName()).port(), tf.tla().listenerPort());
+ ASSERT_EQ(queueDepthObj.firstElement().Int(), 2);
+
+ LOGV2(6400503, "Stopping failpoints, shutting down test");
+
+ tf.stopHangDuringAcceptingConnection();
+}
+#endif
+
TEST(TransportLayerASIO, ThrowOnNetworkErrorInEnsureSync) {
TestFixture tf;
Notification<SessionThread*> mockSessionCreated;
diff --git a/src/mongo/transport/transport_layer_ftdc_collector.h b/src/mongo/transport/transport_layer_ftdc_collector.h
new file mode 100644
index 00000000000..5c5744d8c9c
--- /dev/null
+++ b/src/mongo/transport/transport_layer_ftdc_collector.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/db/ftdc/collector.h"
+#include "mongo/db/operation_context.h"
+
+namespace mongo::transport {
+
+class TransportLayerFTDCCollector final : public FTDCCollectorInterface {
+public:
+ void collect(OperationContext* opCtx, BSONObjBuilder& builder) override {
+ if (auto tl = opCtx->getServiceContext()->getTransportLayer()) {
+ tl->appendStatsForFTDC(builder);
+ }
+ }
+
+ std::string name() const override {
+ return "transportLayerStats";
+ }
+};
+
+} // namespace mongo::transport
diff --git a/src/mongo/transport/transport_layer_manager.cpp b/src/mongo/transport/transport_layer_manager.cpp
index 7b2468a8848..32702186ea0 100644
--- a/src/mongo/transport/transport_layer_manager.cpp
+++ b/src/mongo/transport/transport_layer_manager.cpp
@@ -117,8 +117,12 @@ Status TransportLayerManager::setup() {
return Status::OK();
}
-void TransportLayerManager::appendStats(BSONObjBuilder* bob) const {
- _foreach([&](const TransportLayer* tl) { tl->appendStats(bob); });
+void TransportLayerManager::appendStatsForServerStatus(BSONObjBuilder* bob) const {
+ _foreach([&](const TransportLayer* tl) { tl->appendStatsForServerStatus(bob); });
+}
+
+void TransportLayerManager::appendStatsForFTDC(BSONObjBuilder& bob) const {
+ _foreach([&](const TransportLayer* tl) { tl->appendStatsForFTDC(bob); });
}
Status TransportLayerManager::addAndStartTransportLayer(std::unique_ptr<TransportLayer> tl) {
diff --git a/src/mongo/transport/transport_layer_manager.h b/src/mongo/transport/transport_layer_manager.h
index 750712b2811..b446197f31c 100644
--- a/src/mongo/transport/transport_layer_manager.h
+++ b/src/mongo/transport/transport_layer_manager.h
@@ -81,7 +81,8 @@ public:
Status start() override;
void shutdown() override;
Status setup() override;
- void appendStats(BSONObjBuilder* bob) const override;
+ void appendStatsForServerStatus(BSONObjBuilder* bob) const override;
+ void appendStatsForFTDC(BSONObjBuilder& bob) const override;
ReactorHandle getReactor(WhichReactor which) override;
diff --git a/src/mongo/util/net/sockaddr.cpp b/src/mongo/util/net/sockaddr.cpp
index 2b6d20ec865..abca48f5c9a 100644
--- a/src/mongo/util/net/sockaddr.cpp
+++ b/src/mongo/util/net/sockaddr.cpp
@@ -294,6 +294,16 @@ unsigned SockAddr::getPort() const {
}
}
+void SockAddr::setPort(int port) {
+ if (auto type = getType(); type == AF_INET) {
+ as<sockaddr_in>().sin_port = htons(port);
+ } else if (type == AF_INET6) {
+ as<sockaddr_in6>().sin6_port = htons(port);
+ } else {
+ massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
+ }
+}
+
std::string SockAddr::getAddr() const {
switch (getType()) {
case AF_INET:
diff --git a/src/mongo/util/net/sockaddr.h b/src/mongo/util/net/sockaddr.h
index 79e08ba1045..f62e6c25702 100644
--- a/src/mongo/util/net/sockaddr.h
+++ b/src/mongo/util/net/sockaddr.h
@@ -127,6 +127,7 @@ struct SockAddr {
sa_family_t getType() const;
unsigned getPort() const;
+ void setPort(int port);
std::string getAddr() const;