From 252d3a718ca84b627b4934326646bc359876708b Mon Sep 17 00:00:00 2001 From: jannaerin Date: Tue, 2 Feb 2021 22:47:47 +0000 Subject: SERVER-53567 Create conflict stash collections with same collation as temporary resharding collection --- .../db/s/resharding/resharding_data_copy_util.cpp | 6 ++- .../db/s/resharding/resharding_data_copy_util.h | 9 +++- .../db/s/resharding/resharding_oplog_applier.cpp | 10 +++-- .../db/s/resharding/resharding_oplog_applier.h | 3 +- .../s/resharding/resharding_recipient_service.cpp | 40 +++++++++++++----- .../db/s/resharding/resharding_recipient_service.h | 6 +++ .../resharding_recipient_service_test.cpp | 49 +++++++++++++++++++++- 7 files changed, 104 insertions(+), 19 deletions(-) diff --git a/src/mongo/db/s/resharding/resharding_data_copy_util.cpp b/src/mongo/db/s/resharding/resharding_data_copy_util.cpp index ad85a69d241..f870643e257 100644 --- a/src/mongo/db/s/resharding/resharding_data_copy_util.cpp +++ b/src/mongo/db/s/resharding/resharding_data_copy_util.cpp @@ -39,7 +39,9 @@ namespace mongo::resharding::data_copy { -void ensureCollectionExists(OperationContext* opCtx, const NamespaceString& nss) { +void ensureCollectionExists(OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& options) { invariant(!opCtx->lockState()->isLocked()); invariant(!opCtx->lockState()->inAWriteUnitOfWork()); @@ -50,7 +52,7 @@ void ensureCollectionExists(OperationContext* opCtx, const NamespaceString& nss) } WriteUnitOfWork wuow(opCtx); - coll.ensureDbExists()->createCollection(opCtx, nss); + coll.ensureDbExists()->createCollection(opCtx, nss, options); wuow.commit(); }); } diff --git a/src/mongo/db/s/resharding/resharding_data_copy_util.h b/src/mongo/db/s/resharding/resharding_data_copy_util.h index 22b96a1b26a..3374b8c7228 100644 --- a/src/mongo/db/s/resharding/resharding_data_copy_util.h +++ b/src/mongo/db/s/resharding/resharding_data_copy_util.h @@ -40,7 +40,14 @@ class OperationContext; namespace resharding::data_copy { -void ensureCollectionExists(OperationContext* opCtx, const NamespaceString& nss); +/** + * Creates the specified collection with the given options if the collection does not already exist. + * If the collection already exists, we do not compare the options because the resharding process + * will always use the same options for the same namespace. + */ +void ensureCollectionExists(OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& options); /** * Drops the specified collection or returns without error if the collection has already been diff --git a/src/mongo/db/s/resharding/resharding_oplog_applier.cpp b/src/mongo/db/s/resharding/resharding_oplog_applier.cpp index 263b8e05ec4..e2b4cc76667 100644 --- a/src/mongo/db/s/resharding/resharding_oplog_applier.cpp +++ b/src/mongo/db/s/resharding/resharding_oplog_applier.cpp @@ -496,14 +496,16 @@ Timestamp ReshardingOplogApplier::_clearAppliedOpsAndStoreProgress(OperationCont return lastAppliedTs; } -NamespaceString ReshardingOplogApplier::ensureStashCollectionExists(OperationContext* opCtx, - const UUID& existingUUID, - const ShardId& donorShardId) { +NamespaceString ReshardingOplogApplier::ensureStashCollectionExists( + OperationContext* opCtx, + const UUID& existingUUID, + const ShardId& donorShardId, + const CollectionOptions& options) { auto nss = NamespaceString{NamespaceString::kConfigDb, "localReshardingConflictStash.{}.{}"_format( existingUUID.toString(), donorShardId.toString())}; - resharding::data_copy::ensureCollectionExists(opCtx, nss); + resharding::data_copy::ensureCollectionExists(opCtx, nss, options); return nss; } diff --git a/src/mongo/db/s/resharding/resharding_oplog_applier.h b/src/mongo/db/s/resharding/resharding_oplog_applier.h index 71462dbc9a0..e0b7b4df5da 100644 --- a/src/mongo/db/s/resharding/resharding_oplog_applier.h +++ b/src/mongo/db/s/resharding/resharding_oplog_applier.h @@ -86,7 +86,8 @@ public: static NamespaceString ensureStashCollectionExists(OperationContext* opCtx, const UUID& existingUUID, - const ShardId& donorShardId); + const ShardId& donorShardId, + const CollectionOptions& options); private: using OplogBatch = std::vector; diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.cpp b/src/mongo/db/s/resharding/resharding_recipient_service.cpp index 548072bc3d4..cafff767d33 100644 --- a/src/mongo/db/s/resharding/resharding_recipient_service.cpp +++ b/src/mongo/db/s/resharding/resharding_recipient_service.cpp @@ -138,12 +138,35 @@ 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. collOptions = collOptions.addFields(BSON("uuid" << reshardingUUID)); - CollectionOptionsAndIndexes optionsAndIndexes = {reshardingUUID, indexes, idIndex, collOptions}; MigrationDestinationManager::cloneCollectionIndexesAndOptions( opCtx, reshardingNss, optionsAndIndexes); } +std::vector ensureStashCollectionsExist( + OperationContext* opCtx, + const ChunkManager& cm, + const UUID& existingUUID, + std::vector donorShards) { + // Use the same collation for the stash collections as the temporary resharding collection + auto collator = cm.getDefaultCollator(); + BSONObj collationSpec = collator ? collator->getSpec().toBSON() : BSONObj(); + + std::vector stashCollections; + stashCollections.reserve(donorShards.size()); + + { + CollectionOptions options; + options.collation = std::move(collationSpec); + for (const auto& donor : donorShards) { + stashCollections.emplace_back(ReshardingOplogApplier::ensureStashCollectionExists( + opCtx, existingUUID, donor.getId(), options)); + } + } + + return stashCollections; +} + } // namespace resharding std::shared_ptr ReshardingRecipientService::constructInstance( @@ -420,16 +443,13 @@ ExecutorFuture ReshardingRecipientService::RecipientStateMachine:: return catalogCache->getShardedCollectionRoutingInfo(opCtx.get(), _recipientDoc.getNss()); }(); - std::vector stashCollections; - stashCollections.reserve(numDonors); - - { + auto stashCollections = [&] { auto opCtx = cc().makeOperationContext(); - for (const auto& donor : _recipientDoc.getDonorShardsMirroring()) { - stashCollections.emplace_back(ReshardingOplogApplier::ensureStashCollectionExists( - opCtx.get(), _recipientDoc.getExistingUUID(), donor.getId())); - } - } + return resharding::ensureStashCollectionsExist(opCtx.get(), + sourceChunkMgr, + _recipientDoc.getExistingUUID(), + _recipientDoc.getDonorShardsMirroring()); + }(); size_t i = 0; auto futuresToWaitOn = std::move(_oplogFetcherFutures); diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.h b/src/mongo/db/s/resharding/resharding_recipient_service.h index 045a55bc1a8..71939cdb06c 100644 --- a/src/mongo/db/s/resharding/resharding_recipient_service.h +++ b/src/mongo/db/s/resharding/resharding_recipient_service.h @@ -54,6 +54,12 @@ void createTemporaryReshardingCollectionLocally(OperationContext* opCtx, const UUID& existingUUID, Timestamp fetchTimestamp); +std::vector ensureStashCollectionsExist( + OperationContext* opCtx, + const ChunkManager& cm, + const UUID& existingUUID, + std::vector donorShards); + } // namespace resharding class ReshardingRecipientService final : public repl::PrimaryOnlyService { 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 f8380457895..8a03ed223c6 100644 --- a/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp +++ b/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp @@ -34,6 +34,8 @@ #include "mongo/bson/unordered_fields_bsonobj_comparator.h" #include "mongo/db/catalog_raii.h" #include "mongo/db/dbdirectclient.h" +#include "mongo/db/query/collation/collator_factory_interface.h" +#include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/replication_coordinator_mock.h" #include "mongo/db/repl/storage_interface_impl.h" @@ -133,13 +135,15 @@ public: const NamespaceString& origNss, const ShardKeyPattern& skey, UUID uuid, - OID epoch) { + OID epoch, + const BSONObj& collation = {}) { auto future = scheduleRoutingInfoForcedRefresh(tempNss); expectFindSendBSONObjVector(kConfigHostAndPort, [&]() { CollectionType coll(tempNss, epoch, Date_t::now(), uuid); coll.setKeyPattern(skey.getKeyPattern()); coll.setUnique(false); + coll.setDefaultCollation(collation); TypeCollectionReshardingFields reshardingFields; reshardingFields.setUuid(uuid); @@ -539,5 +543,48 @@ TEST_F(ReshardingRecipientServiceTest, verifyCollectionAndIndexes(kReshardingNss, kReshardingUUID, indexes); } +TEST_F(ReshardingRecipientServiceTest, StashCollectionsHaveSameCollationAsReshardingCollection) { + auto shards = setupNShards(2); + + std::unique_ptr collator = + std::make_unique(CollatorInterfaceMock::MockType::kReverseString); + auto collationSpec = collator->getSpec().toBSON(); + auto srcChunkMgr = makeChunkManager(kOrigNss, + ShardKeyPattern(BSON("_id" << 1)), + std::move(collator), + false /* unique */, + {} /* splitPoints */); + + // Create stash collections for both donor shards + auto stashCollections = resharding::ensureStashCollectionsExist( + operationContext(), + srcChunkMgr, + kOrigUUID, + {DonorShardMirroringEntry(ShardId("shard0"), true), + DonorShardMirroringEntry(ShardId("shard1"), true)}); + + // Verify that each stash collation has the collation we passed in above + { + auto opCtx = operationContext(); + + DBDirectClient client(opCtx); + auto collInfos = client.getCollectionInfos("config"); + StringMap nsToOptions; + for (const auto& coll : collInfos) { + nsToOptions[coll["name"].str()] = coll["options"].Obj(); + } + + for (const auto& coll : stashCollections) { + auto it = nsToOptions.find(coll.coll()); + ASSERT(it != nsToOptions.end()); + auto options = it->second; + + ASSERT(options.hasField("collation")); + auto collation = options["collation"].Obj(); + ASSERT_BSONOBJ_EQ(collationSpec, collation); + } + } +} + } // namespace } // namespace mongo -- cgit v1.2.1