summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/list_databases.cpp41
-rw-r--r--src/mongo/s/catalog/sharding_catalog_append_db_stats_test.cpp52
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client.h6
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.cpp6
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.h1
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.cpp4
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.h1
-rw-r--r--src/mongo/s/commands/cluster_list_databases_cmd.cpp28
8 files changed, 109 insertions, 30 deletions
diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp
index f97988641fa..7088a4248b5 100644
--- a/src/mongo/db/commands/list_databases.cpp
+++ b/src/mongo/db/commands/list_databases.cpp
@@ -34,11 +34,16 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/concurrency/d_concurrency.h"
+#include "mongo/db/matcher/expression.h"
+#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/service_context.h"
#include "mongo/db/storage/storage_engine.h"
namespace mongo {
+namespace {
+static const StringData kFilterField{"filter"};
+} // namespace
using std::set;
using std::string;
@@ -81,6 +86,27 @@ public:
int,
string& errmsg,
BSONObjBuilder& result) {
+ // Parse the filter.
+ std::unique_ptr<MatchExpression> filter;
+ if (auto filterElt = jsobj[kFilterField]) {
+ if (filterElt.type() != BSONType::Object) {
+ return appendCommandStatus(result,
+ {ErrorCodes::TypeMismatch,
+ str::stream() << "Field '" << kFilterField
+ << "' must be of type Object in: "
+ << jsobj});
+ }
+ // The collator is null because database metadata objects are compared using simple
+ // binary comparison.
+ const CollatorInterface* collator = nullptr;
+ auto statusWithMatcher = MatchExpressionParser::parse(
+ filterElt.Obj(), ExtensionsCallbackDisallowExtensions(), collator);
+ if (!statusWithMatcher.isOK()) {
+ return appendCommandStatus(result, statusWithMatcher.getStatus());
+ }
+ filter = std::move(statusWithMatcher.getValue());
+ }
+
vector<string> dbNames;
StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine();
{
@@ -91,7 +117,6 @@ public:
vector<BSONObj> dbInfos;
- set<string> seen;
intmax_t totalSize = 0;
for (vector<string>::iterator i = dbNames.begin(); i != dbNames.end(); ++i) {
const string& dbname = *i;
@@ -99,6 +124,8 @@ public:
BSONObjBuilder b;
b.append("name", dbname);
+ BSONObj curDbObj;
+ int64_t size = 0;
{
ScopedTransaction transaction(txn, MODE_IS);
Lock::DBLock dbLock(txn->lockState(), dbname, MODE_IS);
@@ -110,16 +137,18 @@ public:
const DatabaseCatalogEntry* entry = db->getDatabaseCatalogEntry();
invariant(entry);
- int64_t size = entry->sizeOnDisk(txn);
+ size = entry->sizeOnDisk(txn);
b.append("sizeOnDisk", static_cast<double>(size));
- totalSize += size;
b.appendBool("empty", entry->isEmpty());
- }
- dbInfos.push_back(b.obj());
+ curDbObj = b.obj();
+ }
- seen.insert(i->c_str());
+ if (!filter || filter->matchesBSON(curDbObj)) {
+ totalSize += size;
+ dbInfos.push_back(curDbObj);
+ }
}
result.append("databases", dbInfos);
diff --git a/src/mongo/s/catalog/sharding_catalog_append_db_stats_test.cpp b/src/mongo/s/catalog/sharding_catalog_append_db_stats_test.cpp
index d3f46f56f63..5e2259b56fb 100644
--- a/src/mongo/s/catalog/sharding_catalog_append_db_stats_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_append_db_stats_test.cpp
@@ -63,8 +63,8 @@ TEST_F(ShardingCatalogClientAppendDbStatsTest, BasicAppendDBStats) {
BSONArrayBuilder builder;
auto future = launchAsync([this, &builder] {
- ASSERT_OK(
- catalogClient()->appendInfoForConfigServerDatabases(operationContext(), &builder));
+ ASSERT_OK(catalogClient()->appendInfoForConfigServerDatabases(
+ operationContext(), BSON("listDatabases" << 1), &builder));
});
onCommand([](const RemoteCommandRequest& request) {
@@ -118,13 +118,49 @@ TEST_F(ShardingCatalogClientAppendDbStatsTest, BasicAppendDBStats) {
ASSERT_TRUE(localIter == dbMap.end());
}
+TEST_F(ShardingCatalogClientAppendDbStatsTest, AppendDBStatsWithFilter) {
+ configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1"));
+
+ BSONArrayBuilder builder;
+ auto future = launchAsync([this, &builder] {
+ ASSERT_OK(catalogClient()->appendInfoForConfigServerDatabases(
+ operationContext(),
+ BSON("listDatabases" << 1 << "filter" << BSON("name"
+ << "config")),
+ &builder));
+ });
+
+ onCommand([](const RemoteCommandRequest& request) {
+ ASSERT_BSONOBJ_EQ(kReplSecondaryOkMetadata,
+ rpc::TrackingMetadata::removeTrackingData(request.metadata));
+
+ ASSERT_EQ("admin", request.dbname);
+ ASSERT_BSONOBJ_EQ(BSON("listDatabases" << 1 << "filter" << BSON("name"
+ << "config")),
+ request.cmdObj);
+
+ return fromjson(R"({
+ databases: [
+ {
+ name: 'config',
+ empty: false,
+ sizeOnDisk: 40000
+ }
+ ],
+ ok: 1
+ })");
+ });
+
+ future.timed_get(kFutureTimeout);
+}
+
TEST_F(ShardingCatalogClientAppendDbStatsTest, ErrorRunningListDatabases) {
configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1"));
BSONArrayBuilder builder;
auto future = launchAsync([this, &builder] {
- auto status =
- catalogClient()->appendInfoForConfigServerDatabases(operationContext(), &builder);
+ auto status = catalogClient()->appendInfoForConfigServerDatabases(
+ operationContext(), BSON("listDatabases" << 1), &builder);
ASSERT_NOT_OK(status);
ASSERT_EQ(ErrorCodes::AuthenticationFailed, status.code());
ASSERT_FALSE(status.reason().empty());
@@ -142,8 +178,8 @@ TEST_F(ShardingCatalogClientAppendDbStatsTest, MalformedListDatabasesResponse) {
BSONArrayBuilder builder;
auto future = launchAsync([this, &builder] {
- auto status =
- catalogClient()->appendInfoForConfigServerDatabases(operationContext(), &builder);
+ auto status = catalogClient()->appendInfoForConfigServerDatabases(
+ operationContext(), BSON("listDatabases" << 1), &builder);
ASSERT_NOT_OK(status);
ASSERT_EQ(ErrorCodes::NoSuchKey, status.code());
ASSERT_FALSE(status.reason().empty());
@@ -159,8 +195,8 @@ TEST_F(ShardingCatalogClientAppendDbStatsTest, MalformedListDatabasesEntryInResp
BSONArrayBuilder builder;
auto future = launchAsync([this, &builder] {
- auto status =
- catalogClient()->appendInfoForConfigServerDatabases(operationContext(), &builder);
+ auto status = catalogClient()->appendInfoForConfigServerDatabases(
+ operationContext(), BSON("listDatabases" << 1), &builder);
ASSERT_NOT_OK(status);
ASSERT_EQ(ErrorCodes::NoSuchKey, status.code());
ASSERT_FALSE(status.reason().empty());
diff --git a/src/mongo/s/catalog/sharding_catalog_client.h b/src/mongo/s/catalog/sharding_catalog_client.h
index 1d736fb222d..f334c05a477 100644
--- a/src/mongo/s/catalog/sharding_catalog_client.h
+++ b/src/mongo/s/catalog/sharding_catalog_client.h
@@ -429,10 +429,12 @@ public:
const WriteConcernOptions& writeConcern) = 0;
/**
- * Appends the information about the config and admin databases in the config server
- * with the format for listDatabase.
+ * Appends the information about the config and admin databases in the config server with the
+ * format for listDatabases, based on the listDatabases command parameters in
+ * 'listDatabasesCmd'.
*/
virtual Status appendInfoForConfigServerDatabases(OperationContext* txn,
+ const BSONObj& listDatabasesCmd,
BSONArrayBuilder* builder) = 0;
/**
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
index 0f364b61e84..01bb420f49a 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
@@ -1683,14 +1683,14 @@ void ShardingCatalogClientImpl::_appendReadConcern(BSONObjBuilder* builder) {
readConcern.appendInfo(builder);
}
-Status ShardingCatalogClientImpl::appendInfoForConfigServerDatabases(OperationContext* txn,
- BSONArrayBuilder* builder) {
+Status ShardingCatalogClientImpl::appendInfoForConfigServerDatabases(
+ OperationContext* txn, const BSONObj& listDatabasesCmd, BSONArrayBuilder* builder) {
auto configShard = Grid::get(txn)->shardRegistry()->getConfigShard();
auto resultStatus =
configShard->runCommandWithFixedRetryAttempts(txn,
kConfigPrimaryPreferredSelector,
"admin",
- BSON("listDatabases" << 1),
+ listDatabasesCmd,
Shard::RetryPolicy::kIdempotent);
if (!resultStatus.isOK()) {
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.h b/src/mongo/s/catalog/sharding_catalog_client_impl.h
index c49b1bd6432..898b3774456 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.h
@@ -174,6 +174,7 @@ public:
DistLockManager* getDistLockManager() override;
Status appendInfoForConfigServerDatabases(OperationContext* txn,
+ const BSONObj& listDatabasesCmd,
BSONArrayBuilder* builder) override;
/**
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
index 7058bff8c2b..11e03fb4c70 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
@@ -227,8 +227,8 @@ DistLockManager* ShardingCatalogClientMock::getDistLockManager() {
return _distLockManager.get();
}
-Status ShardingCatalogClientMock::appendInfoForConfigServerDatabases(OperationContext* txn,
- BSONArrayBuilder* builder) {
+Status ShardingCatalogClientMock::appendInfoForConfigServerDatabases(
+ OperationContext* txn, const BSONObj& listDatabasesCmd, BSONArrayBuilder* builder) {
return Status::OK();
}
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.h b/src/mongo/s/catalog/sharding_catalog_client_mock.h
index fd913a267c3..658681fd37a 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.h
@@ -159,6 +159,7 @@ public:
DistLockManager* getDistLockManager() override;
Status appendInfoForConfigServerDatabases(OperationContext* txn,
+ const BSONObj& listDatabasesCmd,
BSONArrayBuilder* builder) override;
private:
diff --git a/src/mongo/s/commands/cluster_list_databases_cmd.cpp b/src/mongo/s/commands/cluster_list_databases_cmd.cpp
index 9151d244bfe..2ae555e8593 100644
--- a/src/mongo/s/commands/cluster_list_databases_cmd.cpp
+++ b/src/mongo/s/commands/cluster_list_databases_cmd.cpp
@@ -32,6 +32,7 @@
#include <string>
#include <vector>
+#include "mongo/bson/util/bson_extract.h"
#include "mongo/client/read_preference.h"
#include "mongo/client/remote_command_targeter.h"
#include "mongo/db/commands.h"
@@ -105,7 +106,7 @@ public:
txn,
ReadPreferenceSetting{ReadPreference::PrimaryPreferred},
"admin",
- BSON("listDatabases" << 1),
+ cmdObj,
Shard::RetryPolicy::kIdempotent));
uassertStatusOK(response.commandStatus);
BSONObj x = std::move(response.response);
@@ -117,13 +118,13 @@ public:
const string name = dbObj["name"].String();
const long long size = dbObj["sizeOnDisk"].numberLong();
- long long& totalSize = sizes[name];
+ long long& sizeSumForDbAcrossShards = sizes[name];
if (size == 1) {
- if (totalSize <= 1) {
- totalSize = 1;
+ if (sizeSumForDbAcrossShards <= 1) {
+ sizeSumForDbAcrossShards = 1;
}
} else {
- totalSize += size;
+ sizeSumForDbAcrossShards += size;
}
unique_ptr<BSONObjBuilder>& bb = dbShardInfo[name];
@@ -135,8 +136,6 @@ public:
}
}
- long long totalSize = 0;
-
BSONArrayBuilder dbListBuilder(result.subarrayStart("databases"));
for (map<string, long long>::iterator i = sizes.begin(); i != sizes.end(); ++i) {
const string name = i->first;
@@ -152,7 +151,6 @@ public:
}
long long size = i->second;
- totalSize += size;
BSONObjBuilder temp;
temp.append("name", name);
@@ -165,13 +163,25 @@ public:
// Get information for config and admin dbs from the config servers.
auto catalogClient = grid.catalogClient(txn);
- auto appendStatus = catalogClient->appendInfoForConfigServerDatabases(txn, &dbListBuilder);
+ auto appendStatus =
+ catalogClient->appendInfoForConfigServerDatabases(txn, cmdObj, &dbListBuilder);
if (!appendStatus.isOK()) {
return Command::appendCommandStatus(result, appendStatus);
}
dbListBuilder.done();
+ // Compute the combined total size based on the response we've built so far.
+ long long totalSize = 0;
+ for (auto&& dbElt : result.asTempObj()["databases"].Obj()) {
+ long long sizeOnDisk;
+ uassertStatusOK(bsonExtractIntegerField(dbElt.Obj(), "sizeOnDisk"_sd, &sizeOnDisk));
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Found negative 'sizeOnDisk' in: " << dbElt.Obj(),
+ sizeOnDisk >= 0);
+ totalSize += sizeOnDisk;
+ }
+
result.appendNumber("totalSize", totalSize);
result.appendNumber("totalSizeMb", totalSize / (1024 * 1024));