0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

SERVER-68511 MovePrimary update of config.databases entry must use dotted fields notation

This commit is contained in:
Pierlauro Sciarelli 2022-08-04 16:53:42 +00:00 committed by Evergreen Agent
parent 963be63f32
commit 2bddb8f08f
2 changed files with 121 additions and 18 deletions

View File

@ -0,0 +1,84 @@
/**
* Test that `movePrimary` works for databases created under a different FCV
*/
(function() {
"use strict";
let st = new ShardingTest({shards: 2, mongos: 1, rs: {nodes: 1}});
const mongos = st.s;
const kBeforeDowngradingDbName = 'createdBeforeDowngrading';
const kBeforeUpgradingDbName = 'createdBeforeUpgrading';
const shard0 = st.shard0.shardName;
const shard1 = st.shard1.shardName;
const createdBeforeDowngradingDB = mongos.getDB(kBeforeDowngradingDbName);
const createdBeforeUpgradingDB = mongos.getDB(kBeforeUpgradingDbName);
const fcvValues = [lastLTSFCV, lastContinuousFCV];
function testMovePrimary(db) {
const dbName = db.getName();
// The following pipeline update modifies the config.databases entry to simulate its database
// version field order as having come from running {setFeatureCompatibility: "5.0"} as part of
// upgrading from MongoDB 4.4. See SERVER-68511 for more details of the original issue.
mongos.getDB('config').databases.update({_id: dbName}, [{
$replaceWith: {
$mergeObjects: [
"$$ROOT",
{
version: {
uuid: "$version.uuid",
lastMod: "$version.lastMod",
timestamp: "$version.timestamp"
}
}
]
}
}]);
const currentPrimary = mongos.getDB('config').databases.findOne({_id: dbName}).primary;
const newPrimary = currentPrimary == shard0 ? shard1 : shard0;
assert.eq(db.coll.countDocuments({}), 1);
assert.commandWorked(mongos.adminCommand({movePrimary: dbName, to: newPrimary}));
assert.eq(newPrimary, mongos.getDB('config').databases.findOne({_id: dbName}).primary);
assert.eq(db.coll.countDocuments({}), 1);
}
for (var i = 0; i < fcvValues.length; i++) {
// Latest FCV
assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
// Create database `createdBeforeDowngrading` under latest FCV
assert.commandWorked(
mongos.adminCommand({enableSharding: kBeforeDowngradingDbName, primaryShard: shard0}));
assert.commandWorked(createdBeforeDowngradingDB.coll.insert({_id: 'foo'}));
// Downgrade FCV
assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: fcvValues[i]}));
// Make sure movePrimary works for `createdBeforeDowngrading`
testMovePrimary(createdBeforeDowngradingDB);
// Create database `createdBeforeUpgrading` under downgraded FCV
assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
assert.commandWorked(
mongos.adminCommand({enableSharding: kBeforeUpgradingDbName, primaryShard: shard0}));
assert.commandWorked(createdBeforeUpgradingDB.coll.insert({_id: 'foo'}));
// Upgrade FCV
assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
// Make sure movePrimary works (again) for `createdBeforeDowngrading`
testMovePrimary(createdBeforeDowngradingDB);
// Make sure movePrimary works for `createdBeforeUpgrading`
testMovePrimary(createdBeforeUpgradingDB);
// Drop databases for next round
assert.commandWorked(createdBeforeDowngradingDB.dropDatabase());
assert.commandWorked(createdBeforeUpgradingDB.dropDatabase());
}
st.stop();
})();

View File

@ -329,23 +329,26 @@ Status MovePrimarySourceManager::commitOnConfig(OperationContext* opCtx) {
Status MovePrimarySourceManager::_commitOnConfig(OperationContext* opCtx) {
auto const configShard = Grid::get(opCtx)->shardRegistry()->getConfigShard();
auto findResponse = uassertStatusOK(
configShard->exhaustiveFindOnConfig(opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
repl::ReadConcernLevel::kMajorityReadConcern,
NamespaceString::kConfigDatabasesNamespace,
BSON(DatabaseType::kNameFieldName << _dbname),
BSON(DatabaseType::kNameFieldName << -1),
1));
auto getDatabaseEntry = [&]() {
auto findResponse = uassertStatusOK(
configShard->exhaustiveFindOnConfig(opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
repl::ReadConcernLevel::kMajorityReadConcern,
NamespaceString::kConfigDatabasesNamespace,
BSON(DatabaseType::kNameFieldName << _dbname),
BSON(DatabaseType::kNameFieldName << -1),
1));
const auto databasesVector = std::move(findResponse.docs);
uassert(ErrorCodes::IncompatibleShardingMetadata,
str::stream() << "Tried to find max database version for database '" << _dbname
<< "', but found no databases",
!databasesVector.empty());
const auto databasesVector = std::move(findResponse.docs);
uassert(ErrorCodes::IncompatibleShardingMetadata,
str::stream() << "Tried to find max database version for database '" << _dbname
<< "', but found no databases",
!databasesVector.empty());
const auto dbType =
DatabaseType::parse(IDLParserContext("DatabaseType"), databasesVector.front());
return DatabaseType::parse(IDLParserContext("DatabaseType"), databasesVector.front());
};
const auto dbType = getDatabaseEntry();
if (dbType.getPrimary() == _toShard) {
return Status::OK();
@ -358,9 +361,17 @@ Status MovePrimarySourceManager::_commitOnConfig(OperationContext* opCtx) {
newDbType.setVersion(currentDatabaseVersion.makeUpdated());
auto const updateQuery =
BSON(DatabaseType::kNameFieldName << _dbname << DatabaseType::kVersionFieldName
<< currentDatabaseVersion.toBSON());
auto const updateQuery = [&] {
BSONObjBuilder queryBuilder;
queryBuilder.append(DatabaseType::kNameFieldName, _dbname);
// Include the version in the update filter to be resilient to potential network retries and
// delayed messages.
for (auto [fieldName, elem] : currentDatabaseVersion.toBSON()) {
auto dottedFieldName = DatabaseType::kVersionFieldName + "." + fieldName;
queryBuilder.appendAs(elem, dottedFieldName);
}
return queryBuilder.obj();
}();
auto updateStatus = Grid::get(opCtx)->catalogClient()->updateConfigDocument(
opCtx,
@ -379,6 +390,14 @@ Status MovePrimarySourceManager::_commitOnConfig(OperationContext* opCtx) {
return updateStatus.getStatus();
}
const auto updatedDbType = getDatabaseEntry();
tassert(6851100,
"Error committing movePrimary: database version went backwards",
updatedDbType.getVersion() > currentDatabaseVersion);
uassert(6851101,
"Error committing movePrimary: update of `config.databases` failed",
updatedDbType.getPrimary() != _fromShard);
return Status::OK();
}