summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlake Oler <blake.oler@mongodb.com>2020-10-15 18:35:53 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-11-10 21:14:03 +0000
commitbf30ff31b65e490cac450f91afe45b04c2ea30da (patch)
tree4e4c8d4b9ea713ea2df526b9588756a4a8107d53
parent83162ebfc508346a283463053d858dd7dfe6d97d (diff)
downloadmongo-bf30ff31b65e490cac450f91afe45b04c2ea30da.tar.gz
SERVER-51217 Create temporary resharding collection on recipient
-rw-r--r--jstests/sharding/reshard_collection_basic.js231
-rw-r--r--src/mongo/db/s/config/configsvr_reshard_collection_cmd.cpp4
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service.cpp37
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service.h4
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service_test.cpp10
5 files changed, 179 insertions, 107 deletions
diff --git a/jstests/sharding/reshard_collection_basic.js b/jstests/sharding/reshard_collection_basic.js
index c536503c82a..734fb20fb4b 100644
--- a/jstests/sharding/reshard_collection_basic.js
+++ b/jstests/sharding/reshard_collection_basic.js
@@ -3,25 +3,128 @@
// @tags: [requires_fcv_47]
//
+load("jstests/libs/uuid_util.js");
+
(function() {
'use strict';
const st = new ShardingTest({mongos: 1, shards: 2});
const kDbName = 'db';
-const collName = '.foo';
-const ns = kDbName + collName;
+const collName = 'foo';
+const ns = kDbName + '.' + collName;
const mongos = st.s0;
+const mongosConfig = mongos.getDB('config');
+
+let shardToRSMap = {};
+shardToRSMap[st.shard0.shardName] = st.rs0;
+shardToRSMap[st.shard1.shardName] = st.rs1;
+
+let getUUIDFromCollectionInfo = (dbName, collName, collInfo) => {
+ if (collInfo) {
+ return extractUUIDFromObject(collInfo.info.uuid);
+ }
+
+ const uuidObject = getUUIDFromListCollections(mongos.getDB(dbName), collName);
+ return extractUUIDFromObject(uuidObject);
+};
+
+let constructTemporaryReshardingCollName = (dbName, collName, collInfo) => {
+ const existingUUID = getUUIDFromCollectionInfo(dbName, collName, collInfo);
+ return 'system.resharding.' + existingUUID;
+};
+
+let getAllShardIdsFromExpectedChunks = (expectedChunks) => {
+ let shardIds = new Set();
+ expectedChunks.forEach(chunk => {
+ shardIds.add(chunk.recipientShardId);
+ });
+ return shardIds;
+};
+
+let verifyTemporaryReshardingChunksMatchExpected = (expectedChunks) => {
+ const tempReshardingCollNs =
+ kDbName + '.' + constructTemporaryReshardingCollName(kDbName, collName);
+ const tempReshardingChunks = mongosConfig.chunks.find({ns: tempReshardingCollNs}).toArray();
+
+ expectedChunks.sort();
+ tempReshardingChunks.sort();
+
+ assert.eq(expectedChunks.size, tempReshardingChunks.size);
+ for (let i = 0; i < expectedChunks.size; i++) {
+ assert.eq(expectedChunks[i].recipientShardId, tempReshardingChunks[i].shard);
+ assert.eq(expectedChunks[i].min, tempReshardingChunks[i].min);
+ assert.eq(expectedChunks[i].max, tempReshardingChunks[i].max);
+ }
+};
+
+let verifyTemporaryReshardingCollectionExistsWithCorrectOptionsForConn =
+ (expectedCollInfo, tempCollName, conn) => {
+ const tempReshardingCollInfo =
+ conn.getDB(kDbName).getCollectionInfos({name: tempCollName})[0];
+ assert.neq(tempReshardingCollInfo, null);
+ assert.eq(expectedCollInfo.options, tempReshardingCollInfo.options);
+ };
+
+let verifyTemporaryReshardingCollectionExistsWithCorrectOptions = (expectedRecipientShards) => {
+ const originalCollInfo = mongos.getDB(kDbName).getCollectionInfos({name: collName})[0];
+ assert.neq(originalCollInfo, null);
+
+ const tempReshardingCollName =
+ constructTemporaryReshardingCollName(kDbName, collName, originalCollInfo);
+
+ verifyTemporaryReshardingCollectionExistsWithCorrectOptionsForConn(
+ originalCollInfo, tempReshardingCollName, mongos);
+
+ expectedRecipientShards.forEach(shardId => {
+ verifyTemporaryReshardingCollectionExistsWithCorrectOptionsForConn(
+ originalCollInfo, tempReshardingCollName, shardToRSMap[shardId].getPrimary());
+ });
+};
let removeAllReshardingCollections = () => {
+ const tempReshardingCollName = constructTemporaryReshardingCollName(kDbName, collName);
mongos.getDB(kDbName).foo.drop();
- mongos.getDB('config').reshardingOperations.remove({nss: ns});
- mongos.getDB('config').collections.remove({reshardingFields: {$exists: true}});
+ mongos.getDB(kDbName)[tempReshardingCollName].drop();
+ mongosConfig.reshardingOperations.remove({nss: ns});
+ mongosConfig.collections.remove({reshardingFields: {$exists: true}});
st.rs0.getPrimary().getDB('config').localReshardingOperations.donor.remove({nss: ns});
st.rs0.getPrimary().getDB('config').localReshardingOperations.recipient.remove({nss: ns});
st.rs1.getPrimary().getDB('config').localReshardingOperations.donor.remove({nss: ns});
st.rs1.getPrimary().getDB('config').localReshardingOperations.recipient.remove({nss: ns});
};
+let assertSuccessfulReshardCollection = (commandObj, presetReshardedChunks) => {
+ assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
+
+ if (presetReshardedChunks) {
+ commandObj._presetReshardedChunks = presetReshardedChunks;
+ } else {
+ assert.eq(commandObj._presetReshardedChunks, null);
+ const configChunksArray = mongosConfig.chunks.find({'ns': ns});
+ presetReshardedChunks = [];
+ configChunksArray.forEach(chunk => {
+ presetReshardedChunks.push(
+ {recipientShardId: chunk.shard, min: chunk.min, max: chunk.max});
+ });
+ }
+
+ assert.commandWorked(mongos.adminCommand(commandObj));
+
+ verifyTemporaryReshardingCollectionExistsWithCorrectOptions(
+ getAllShardIdsFromExpectedChunks(presetReshardedChunks));
+ verifyTemporaryReshardingChunksMatchExpected(presetReshardedChunks);
+
+ removeAllReshardingCollections();
+};
+
+let presetReshardedChunks =
+ [{recipientShardId: st.shard1.shardName, min: {_id: MinKey}, max: {_id: MaxKey}}];
+const existingZoneName = 'x1';
+
+/**
+ * Fail cases
+ */
+
// Fail if sharding is disabled.
assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, key: {_id: 1}}),
ErrorCodes.NamespaceNotFound);
@@ -37,39 +140,14 @@ assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
// Fail if missing required key.
assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns}), 40414);
-// Fail if collation is specified and is not {locale: 'simple'}.
-assert.commandFailedWithCode(
- mongos.adminCommand({reshardCollection: ns, key: {_id: 1}, collation: {locale: 'en_US'}}),
- ErrorCodes.BadValue);
-
-// Succeed when correct locale is provided.
-assert.commandWorked(
- mongos.adminCommand({reshardCollection: ns, key: {_id: 1}, collation: {locale: 'simple'}}));
-
-removeAllReshardingCollections();
-
-assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
-
// Fail if unique is specified and is true.
assert.commandFailedWithCode(
mongos.adminCommand({reshardCollection: ns, key: {_id: 1}, unique: true}), ErrorCodes.BadValue);
-// Succeed if unique is specified and is false.
-assert.commandWorked(mongos.adminCommand({reshardCollection: ns, key: {_id: 1}, unique: false}));
-
-removeAllReshardingCollections();
-
-// Succeed if _presetReshardedChunks is provided and test commands are enabled (default).
-assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
-assert.commandWorked(mongos.adminCommand({
- reshardCollection: ns,
- key: {_id: 1},
- _presetReshardedChunks:
- [{recipientShardId: st.shard1.shardName, min: {_id: MinKey}, max: {_id: MaxKey}}]
-}));
-
-removeAllReshardingCollections();
-assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
+// Fail if collation is specified and is not {locale: 'simple'}.
+assert.commandFailedWithCode(
+ mongos.adminCommand({reshardCollection: ns, key: {_id: 1}, collation: {locale: 'en_US'}}),
+ ErrorCodes.BadValue);
// Fail if both numInitialChunks and _presetReshardedChunks are provided.
assert.commandFailedWithCode(mongos.adminCommand({
@@ -78,46 +156,13 @@ assert.commandFailedWithCode(mongos.adminCommand({
unique: false,
collation: {locale: 'simple'},
numInitialChunks: 2,
- _presetReshardedChunks: [
- {recipientShardId: st.shard0.shardName, min: {_id: MinKey}, max: {_id: 0}},
- {recipientShardId: st.shard1.shardName, min: {_id: 0}, max: {_id: MaxKey}}
- ]
+ _presetReshardedChunks: presetReshardedChunks
}),
ErrorCodes.BadValue);
-// Succeed if all optional fields and numInitialChunks are provided with correct values.
-assert.commandWorked(mongos.adminCommand({
- reshardCollection: ns,
- key: {_id: 1},
- unique: false,
- collation: {locale: 'simple'},
- numInitialChunks: 2,
-}));
-
-removeAllReshardingCollections();
-
-// Succeed if all optional fields and _presetReshardedChunks are provided with correct values and
-// test commands are enabled (default).
-assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
-assert.commandWorked(mongos.adminCommand({
- reshardCollection: ns,
- key: {_id: 1},
- unique: false,
- collation: {locale: 'simple'},
- _presetReshardedChunks: [
- {recipientShardId: st.shard1.shardName, min: {_id: 0}, max: {_id: MaxKey}},
- {recipientShardId: st.shard0.shardName, min: {_id: MinKey}, max: {_id: 0}}
- ]
-}));
-
-removeAllReshardingCollections();
-
-const existingZoneName = 'x1';
-
// Fail if authoritative tags exist in config.tags collection and zones are not provided.
assert.commandWorked(
st.s.adminCommand({addShardToZone: st.shard1.shardName, zone: existingZoneName}));
-assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {_id: 1}}));
assert.commandWorked(st.s.adminCommand(
{updateZoneKeyRange: ns, min: {_id: 0}, max: {_id: 5}, zone: existingZoneName}));
@@ -142,21 +187,55 @@ assert.commandFailedWithCode(mongos.adminCommand({
}),
ErrorCodes.BadValue);
+/**
+ * Success cases
+ */
+
+removeAllReshardingCollections();
+
+// Succeed when correct locale is provided.
+assertSuccessfulReshardCollection(
+ {reshardCollection: ns, key: {_id: 1}, collation: {locale: 'simple'}});
+
+// Succeed base case.
+assertSuccessfulReshardCollection({reshardCollection: ns, key: {_id: 1}});
+
+// Succeed if unique is specified and is false.
+assertSuccessfulReshardCollection({reshardCollection: ns, key: {_id: 1}, unique: false});
+
+// Succeed if _presetReshardedChunks is provided and test commands are enabled (default).
+assertSuccessfulReshardCollection({reshardCollection: ns, key: {_id: 1}}, presetReshardedChunks);
+
+presetReshardedChunks = [
+ {recipientShardId: st.shard0.shardName, min: {_id: MinKey}, max: {_id: 0}},
+ {recipientShardId: st.shard1.shardName, min: {_id: 0}, max: {_id: MaxKey}}
+];
+
+// Succeed if all optional fields and numInitialChunks are provided with correct values.
+assertSuccessfulReshardCollection({
+ reshardCollection: ns,
+ key: {_id: 1},
+ unique: false,
+ collation: {locale: 'simple'},
+ numInitialChunks: 2,
+});
+
+// Succeed if all optional fields and _presetReshardedChunks are provided with correct values and
+// test commands are enabled (default).
+assertSuccessfulReshardCollection(
+ {reshardCollection: ns, key: {_id: 1}, unique: false, collation: {locale: 'simple'}},
+ presetReshardedChunks);
+
// Succeed if authoritative tags exist in config.tags collection and zones are provided and use an
// existing zone's name.
-assert.commandWorked(mongos.adminCommand({
+assertSuccessfulReshardCollection({
reshardCollection: ns,
key: {_id: 1},
unique: false,
collation: {locale: 'simple'},
- zones: [{tag: existingZoneName, min: {_id: 5}, max: {_id: 10}, ns: ns}],
- _presetReshardedChunks: [
- {recipientShardId: st.shard1.shardName, min: {_id: 0}, max: {_id: MaxKey}},
- {recipientShardId: st.shard0.shardName, min: {_id: MinKey}, max: {_id: 0}}
- ]
-}));
-
-removeAllReshardingCollections();
+ zones: [{tag: existingZoneName, min: {_id: 5}, max: {_id: 10}, ns: ns}]
+},
+ presetReshardedChunks);
st.stop();
})();
diff --git a/src/mongo/db/s/config/configsvr_reshard_collection_cmd.cpp b/src/mongo/db/s/config/configsvr_reshard_collection_cmd.cpp
index ccebb894ecf..99d097b8528 100644
--- a/src/mongo/db/s/config/configsvr_reshard_collection_cmd.cpp
+++ b/src/mongo/db/s/config/configsvr_reshard_collection_cmd.cpp
@@ -211,9 +211,7 @@ public:
instance->getObserver()->awaitAllDonorsReadyToDonate().wait();
// This promise is currently automatically filled by recipient shards after creating
- // their ReshardingRecipientStateMachines.
- // TODO SERVER-51217 Update this comment to reflect that the temporary collection
- // has been created.
+ // the temporary resharding collection.
instance->getObserver()->awaitAllRecipientsFinishedApplying().wait();
instance->interrupt(
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.cpp b/src/mongo/db/s/resharding/resharding_recipient_service.cpp
index 25c87941614..1f62ed5c3ae 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service.cpp
+++ b/src/mongo/db/s/resharding/resharding_recipient_service.cpp
@@ -49,21 +49,15 @@ namespace mongo {
namespace resharding {
void createTemporaryReshardingCollectionLocally(OperationContext* opCtx,
- const NamespaceString& reshardingNss,
+ const NamespaceString& originalNss,
+ const UUID& reshardingUUID,
+ const UUID& existingUUID,
Timestamp fetchTimestamp) {
LOGV2_DEBUG(
- 5002300, 1, "Creating temporary resharding collection", "namespace"_attr = reshardingNss);
+ 5002300, 1, "Creating temporary resharding collection", "originalNss"_attr = originalNss);
auto catalogCache = Grid::get(opCtx)->catalogCache();
- auto reshardingCm =
- uassertStatusOK(catalogCache->getCollectionRoutingInfo(opCtx, reshardingNss));
- uassert(
- 5002301,
- "Expected cached metadata for resharding temporary collection to have resharding fields",
- reshardingCm.getReshardingFields() &&
- reshardingCm.getReshardingFields()->getRecipientFields());
- auto originalNss =
- reshardingCm.getReshardingFields()->getRecipientFields()->getOriginalNamespace();
+ auto reshardingNss = constructTemporaryReshardingNss(originalNss.db(), existingUUID);
// Load the original collection's options from the database's primary shard.
auto [collOptions, uuid] = sharded_agg_helpers::shardVersionRetry(
@@ -74,12 +68,9 @@ void createTemporaryReshardingCollectionLocally(OperationContext* opCtx,
[&]() -> MigrationDestinationManager::CollectionOptionsAndUUID {
auto originalCm =
uassertStatusOK(catalogCache->getCollectionRoutingInfo(opCtx, originalNss));
- uassert(ErrorCodes::InvalidUUID,
- "Expected cached metadata for resharding temporary collection to have a UUID",
- originalCm.getUUID());
return MigrationDestinationManager::getCollectionOptions(
opCtx,
- NamespaceStringOrUUID(originalNss.db().toString(), *originalCm.getUUID()),
+ NamespaceStringOrUUID(originalNss.db().toString(), existingUUID),
originalCm.dbPrimary(),
originalCm,
fetchTimestamp);
@@ -97,13 +88,10 @@ void createTemporaryReshardingCollectionLocally(OperationContext* opCtx,
uassert(ErrorCodes::NamespaceNotSharded,
str::stream() << "Expected collection " << originalNss << " to be sharded",
originalCm.isSharded());
- uassert(ErrorCodes::InvalidUUID,
- "Expected cached metadata for resharding temporary collection to have a UUID",
- originalCm.getUUID());
auto indexShardId = originalCm.getMinKeyShardIdWithSimpleCollation();
return MigrationDestinationManager::getCollectionIndexes(
opCtx,
- NamespaceStringOrUUID(originalNss.db().toString(), *originalCm.getUUID()),
+ NamespaceStringOrUUID(originalNss.db().toString(), existingUUID),
indexShardId,
originalCm,
fetchTimestamp);
@@ -111,7 +99,6 @@ void createTemporaryReshardingCollectionLocally(OperationContext* opCtx,
// Set the temporary resharding collection's UUID to the resharding UUID. Note that
// BSONObj::addFields() replaces any fields that already exist.
- auto reshardingUUID = reshardingCm.getReshardingFields()->getUuid();
collOptions = collOptions.addFields(BSON("uuid" << reshardingUUID));
CollectionOptionsAndIndexes optionsAndIndexes = {reshardingUUID, indexes, idIndex, collOptions};
@@ -216,8 +203,14 @@ void ReshardingRecipientService::RecipientStateMachine::
return;
}
- // TODO SERVER-51217: Call
- // resharding_recipient_service_util::createTemporaryReshardingCollectionLocally()
+ {
+ auto opCtx = cc().makeOperationContext();
+ resharding::createTemporaryReshardingCollectionLocally(opCtx.get(),
+ _recipientDoc.getNss(),
+ _recipientDoc.get_id(),
+ _recipientDoc.getExistingUUID(),
+ *_recipientDoc.getFetchTimestamp());
+ }
_transitionState(RecipientStateEnum::kCloning);
}
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.h b/src/mongo/db/s/resharding/resharding_recipient_service.h
index 9c53b20ca8a..da04ed475cf 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service.h
+++ b/src/mongo/db/s/resharding/resharding_recipient_service.h
@@ -44,7 +44,9 @@ namespace resharding {
* respectively.
*/
void createTemporaryReshardingCollectionLocally(OperationContext* opCtx,
- const NamespaceString& reshardingNss,
+ const NamespaceString& originalNss,
+ const UUID& reshardingUUID,
+ const UUID& existingUUID,
Timestamp fetchTimestamp);
} // namespace resharding
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp b/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
index debfc34017a..341b8c96c26 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
@@ -251,7 +251,7 @@ TEST_F(ReshardingRecipientServiceTest, CreateLocalReshardingCollectionBasic) {
});
resharding::createTemporaryReshardingCollectionLocally(
- operationContext(), kReshardingNss, kDefaultFetchTimestamp);
+ operationContext(), kOrigNss, kReshardingUUID, kOrigUUID, kDefaultFetchTimestamp);
future.default_timed_get();
@@ -301,7 +301,7 @@ TEST_F(ReshardingRecipientServiceTest,
});
resharding::createTemporaryReshardingCollectionLocally(
- operationContext(), kReshardingNss, kDefaultFetchTimestamp);
+ operationContext(), kOrigNss, kReshardingUUID, kOrigUUID, kDefaultFetchTimestamp);
future.default_timed_get();
@@ -362,7 +362,7 @@ TEST_F(ReshardingRecipientServiceTest,
});
resharding::createTemporaryReshardingCollectionLocally(
- operationContext(), kReshardingNss, kDefaultFetchTimestamp);
+ operationContext(), kOrigNss, kReshardingUUID, kOrigUUID, kDefaultFetchTimestamp);
future.default_timed_get();
@@ -425,7 +425,7 @@ TEST_F(ReshardingRecipientServiceTest,
});
resharding::createTemporaryReshardingCollectionLocally(
- operationContext(), kReshardingNss, kDefaultFetchTimestamp);
+ operationContext(), kOrigNss, kReshardingUUID, kOrigUUID, kDefaultFetchTimestamp);
future.default_timed_get();
@@ -478,7 +478,7 @@ TEST_F(ReshardingRecipientServiceTest,
});
resharding::createTemporaryReshardingCollectionLocally(
- operationContext(), kReshardingNss, kDefaultFetchTimestamp);
+ operationContext(), kOrigNss, kReshardingUUID, kOrigUUID, kDefaultFetchTimestamp);
future.default_timed_get();