diff options
4 files changed, 57 insertions, 4 deletions
diff --git a/jstests/sharding/libs/resharding_test_fixture.js b/jstests/sharding/libs/resharding_test_fixture.js index 580eb1bf4bb..f536f25435b 100644 --- a/jstests/sharding/libs/resharding_test_fixture.js +++ b/jstests/sharding/libs/resharding_test_fixture.js @@ -58,6 +58,8 @@ var ReshardingTest = class { this._sourceCollectionUUID = undefined; /** @private */ this._tempNs = undefined; + /** @private */ + this._primaryShardName = undefined; // Properties set by startReshardingInBackground() and withReshardingInBackground(). /** @private */ @@ -149,7 +151,8 @@ var ReshardingTest = class { * {min: <shardKeyValue0>, max: <shardKeyValue1>, shard: <shardName>} objects. The chunks must * form a partition of the {shardKey: MinKey} --> {shardKey: MaxKey} space. */ - createShardedCollection({ns, shardKeyPattern, chunks}) { + createShardedCollection( + {ns, shardKeyPattern, chunks, primaryShardName = this.donorShardNames[0]}) { this._ns = ns; this._currentShardKey = Object.assign({}, shardKeyPattern); @@ -169,7 +172,8 @@ var ReshardingTest = class { // collection is unsharded. We configure one of the recipient shards to be the primary shard // for the database so mongos still ends up routing operations to a shard which owns the // temporary resharding collection. - this._st.ensurePrimaryShard(sourceDB.getName(), this.recipientShardNames[0]); + this._st.ensurePrimaryShard(sourceDB.getName(), primaryShardName); + this._primaryShardName = primaryShardName; return sourceCollection; } @@ -627,7 +631,8 @@ var ReshardingTest = class { /** @private */ _checkDonorPostState(donor, expectedErrorCode) { const collInfo = donor.getCollection(this._ns).exists(); - const isAlsoRecipient = this._recipientShards().includes(donor); + const isAlsoRecipient = + this._recipientShards().includes(donor) || donor.shardName === this._primaryShardName; if (expectedErrorCode === ErrorCodes.OK && !isAlsoRecipient) { assert.eq( null, diff --git a/jstests/sharding/resharding_verify_primary_catalog_consistency.js b/jstests/sharding/resharding_verify_primary_catalog_consistency.js new file mode 100644 index 00000000000..63db7e158d3 --- /dev/null +++ b/jstests/sharding/resharding_verify_primary_catalog_consistency.js @@ -0,0 +1,40 @@ +/** + * Tests that the collection catalog entry is updated correctly and is consistent after a resharding + * operation has completed. + * + * @tags: [ + * requires_fcv_49, + * uses_atclustertime, + * ] + */ +(function() { +"use strict"; + +load("jstests/sharding/libs/resharding_test_fixture.js"); + +const reshardingTest = new ReshardingTest({numDonors: 2, reshardInPlace: false}); +reshardingTest.setup(); + +const donorShardNames = reshardingTest.donorShardNames; +const sourceCollection = reshardingTest.createShardedCollection({ + ns: "reshardingDb.coll", + shardKeyPattern: {oldKey: 1}, + chunks: [{min: {oldKey: MinKey}, max: {oldKey: MaxKey}, shard: donorShardNames[1]}], + primaryShardName: donorShardNames[0], +}); + +const originalCollInfo = sourceCollection.exists(); +assert.neq(originalCollInfo, null, "failed to find sharded collection before resharding"); + +const recipientShardNames = reshardingTest.recipientShardNames; +reshardingTest.withReshardingInBackground({ + newShardKeyPattern: {newKey: 1}, + newChunks: [{min: {newKey: MinKey}, max: {newKey: MaxKey}, shard: recipientShardNames[0]}], +}); + +const newCollInfo = sourceCollection.exists(); +assert.neq(newCollInfo, null, "failed to find sharded collection after resharding"); +assert.neq(newCollInfo.info.uuid, originalCollInfo.info.uuid, {newCollInfo, originalCollInfo}); + +reshardingTest.teardown(); +})(); diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service.cpp b/src/mongo/db/s/resharding/resharding_coordinator_service.cpp index 0fbd503d233..3ef29568df1 100644 --- a/src/mongo/db/s/resharding/resharding_coordinator_service.cpp +++ b/src/mongo/db/s/resharding/resharding_coordinator_service.cpp @@ -629,6 +629,10 @@ ParticipantShardsAndChunks calculateParticipantShardsAndChunks( std::set<ShardId> recipientShardIds; std::vector<ChunkType> initialChunks; + // The database primary must always be a recipient to ensure it ends up with consistent + // collection metadata. + recipientShardIds.emplace(cm.dbPrimary()); + if (const auto& chunks = coordinatorDoc.getPresetReshardedChunks()) { auto version = calculateChunkVersionForInitialChunks(opCtx); diff --git a/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp b/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp index 9b577a4f59f..df03a16bddb 100644 --- a/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp +++ b/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp @@ -208,6 +208,10 @@ void processReshardingFieldsForDonorCollection(OperationContext* opCtx, ReshardingDonorDocument>(opCtx, donorDoc); } +bool isCurrentShardPrimary(OperationContext* opCtx, const CollectionMetadata& metadata) { + return metadata.getChunkManager()->dbPrimary() == ShardingState::get(opCtx)->shardId(); +} + /* * Either constructs a new ReshardingRecipientStateMachine with 'reshardingFields' or passes * 'reshardingFields' to an already-existing ReshardingRecipientStateMachine. @@ -243,7 +247,7 @@ void processReshardingFieldsForRecipientCollection(OperationContext* opCtx, // This could be a shard not indicated as a recipient that's trying to refresh the temporary // collection. In this case, we don't want to create a recipient machine. - if (!metadata.currentShardHasAnyChunks()) { + if (!isCurrentShardPrimary(opCtx, metadata) && !metadata.currentShardHasAnyChunks()) { return; } |