diff options
author | Matt Cotter <matt.cotter@mongodb.com> | 2016-07-22 17:24:44 -0400 |
---|---|---|
committer | samantharitter <samantha.ritter@10gen.com> | 2017-04-15 16:58:52 -0400 |
commit | 35405a48079c58de51a46c929d892afdd423fc2a (patch) | |
tree | a0f2796a7e8841a634cf88cd02f52fb98df6c4a3 | |
parent | 934eb7d00a0d85ff6a209b6add038103eb247858 (diff) | |
download | mongo-35405a48079c58de51a46c929d892afdd423fc2a.tar.gz |
SERVER-25218 add more information to connPoolStats
(cherry-picked from commit 8f7423be75dca29ca1bc14b6bcfb34a46b8fdc2f)
* group stats by pool
* fix tests that relied on broken behavior
-rw-r--r-- | jstests/sharding/conn_pool_stats.js | 43 | ||||
-rw-r--r-- | jstests/sharding/shard6.js | 34 | ||||
-rw-r--r-- | src/mongo/client/connpool.cpp | 10 | ||||
-rw-r--r-- | src/mongo/executor/connection_pool.cpp | 25 | ||||
-rw-r--r-- | src/mongo/executor/connection_pool.h | 3 | ||||
-rw-r--r-- | src/mongo/executor/connection_pool_stats.cpp | 61 | ||||
-rw-r--r-- | src/mongo/executor/connection_pool_stats.h | 19 | ||||
-rw-r--r-- | src/mongo/executor/connection_pool_test.cpp | 32 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_asio.cpp | 1 |
9 files changed, 148 insertions, 80 deletions
diff --git a/jstests/sharding/conn_pool_stats.js b/jstests/sharding/conn_pool_stats.js index 872c20602a5..04952a273b6 100644 --- a/jstests/sharding/conn_pool_stats.js +++ b/jstests/sharding/conn_pool_stats.js @@ -1,19 +1,32 @@ // Tests for the connPoolStats command. +(function() { + "use strict"; + // Create a cluster with 2 shards. + var cluster = new ShardingTest({shards: 2}); -// Create a cluster with 2 shards. -var cluster = new ShardingTest({shards: 2}); + // Needed because the command was expanded post 3.2 + var version = cluster.s.getDB("admin").runCommand({buildinfo: 1}).versionArray; + var post32 = (version[0] > 4) || ((version[0] == 3) && (version[1] > 2)); -// Run the connPoolStats command -stats = cluster.s.getDB("admin").runCommand({connPoolStats: 1}); + // Run the connPoolStats command + var stats = cluster.s.getDB("admin").runCommand({connPoolStats: 1}); -// Validate output -printjson(stats); -assert.commandWorked(stats); -assert("replicaSets" in stats); -assert("hosts" in stats); -assert("numClientConnections" in stats); -assert("numAScopedConnections" in stats); -assert("totalInUse" in stats); -assert("totalAvailable" in stats); -assert("totalCreated" in stats); -assert.lte(stats["totalInUse"] + stats["totalAvailable"], stats["totalCreated"], tojson(stats)); + // Validate output + printjson(stats); + assert.commandWorked(stats); + assert("replicaSets" in stats); + assert("hosts" in stats); + assert("numClientConnections" in stats); + assert("numAScopedConnections" in stats); + assert("totalInUse" in stats); + assert("totalAvailable" in stats); + assert("totalCreated" in stats); + assert.lte(stats["totalInUse"] + stats["totalAvailable"], stats["totalCreated"], tojson(stats)); + if (post32) { + assert("pools" in stats); + assert("totalRefreshing" in stats); + assert.lte(stats["totalInUse"] + stats["totalAvailable"] + stats["totalRefreshing"], + stats["totalCreated"], + tojson(stats)); + } +})(); diff --git a/jstests/sharding/shard6.js b/jstests/sharding/shard6.js index 3b4f3e416eb..7d3736c5c21 100644 --- a/jstests/sharding/shard6.js +++ b/jstests/sharding/shard6.js @@ -1,8 +1,8 @@ // shard6.js -summary = ""; +var summary = ""; -s = new ShardingTest({name: "shard6", shards: 2}); +var s = new ShardingTest({name: "shard6", shards: 2}); s.config.settings.update({_id: "balancer"}, {$set: {stopped: true}}, true); @@ -10,29 +10,33 @@ s.adminCommand({enablesharding: "test"}); s.ensurePrimaryShard('test', 'shard0001'); s.adminCommand({shardcollection: "test.data", key: {num: 1}}); -db = s.getDB("test"); +var db = s.getDB("test"); function poolStats(where) { var total = 0; var msg = "poolStats " + where + " "; - var x = db.runCommand("connPoolStats").hosts; - for (var h in x) { - var z = x[h]; - msg += z.created + " "; - total += z.created; + var stats = db.runCommand("connPoolStats"); + for (var h in stats.hosts) { + if (!stats.hosts.hasOwnProperty(h)) { + continue; + } + var host = stats.hosts[h]; + msg += host.created + " "; + total += host.created; } - printjson(x); + printjson(stats.hosts); print("****\n" + msg + "\n*****"); summary += msg + "\n"; + + assert.eq(total, stats.totalCreated, "mismatched number of total connections created"); + return total; } poolStats("at start"); // we want a lot of data, so lets make a 50k string to cheat :) -bigString = ""; -while (bigString.length < 50000) - bigString += "this is a big string. "; +var bigString = "this is a big string. ".repeat(50000); // ok, now lets insert a some data var num = 0; @@ -42,7 +46,7 @@ for (; num < 100; num++) { assert.eq(100, db.data.find().toArray().length, "basic find after setup"); -connBefore = poolStats("setup done"); +poolStats("setup done"); // limit @@ -54,7 +58,7 @@ for (var i = 1; i < 10; i++) { poolStats("after loop : " + i); } -assert.eq(connBefore, poolStats("limit test done"), "limit test conns"); +poolStats("limit test done"); function assertOrder(start, num) { var a = db.data.find().skip(start).limit(num).sort({num: 1}).map(function(z) { @@ -99,7 +103,7 @@ poolStats("after checking itcount"); // --- test save support --- -o = db.data.findOne(); +var o = db.data.findOne(); o.x = 16; db.data.save(o); o = db.data.findOne({_id: o._id}); diff --git a/src/mongo/client/connpool.cpp b/src/mongo/client/connpool.cpp index 219888e68f9..40baf4d0222 100644 --- a/src/mongo/client/connpool.cpp +++ b/src/mongo/client/connpool.cpp @@ -391,11 +391,11 @@ void DBConnectionPool::appendConnectionStats(executor::ConnectionPoolStats* stat invariant(uri.isOK()); HostAndPort host = uri.getValue().getServers().front(); - executor::ConnectionStatsPerHost hostStats{ - static_cast<size_t>(i->second.numInUse()), - static_cast<size_t>(i->second.numAvailable()), - static_cast<size_t>(i->second.numCreated())}; - stats->updateStatsForHost(host, hostStats); + executor::ConnectionStatsPer hostStats{static_cast<size_t>(i->second.numInUse()), + static_cast<size_t>(i->second.numAvailable()), + static_cast<size_t>(i->second.numCreated()), + 0}; + stats->updateStatsForHost("global", host, hostStats); } } } diff --git a/src/mongo/executor/connection_pool.cpp b/src/mongo/executor/connection_pool.cpp index c06a6b209e2..f4d8ed87f05 100644 --- a/src/mongo/executor/connection_pool.cpp +++ b/src/mongo/executor/connection_pool.cpp @@ -95,6 +95,11 @@ public: size_t availableConnections(const stdx::unique_lock<stdx::mutex>& lk); /** + * Returns the number of in progress connections in the pool. + */ + size_t refreshingConnections(const stdx::unique_lock<stdx::mutex>& lk); + + /** * Returns the total number of connections ever created in this pool. */ size_t createdConnections(const stdx::unique_lock<stdx::mutex>& lk); @@ -184,8 +189,10 @@ const Milliseconds ConnectionPool::kDefaultRefreshTimeout = Seconds(20); const Status ConnectionPool::kConnectionStateUnknown = Status(ErrorCodes::InternalError, "Connection is in an unknown state"); -ConnectionPool::ConnectionPool(std::unique_ptr<DependentTypeFactoryInterface> impl, Options options) - : _options(std::move(options)), _factory(std::move(impl)) {} +ConnectionPool::ConnectionPool(std::unique_ptr<DependentTypeFactoryInterface> impl, + std::string name, + Options options) + : _name(std::move(name)), _options(std::move(options)), _factory(std::move(impl)) {} ConnectionPool::~ConnectionPool() = default; @@ -230,10 +237,11 @@ void ConnectionPool::appendConnectionStats(ConnectionPoolStats* stats) const { HostAndPort host = kv.first; auto& pool = kv.second; - ConnectionStatsPerHost hostStats{pool->inUseConnections(lk), - pool->availableConnections(lk), - pool->createdConnections(lk)}; - stats->updateStatsForHost(host, hostStats); + ConnectionStatsPer hostStats{pool->inUseConnections(lk), + pool->availableConnections(lk), + pool->createdConnections(lk), + pool->refreshingConnections(lk)}; + stats->updateStatsForHost(_name, host, hostStats); } } @@ -280,6 +288,11 @@ size_t ConnectionPool::SpecificPool::availableConnections( return _readyPool.size(); } +size_t ConnectionPool::SpecificPool::refreshingConnections( + const stdx::unique_lock<stdx::mutex>& lk) { + return _processingPool.size(); +} + size_t ConnectionPool::SpecificPool::createdConnections(const stdx::unique_lock<stdx::mutex>& lk) { return _created; } diff --git a/src/mongo/executor/connection_pool.h b/src/mongo/executor/connection_pool.h index ffa5495602f..962f9f39b66 100644 --- a/src/mongo/executor/connection_pool.h +++ b/src/mongo/executor/connection_pool.h @@ -111,6 +111,7 @@ public: }; explicit ConnectionPool(std::unique_ptr<DependentTypeFactoryInterface> impl, + std::string name, Options options = Options{}); ~ConnectionPool(); @@ -126,6 +127,8 @@ public: private: void returnConnection(ConnectionInterface* connection); + std::string _name; + // Options are set at startup and never changed at run time, so these are // accessed outside the lock const Options _options; diff --git a/src/mongo/executor/connection_pool_stats.cpp b/src/mongo/executor/connection_pool_stats.cpp index 02ff34da6c1..64cc3bbc6eb 100644 --- a/src/mongo/executor/connection_pool_stats.cpp +++ b/src/mongo/executor/connection_pool_stats.cpp @@ -36,44 +36,73 @@ namespace mongo { namespace executor { -ConnectionStatsPerHost::ConnectionStatsPerHost(size_t nInUse, size_t nAvailable, size_t nCreated) - : inUse(nInUse), available(nAvailable), created(nCreated) {} +ConnectionStatsPer::ConnectionStatsPer(size_t nInUse, + size_t nAvailable, + size_t nCreated, + size_t nRefreshing) + : inUse(nInUse), available(nAvailable), created(nCreated), refreshing(nRefreshing) {} -ConnectionStatsPerHost::ConnectionStatsPerHost() = default; +ConnectionStatsPer::ConnectionStatsPer() = default; -ConnectionStatsPerHost& ConnectionStatsPerHost::operator+=(const ConnectionStatsPerHost& other) { +ConnectionStatsPer& ConnectionStatsPer::operator+=(const ConnectionStatsPer& other) { inUse += other.inUse; available += other.available; created += other.created; + refreshing += other.refreshing; return *this; } -void ConnectionPoolStats::updateStatsForHost(HostAndPort host, ConnectionStatsPerHost newStats) { +void ConnectionPoolStats::updateStatsForHost(std::string pool, + HostAndPort host, + ConnectionStatsPer newStats) { // Update stats for this host. - auto hostStats = mapFindWithDefault(statsByHost, host); - hostStats += newStats; - statsByHost.insert(std::make_pair(host, hostStats)); + statsByPool[pool] += newStats; + statsByHost[host] += newStats; + statsByPoolHost[pool][host] += newStats; // Update total connection stats. totalInUse += newStats.inUse; totalAvailable += newStats.available; totalCreated += newStats.created; + totalRefreshing += newStats.refreshing; } void ConnectionPoolStats::appendToBSON(mongo::BSONObjBuilder& result) { result.appendNumber("totalInUse", totalInUse); result.appendNumber("totalAvailable", totalAvailable); result.appendNumber("totalCreated", totalCreated); + result.appendNumber("totalRefreshing", totalRefreshing); - BSONObjBuilder hostBuilder(result.subobjStart("hosts")); - for (auto&& host : statsByHost) { - BSONObjBuilder hostInfo(hostBuilder.subobjStart(host.first.toString())); - - auto hostStats = host.second; - hostInfo.appendNumber("inUse", hostStats.inUse); - hostInfo.appendNumber("available", hostStats.available); - hostInfo.appendNumber("created", hostStats.created); + { + BSONObjBuilder poolBuilder(result.subobjStart("pools")); + for (auto&& pool : statsByPool) { + BSONObjBuilder poolInfo(poolBuilder.subobjStart(pool.first)); + auto poolStats = pool.second; + poolInfo.appendNumber("poolInUse", poolStats.inUse); + poolInfo.appendNumber("poolAvailable", poolStats.available); + poolInfo.appendNumber("poolCreated", poolStats.created); + poolInfo.appendNumber("poolRefreshing", poolStats.refreshing); + for (auto&& host : statsByPoolHost[pool.first]) { + BSONObjBuilder hostInfo(poolInfo.subobjStart(host.first.toString())); + auto hostStats = host.second; + hostInfo.appendNumber("inUse", hostStats.inUse); + hostInfo.appendNumber("available", hostStats.available); + hostInfo.appendNumber("created", hostStats.created); + hostInfo.appendNumber("refreshing", hostStats.refreshing); + } + } + } + { + BSONObjBuilder hostBuilder(result.subobjStart("hosts")); + for (auto&& host : statsByHost) { + BSONObjBuilder hostInfo(hostBuilder.subobjStart(host.first.toString())); + auto hostStats = host.second; + hostInfo.appendNumber("inUse", hostStats.inUse); + hostInfo.appendNumber("available", hostStats.available); + hostInfo.appendNumber("created", hostStats.created); + hostInfo.appendNumber("refreshing", hostStats.refreshing); + } } } diff --git a/src/mongo/executor/connection_pool_stats.h b/src/mongo/executor/connection_pool_stats.h index 5e9bd0c7633..148dd89facf 100644 --- a/src/mongo/executor/connection_pool_stats.h +++ b/src/mongo/executor/connection_pool_stats.h @@ -36,19 +36,20 @@ namespace mongo { namespace executor { /** - * Holds connection information for a specific remote host. These objects are maintained by + * Holds connection information for a specific pool or remote host. These objects are maintained by * a parent ConnectionPoolStats object and should not need to be created directly. */ -struct ConnectionStatsPerHost { - ConnectionStatsPerHost(size_t nInUse, size_t nAvailable, size_t nCreated); +struct ConnectionStatsPer { + ConnectionStatsPer(size_t nInUse, size_t nAvailable, size_t nCreated, size_t nRefreshing); - ConnectionStatsPerHost(); + ConnectionStatsPer(); - ConnectionStatsPerHost& operator+=(const ConnectionStatsPerHost& other); + ConnectionStatsPer& operator+=(const ConnectionStatsPer& other); size_t inUse = 0u; size_t available = 0u; size_t created = 0u; + size_t refreshing = 0u; }; /** @@ -57,15 +58,19 @@ struct ConnectionStatsPerHost { * Total connection counts will then be updated accordingly. */ struct ConnectionPoolStats { - void updateStatsForHost(HostAndPort host, ConnectionStatsPerHost newStats); + void updateStatsForHost(std::string pool, HostAndPort host, ConnectionStatsPer newStats); void appendToBSON(mongo::BSONObjBuilder& result); size_t totalInUse = 0u; size_t totalAvailable = 0u; size_t totalCreated = 0u; + size_t totalRefreshing = 0u; - std::unordered_map<HostAndPort, ConnectionStatsPerHost> statsByHost; + std::unordered_map<std::string, ConnectionStatsPer> statsByPool; + std::unordered_map<HostAndPort, ConnectionStatsPer> statsByHost; + std::unordered_map<std::string, std::unordered_map<HostAndPort, ConnectionStatsPer>> + statsByPoolHost; }; } // namespace executor diff --git a/src/mongo/executor/connection_pool_test.cpp b/src/mongo/executor/connection_pool_test.cpp index 89e6d282791..0d541dfa86a 100644 --- a/src/mongo/executor/connection_pool_test.cpp +++ b/src/mongo/executor/connection_pool_test.cpp @@ -66,7 +66,7 @@ private: * another. */ TEST_F(ConnectionPoolTest, SameConn) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); // Grab and stash an id for the first request size_t conn1Id = 0; @@ -98,7 +98,7 @@ TEST_F(ConnectionPoolTest, SameConn) { * Verify that a failed connection isn't returned to the pool */ TEST_F(ConnectionPoolTest, FailedConnDifferentConn) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); // Grab the first connection and indicate that it failed size_t conn1Id = 0; @@ -131,7 +131,7 @@ TEST_F(ConnectionPoolTest, FailedConnDifferentConn) { * connections. */ TEST_F(ConnectionPoolTest, DifferentHostDifferentConn) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); // Conn 1 from port 30000 size_t conn1Id = 0; @@ -163,7 +163,7 @@ TEST_F(ConnectionPoolTest, DifferentHostDifferentConn) { * Verify that not returning handle's to the pool spins up new connections. */ TEST_F(ConnectionPoolTest, DifferentConnWithoutReturn) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); // Get the first connection, move it out rather than letting it return ConnectionPool::ConnectionHandle conn1; @@ -199,7 +199,7 @@ TEST_F(ConnectionPoolTest, DifferentConnWithoutReturn) { * Note that the lack of pushSetup() calls delays the get. */ TEST_F(ConnectionPoolTest, TimeoutOnSetup) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); bool notOk = false; @@ -234,7 +234,7 @@ TEST_F(ConnectionPoolTest, refreshHappens) { ConnectionPool::Options options; options.refreshRequirement = Milliseconds(1000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -270,7 +270,7 @@ TEST_F(ConnectionPoolTest, refreshTimeoutHappens) { ConnectionPool::Options options; options.refreshRequirement = Milliseconds(1000); options.refreshTimeout = Milliseconds(2000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -339,7 +339,7 @@ TEST_F(ConnectionPoolTest, refreshTimeoutHappens) { * Verify that requests are served in expiration order, not insertion order */ TEST_F(ConnectionPoolTest, requestsServedByUrgency) { - ConnectionPool pool(stdx::make_unique<PoolImpl>()); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool"); bool reachedA = false; bool reachedB = false; @@ -386,7 +386,7 @@ TEST_F(ConnectionPoolTest, maxPoolRespected) { ConnectionPool::Options options; options.minConnections = 1; options.maxConnections = 2; - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); ConnectionPool::ConnectionHandle conn1; ConnectionPool::ConnectionHandle conn2; @@ -446,7 +446,7 @@ TEST_F(ConnectionPoolTest, minPoolRespected) { options.maxConnections = 3; options.refreshRequirement = Milliseconds(1000); options.refreshTimeout = Milliseconds(2000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -555,7 +555,7 @@ TEST_F(ConnectionPoolTest, hostTimeoutHappens) { options.refreshRequirement = Milliseconds(5000); options.refreshTimeout = Milliseconds(5000); options.hostTimeout = Milliseconds(1000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -604,7 +604,7 @@ TEST_F(ConnectionPoolTest, hostTimeoutHappensMoreGetsDelay) { options.refreshRequirement = Milliseconds(5000); options.refreshTimeout = Milliseconds(5000); options.hostTimeout = Milliseconds(1000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -666,7 +666,7 @@ TEST_F(ConnectionPoolTest, hostTimeoutHappensCheckoutDelays) { options.refreshRequirement = Milliseconds(5000); options.refreshTimeout = Milliseconds(5000); options.hostTimeout = Milliseconds(1000); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); @@ -746,7 +746,7 @@ TEST_F(ConnectionPoolTest, dropConnections) { options.maxConnections = 1; options.refreshRequirement = Seconds(1); options.refreshTimeout = Seconds(2); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); PoolImpl::setNow(now); @@ -839,7 +839,7 @@ TEST_F(ConnectionPoolTest, SetupTimeoutsDontTimeoutUnrelatedRequests) { options.maxConnections = 1; options.refreshTimeout = Seconds(2); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); PoolImpl::setNow(now); @@ -883,7 +883,7 @@ TEST_F(ConnectionPoolTest, RefreshTimeoutsDontTimeoutRequests) { options.maxConnections = 1; options.refreshTimeout = Seconds(2); options.refreshRequirement = Seconds(3); - ConnectionPool pool(stdx::make_unique<PoolImpl>(), options); + ConnectionPool pool(stdx::make_unique<PoolImpl>(), "test pool", options); auto now = Date_t::now(); PoolImpl::setNow(now); diff --git a/src/mongo/executor/network_interface_asio.cpp b/src/mongo/executor/network_interface_asio.cpp index aea5eb58951..60db2b52e95 100644 --- a/src/mongo/executor/network_interface_asio.cpp +++ b/src/mongo/executor/network_interface_asio.cpp @@ -86,6 +86,7 @@ NetworkInterfaceASIO::NetworkInterfaceASIO(Options options) _timerFactory(std::move(_options.timerFactory)), _streamFactory(std::move(_options.streamFactory)), _connectionPool(stdx::make_unique<connection_pool_asio::ASIOImpl>(this), + _options.instanceName, _options.connectionPoolOptions), _isExecutorRunnable(false), _strand(_io_service) {} |