summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/multiVersion/fcv_db_versioning.js50
-rw-r--r--src/mongo/db/commands/set_feature_compatibility_version_command.cpp17
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client.h8
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.cpp34
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.h3
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.cpp5
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.h3
7 files changed, 120 insertions, 0 deletions
diff --git a/jstests/multiVersion/fcv_db_versioning.js b/jstests/multiVersion/fcv_db_versioning.js
new file mode 100644
index 00000000000..bb47b6deafa
--- /dev/null
+++ b/jstests/multiVersion/fcv_db_versioning.js
@@ -0,0 +1,50 @@
+/**
+ * Tests that database versions are properly generated and stored when upgrading from FCV 3.6 to FCV
+ * 4.0 in a sharded cluster.
+ */
+
+(function() {
+ "use strict";
+
+ load("jstests/libs/feature_compatibility_version.js");
+
+ var st = new ShardingTest({
+ shards: 1,
+ shardOptions: {binVersion: "last-stable"},
+ });
+
+ let configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin");
+ let shardPrimaryAdminDB = st.rs0.getPrimary().getDB("admin");
+
+ // Make sure config and shards start with last stable FCV
+ checkFCV(configPrimaryAdminDB, lastStableFCV);
+ checkFCV(shardPrimaryAdminDB, lastStableFCV);
+
+ assert.writeOK(st.s.getDB("test1").foo.insert({_id: "test1", x: 1}));
+ assert.writeOK(st.s.getDB("test2").foo.insert({_id: "test2", x: 1}));
+ assert.neq(null, st.s.getDB("test1").foo.findOne({_id: "test1", x: 1}));
+ assert.neq(null, st.s.getDB("test2").foo.findOne({_id: "test2", x: 1}));
+
+ // Make sure the databases don't have versions when FCV <= 3.6
+ let test1 = st.s.getDB("config").getCollection("databases").findOne({_id: "test1"});
+ assert(!test1.hasOwnProperty("version"), "db test1 has db version before upgrade");
+
+ let test2 = st.s.getDB("config").getCollection("databases").findOne({_id: "test2"});
+ assert(!test2.hasOwnProperty("version"), "db test2 has db version before upgrade");
+
+ // Set FCV to latest
+ assert.commandWorked(
+ configPrimaryAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV}));
+ checkFCV(configPrimaryAdminDB, latestFCV);
+ checkFCV(shardPrimaryAdminDB, latestFCV);
+
+ // Make sure databases were given versions after upgrade
+ test1 = st.s.getDB("config").getCollection("databases").findOne({_id: "test1"});
+ assert(test1.hasOwnProperty("version"), "db test1 does not have db version after upgrade");
+
+ test2 = st.s.getDB("config").getCollection("databases").findOne({_id: "test2"});
+ assert(test2.hasOwnProperty("version"), "db test2 does not have db version after upgrade");
+
+ st.stop();
+
+})(); \ No newline at end of file
diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
index 5772eae91c0..3c1c84e6b34 100644
--- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
+++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
@@ -43,6 +43,8 @@
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/db/server_options.h"
#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/versioning.h"
#include "mongo/util/exit.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/scopeguard.h"
@@ -167,6 +169,21 @@ public:
// Upgrade shards before config finishes its upgrade.
if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) {
+ auto allDbs = uassertStatusOK(Grid::get(opCtx)->catalogClient()->getAllDBs(
+ opCtx, repl::ReadConcernLevel::kLocalReadConcern));
+
+ for (const auto& db : allDbs.value) {
+ const auto dbVersion = Versioning::newDatabaseVersion();
+
+ uassertStatusOK(Grid::get(opCtx)->catalogClient()->updateConfigDocument(
+ opCtx,
+ DatabaseType::ConfigNS,
+ BSON(DatabaseType::name(db.getName())),
+ BSON("$set" << BSON(DatabaseType::version(dbVersion.toBSON()))),
+ false,
+ ShardingCatalogClient::kLocalWriteConcern));
+ }
+
uassertStatusOK(
ShardingCatalogManager::get(opCtx)->setFeatureCompatibilityVersionOnShards(
opCtx,
diff --git a/src/mongo/s/catalog/sharding_catalog_client.h b/src/mongo/s/catalog/sharding_catalog_client.h
index 63de4c670f0..427a4c53775 100644
--- a/src/mongo/s/catalog/sharding_catalog_client.h
+++ b/src/mongo/s/catalog/sharding_catalog_client.h
@@ -131,6 +131,14 @@ public:
repl::ReadConcernLevel readConcernLevel) = 0;
/**
+ * Retrieves all databases in a cluster.
+ *
+ * Returns a !OK status if an error occurs.
+ */
+ virtual StatusWith<repl::OpTimeWith<std::vector<DatabaseType>>> getAllDBs(
+ OperationContext* opCtx, repl::ReadConcernLevel readConcern) = 0;
+
+ /**
* Retrieves the metadata for a given collection, if it exists.
*
* @param nss fully qualified name of the collection (case sensitive)
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
index ed356618bfe..3bdb9b93dba 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
@@ -276,6 +276,40 @@ StatusWith<repl::OpTimeWith<DatabaseType>> ShardingCatalogClientImpl::getDatabas
return result;
}
+StatusWith<repl::OpTimeWith<std::vector<DatabaseType>>> ShardingCatalogClientImpl::getAllDBs(
+ OperationContext* opCtx, repl::ReadConcernLevel readConcern) {
+ std::vector<DatabaseType> databases;
+ auto findStatus = _exhaustiveFindOnConfig(opCtx,
+ kConfigReadSelector,
+ readConcern,
+ DatabaseType::ConfigNS,
+ BSONObj(), // no query filter
+ BSONObj(), // no sort
+ boost::none); // no limit
+ if (!findStatus.isOK()) {
+ return findStatus.getStatus();
+ }
+
+ for (const BSONObj& doc : findStatus.getValue().value) {
+ auto dbRes = DatabaseType::fromBSON(doc);
+ if (!dbRes.isOK()) {
+ return dbRes.getStatus().withContext(stream() << "Failed to parse database document "
+ << doc);
+ }
+
+ Status validateStatus = dbRes.getValue().validate();
+ if (!validateStatus.isOK()) {
+ return validateStatus.withContext(stream() << "Failed to validate database document "
+ << doc);
+ }
+
+ databases.push_back(dbRes.getValue());
+ }
+
+ return repl::OpTimeWith<std::vector<DatabaseType>>{std::move(databases),
+ findStatus.getValue().opTime};
+}
+
StatusWith<repl::OpTimeWith<DatabaseType>> ShardingCatalogClientImpl::_fetchDatabaseMetadata(
OperationContext* opCtx,
const std::string& dbName,
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.h b/src/mongo/s/catalog/sharding_catalog_client_impl.h
index 69ab623b5c2..f20ea1e4ac1 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.h
@@ -91,6 +91,9 @@ public:
const std::string& dbName,
repl::ReadConcernLevel readConcernLevel) override;
+ StatusWith<repl::OpTimeWith<std::vector<DatabaseType>>> getAllDBs(
+ OperationContext* opCtx, repl::ReadConcernLevel readConcern) override;
+
StatusWith<repl::OpTimeWith<CollectionType>> getCollection(
OperationContext* opCtx,
const NamespaceString& nss,
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
index 2dfae2be444..04fdd6b649e 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
@@ -79,6 +79,11 @@ StatusWith<repl::OpTimeWith<DatabaseType>> ShardingCatalogClientMock::getDatabas
return {ErrorCodes::InternalError, "Method not implemented"};
}
+StatusWith<repl::OpTimeWith<std::vector<DatabaseType>>> ShardingCatalogClientMock::getAllDBs(
+ OperationContext* opCtx, repl::ReadConcernLevel readConcern) {
+ return {ErrorCodes::InternalError, "Method not implemented"};
+}
+
StatusWith<repl::OpTimeWith<CollectionType>> ShardingCatalogClientMock::getCollection(
OperationContext* opCtx, const NamespaceString& nss, repl::ReadConcernLevel readConcernLevel) {
return {ErrorCodes::InternalError, "Method not implemented"};
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.h b/src/mongo/s/catalog/sharding_catalog_client_mock.h
index 0ea4e6dd18f..643ef0e3d78 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.h
@@ -55,6 +55,9 @@ public:
const std::string& dbName,
repl::ReadConcernLevel readConcernLevel) override;
+ StatusWith<repl::OpTimeWith<std::vector<DatabaseType>>> getAllDBs(
+ OperationContext* opCtx, repl::ReadConcernLevel readConcern) override;
+
StatusWith<repl::OpTimeWith<CollectionType>> getCollection(
OperationContext* opCtx,
const NamespaceString& nss,