diff options
author | Cheahuychou Mao <cheahuychou.mao@mongodb.com> | 2020-01-20 01:58:47 +0000 |
---|---|---|
committer | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2020-01-27 15:40:41 -0500 |
commit | a8c79b41242dde27db00a60a17fe0d60f5fa3c8a (patch) | |
tree | 7a0a439b1f7c95b1b0edf68005a05dfc289d0794 | |
parent | a56f09f03498b68985df062db12d84f0b0c7d905 (diff) | |
download | mongo-a8c79b41242dde27db00a60a17fe0d60f5fa3c8a.tar.gz |
SERVER-45249 Make recipient wait for orphan cleanup before cloning indexes
-rw-r--r-- | jstests/libs/chunk_manipulation_util.js | 10 | ||||
-rw-r--r-- | src/mongo/base/error_codes.yml | 2 | ||||
-rw-r--r-- | src/mongo/db/s/clone_collection_options_from_primary_shard_cmd.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime.h | 6 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.cpp | 200 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.h | 23 | ||||
-rw-r--r-- | src/mongo/db/s/migration_source_manager.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/s/range_deletion_util.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/s/range_deletion_util_test.cpp | 15 |
10 files changed, 171 insertions, 126 deletions
diff --git a/jstests/libs/chunk_manipulation_util.js b/jstests/libs/chunk_manipulation_util.js index 90ea743ecf3..bba74a17886 100644 --- a/jstests/libs/chunk_manipulation_util.js +++ b/jstests/libs/chunk_manipulation_util.js @@ -127,7 +127,7 @@ function configureMoveChunkFailPoint(shardConnection, stepNumber, mode) { function waitForMoveChunkStep(shardConnection, stepNumber) { var searchString = 'step ' + stepNumber, admin = shardConnection.getDB('admin'); - assert.between(migrateStepNames.copiedIndexes, + assert.between(migrateStepNames.deletedPriorDataInRange, stepNumber, migrateStepNames.done, "incorrect stepNumber", @@ -158,8 +158,8 @@ function waitForMoveChunkStep(shardConnection, stepNumber) { } var migrateStepNames = { - copiedIndexes: 1, - deletedPriorDataInRange: 2, + deletedPriorDataInRange: 1, + copiedIndexes: 2, cloned: 3, catchup: 4, // About to enter steady state. steady: 5, @@ -191,7 +191,7 @@ function proceedToMigrateStep(shardConnection, stepNumber) { } function configureMigrateFailPoint(shardConnection, stepNumber, mode) { - assert.between(migrateStepNames.copiedIndexes, + assert.between(migrateStepNames.deletedPriorDataInRange, stepNumber, migrateStepNames.done, "incorrect stepNumber", @@ -208,7 +208,7 @@ function configureMigrateFailPoint(shardConnection, stepNumber, mode) { function waitForMigrateStep(shardConnection, stepNumber) { var searchString = 'step ' + stepNumber, admin = shardConnection.getDB('admin'); - assert.between(migrateStepNames.copiedIndexes, + assert.between(migrateStepNames.deletedPriorDataInRange, stepNumber, migrateStepNames.done, "incorrect stepNumber", diff --git a/src/mongo/base/error_codes.yml b/src/mongo/base/error_codes.yml index baa25cc2821..71f09e7d92a 100644 --- a/src/mongo/base/error_codes.yml +++ b/src/mongo/base/error_codes.yml @@ -333,7 +333,7 @@ error_codes: - {code: 297,name: HierarchicalAcquisitionLevelViolation} - {code: 298,name: InvalidServerType} - {code: 299,name: OCSPCertificateStatusRevoked} - - {code: 300,name: RangeDeletionAbandonedDueToCollectionDrop} + - {code: 300,name: RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist} - {code: 301,name: DataCorruptionDetected} # Error codes 4000-8999 are reserved. diff --git a/src/mongo/db/s/clone_collection_options_from_primary_shard_cmd.cpp b/src/mongo/db/s/clone_collection_options_from_primary_shard_cmd.cpp index 963c1c660a2..7f7439ae15b 100644 --- a/src/mongo/db/s/clone_collection_options_from_primary_shard_cmd.cpp +++ b/src/mongo/db/s/clone_collection_options_from_primary_shard_cmd.cpp @@ -52,8 +52,11 @@ public: void typedRun(OperationContext* opCtx) { auto primaryShardId = ShardId(request().getPrimaryShard().toString()); + auto collectionOptionsAndIndexes = + MigrationDestinationManager::getCollectionIndexesAndOptions( + opCtx, ns(), primaryShardId); MigrationDestinationManager::cloneCollectionIndexesAndOptions( - opCtx, ns(), primaryShardId); + opCtx, ns(), collectionOptionsAndIndexes); // At the time this command is invoked, the config server primary has already written // the collection's routing metadata, so sync from the config server diff --git a/src/mongo/db/s/collection_sharding_runtime.cpp b/src/mongo/db/s/collection_sharding_runtime.cpp index 93b4529d502..bef293677d8 100644 --- a/src/mongo/db/s/collection_sharding_runtime.cpp +++ b/src/mongo/db/s/collection_sharding_runtime.cpp @@ -248,7 +248,7 @@ SharedSemiFuture<void> CollectionShardingRuntime::cleanUpRange(ChunkRange const& Status CollectionShardingRuntime::waitForClean(OperationContext* opCtx, const NamespaceString& nss, - OID const& epoch, + const UUID& collectionUuid, ChunkRange orphanRange) { while (true) { boost::optional<SharedSemiFuture<void>> stillScheduled; @@ -258,13 +258,13 @@ Status CollectionShardingRuntime::waitForClean(OperationContext* opCtx, auto* const self = CollectionShardingRuntime::get(opCtx, nss); stdx::lock_guard lk(self->_metadataManagerLock); - // If the metadata was reset, the collection does not exist, or the collection was - // dropped and recreated since the metadata manager was created, return an error. - if (!self->_metadataManager || !autoColl.getCollection() || - autoColl.getCollection()->uuid() != self->_metadataManager->getCollectionUuid()) { + // If the metadata was reset, or the collection was dropped and recreated since the + // metadata manager was created, return an error. + if (!self->_metadataManager || + (collectionUuid != self->_metadataManager->getCollectionUuid())) { return {ErrorCodes::ConflictingOperationInProgress, - "Collection being migrated was dropped or otherwise had its metadata " - "reset"}; + "Collection being migrated was dropped and created or otherwise had its " + "metadata reset"}; } stillScheduled = self->_metadataManager->trackOrphanedDataCleanup(orphanRange); @@ -278,7 +278,12 @@ Status CollectionShardingRuntime::waitForClean(OperationContext* opCtx, log() << "Waiting for deletion of " << nss.ns() << " range " << orphanRange; Status result = stillScheduled->getNoThrow(opCtx); - if (!result.isOK()) { + + // Swallow RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist error since the + // collection could either never exist or get dropped directly from the shard after + // the range deletion task got scheduled. + if (!result.isOK() && + result != ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist) { return result.withContext(str::stream() << "Failed to delete orphaned " << nss.ns() << " range " << orphanRange.toString()); } diff --git a/src/mongo/db/s/collection_sharding_runtime.h b/src/mongo/db/s/collection_sharding_runtime.h index 054f637440e..9e0e3a7f9e4 100644 --- a/src/mongo/db/s/collection_sharding_runtime.h +++ b/src/mongo/db/s/collection_sharding_runtime.h @@ -74,12 +74,12 @@ public: const NamespaceString& nss); /** - * Tracks deletion of any documents within the range, returning when deletion is complete. - * Throws if the collection is dropped while it sleeps. + * Waits for all ranges deletion tasks with UUID 'collectionUuid' overlapping range + * 'orphanRange' to be processed, even if the collection does not exist in the storage catalog. */ static Status waitForClean(OperationContext* opCtx, const NamespaceString& nss, - OID const& epoch, + const UUID& collectionUuid, ChunkRange orphanRange); ScopedCollectionMetadata getOrphansFilter(OperationContext* opCtx, bool isCollection) override; diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index 63d098e96a0..ad170299a1a 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -531,9 +531,8 @@ Status MigrationDestinationManager::startCommit(const MigrationSessionId& sessio return Status::OK(); } -void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationContext* opCtx, - const NamespaceString& nss, - const ShardId& fromShardId) { +CollectionOptionsAndIndexes MigrationDestinationManager::getCollectionIndexesAndOptions( + OperationContext* opCtx, const NamespaceString& nss, const ShardId& fromShardId) { auto fromShard = uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, fromShardId)); @@ -542,73 +541,80 @@ void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationCont std::vector<BSONObj> donorIndexSpecs; BSONObj donorIdIndexSpec; BSONObj donorOptions; - { - // 0. Get the collection indexes and options from the donor shard. - - // Do not hold any locks while issuing remote calls. - invariant(!opCtx->lockState()->isLocked()); - - // Get indexes by calling listIndexes against the donor. - auto indexes = uassertStatusOK(fromShard->runExhaustiveCursorCommand( - opCtx, - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - nss.db().toString(), - BSON("listIndexes" << nss.coll().toString()), - Milliseconds(-1))); - - for (auto&& spec : indexes.docs) { - donorIndexSpecs.push_back(spec); - if (auto indexNameElem = spec[IndexDescriptor::kIndexNameFieldName]) { - if (indexNameElem.type() == BSONType::String && - indexNameElem.valueStringData() == "_id_"_sd) { - donorIdIndexSpec = spec; - } + + // Get the collection indexes and options from the donor shard. + + // Do not hold any locks while issuing remote calls. + invariant(!opCtx->lockState()->isLocked()); + + // Get indexes by calling listIndexes against the donor. + auto indexes = uassertStatusOK( + fromShard->runExhaustiveCursorCommand(opCtx, + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + nss.db().toString(), + BSON("listIndexes" << nss.coll().toString()), + Milliseconds(-1))); + + for (auto&& spec : indexes.docs) { + donorIndexSpecs.push_back(spec); + if (auto indexNameElem = spec[IndexDescriptor::kIndexNameFieldName]) { + if (indexNameElem.type() == BSONType::String && + indexNameElem.valueStringData() == "_id_"_sd) { + donorIdIndexSpec = spec; } } + } - // Get collection options by calling listCollections against the donor. - auto infosRes = uassertStatusOK(fromShard->runExhaustiveCursorCommand( - opCtx, - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - nss.db().toString(), - BSON("listCollections" << 1 << "filter" << BSON("name" << nss.coll())), - Milliseconds(-1))); + // Get collection options by calling listCollections against the donor. + auto infosRes = uassertStatusOK(fromShard->runExhaustiveCursorCommand( + opCtx, + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + nss.db().toString(), + BSON("listCollections" << 1 << "filter" << BSON("name" << nss.coll())), + Milliseconds(-1))); - auto infos = infosRes.docs; - uassert(ErrorCodes::NamespaceNotFound, - str::stream() << "expected listCollections against the primary shard for " - << nss.toString() << " to return 1 entry, but got " << infos.size() - << " entries", - infos.size() == 1); + auto infos = infosRes.docs; + uassert(ErrorCodes::NamespaceNotFound, + str::stream() << "expected listCollections against the primary shard for " + << nss.toString() << " to return 1 entry, but got " << infos.size() + << " entries", + infos.size() == 1); - BSONObj entry = infos.front(); + BSONObj entry = infos.front(); - // The entire options include both the settable options under the 'options' field in the - // listCollections response, and the UUID under the 'info' field. - BSONObjBuilder donorOptionsBob; + // The entire options include both the settable options under the 'options' field in the + // listCollections response, and the UUID under the 'info' field. + BSONObjBuilder donorOptionsBob; - if (entry["options"].isABSONObj()) { - donorOptionsBob.appendElements(entry["options"].Obj()); - } + if (entry["options"].isABSONObj()) { + donorOptionsBob.appendElements(entry["options"].Obj()); + } - BSONObj info; - if (entry["info"].isABSONObj()) { - info = entry["info"].Obj(); - } + BSONObj info; + if (entry["info"].isABSONObj()) { + info = entry["info"].Obj(); + } - uassert(ErrorCodes::InvalidUUID, - str::stream() << "The donor shard did not return a UUID for collection " << nss.ns() - << " as part of its listCollections response: " << entry - << ", but this node expects to see a UUID.", - !info["uuid"].eoo()); + uassert(ErrorCodes::InvalidUUID, + str::stream() << "The donor shard did not return a UUID for collection " << nss.ns() + << " as part of its listCollections response: " << entry + << ", but this node expects to see a UUID.", + !info["uuid"].eoo()); - donorOptionsBob.append(info["uuid"]); + auto donorUUID = info["uuid"].uuid(); - donorOptions = donorOptionsBob.obj(); - } + donorOptionsBob.append(info["uuid"]); + donorOptions = donorOptionsBob.obj(); + + return {donorUUID, donorIndexSpecs, donorIdIndexSpec, donorOptions}; +} - // 1. If this shard doesn't own any chunks for the collection to be cloned and the collection +void MigrationDestinationManager::cloneCollectionIndexesAndOptions( + OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptionsAndIndexes& collectionOptionsAndIndexes) { + // 0. If this shard doesn't own any chunks for the collection to be cloned and the collection // exists locally, we drop its indexes to guarantee that no stale indexes carry over. bool dropNonDonorIndexes = [&]() -> bool { AutoGetCollection autoColl(opCtx, nss, MODE_IS); @@ -636,7 +642,7 @@ void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationCont auto indexes = client.getIndexSpecs(nss); for (auto&& recipientIndex : indexes) { bool dropIndex = true; - for (auto&& donorIndex : donorIndexSpecs) { + for (auto&& donorIndex : collectionOptionsAndIndexes.indexSpecs) { if (recipientIndex.woCompare(donorIndex) == 0) { dropIndex = false; break; @@ -658,7 +664,7 @@ void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationCont } { - // 2. Create the collection (if it doesn't already exist) and create any indexes we are + // 1. Create the collection (if it doesn't already exist) and create any indexes we are // missing (auto-heal indexes). // Checks that the collection's UUID matches the donor's. @@ -668,28 +674,24 @@ void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationCont << " because the node is not primary", repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, nss)); - boost::optional<UUID> donorUUID; - if (!donorOptions["uuid"].eoo()) { - donorUUID.emplace(UUID::parse(donorOptions)); - } - uassert(ErrorCodes::InvalidUUID, str::stream() << "Cannot create collection " << nss.ns() << " because we already have an identically named collection with UUID " << collection->uuid() << ", which differs from the donor's UUID " - << (donorUUID ? donorUUID->toString() : "(none)") + << collectionOptionsAndIndexes.uuid << ". Manually drop the collection on this shard if it contains data from " "a previous incarnation of " << nss.ns(), - collection->uuid() == donorUUID); + collection->uuid() == collectionOptionsAndIndexes.uuid); }; // Gets the missing indexes and checks if the collection is empty (auto-healing is // possible). auto checkEmptyOrGetMissingIndexesFromDonor = [&](Collection* collection) { auto indexCatalog = collection->getIndexCatalog(); - auto indexSpecs = indexCatalog->removeExistingIndexesNoChecks(opCtx, donorIndexSpecs); + auto indexSpecs = indexCatalog->removeExistingIndexesNoChecks( + opCtx, collectionOptionsAndIndexes.indexSpecs); if (!indexSpecs.empty()) { // Only allow indexes to be copied if the collection does not have any documents. uassert(ErrorCodes::CannotCreateCollection, @@ -727,11 +729,15 @@ void MigrationDestinationManager::cloneCollectionIndexesAndOptions(OperationCont // We do not have a collection by this name. Create the collection with the donor's // options. WriteUnitOfWork wuow(opCtx); - CollectionOptions collectionOptions = uassertStatusOK(CollectionOptions::parse( - donorOptions, CollectionOptions::ParseKind::parseForStorage)); + CollectionOptions collectionOptions = uassertStatusOK( + CollectionOptions::parse(collectionOptionsAndIndexes.options, + CollectionOptions::ParseKind::parseForStorage)); const bool createDefaultIndexes = true; - uassertStatusOK(db->userCreateNS( - opCtx, nss, collectionOptions, createDefaultIndexes, donorIdIndexSpec)); + uassertStatusOK(db->userCreateNS(opCtx, + nss, + collectionOptions, + createDefaultIndexes, + collectionOptionsAndIndexes.idIndexSpec)); wuow.commit(); collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, nss); } @@ -796,33 +802,25 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx) { invariant(initialState == READY); - { - cloneCollectionIndexesAndOptions(opCtx, _nss, _fromShard); - - timing.done(1); - migrateThreadHangAtStep1.pauseWhileSet(); - } + auto donorCollectionOptionsAndIndexes = getCollectionIndexesAndOptions(opCtx, _nss, _fromShard); auto fromShard = uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, _fromShard)); - const UUID collectionUuid = [&] { - AutoGetCollection autoGetCollection(opCtx, _nss, MODE_IS); - return autoGetCollection.getCollection()->uuid(); - }(); - { const ChunkRange range(_min, _max); // 2. Ensure any data which might have been left orphaned in the range being moved has been // deleted. if (_useFCV44Protocol) { - while (migrationutil::checkForConflictingDeletions(opCtx, range, collectionUuid)) { + while (migrationutil::checkForConflictingDeletions( + opCtx, range, donorCollectionOptionsAndIndexes.uuid)) { LOG(0) << "Migration paused because range overlaps with a " "range that is scheduled for deletion: collection: " << _nss.ns() << " range: " << redact(range.toString()); - auto status = CollectionShardingRuntime::waitForClean(opCtx, _nss, _epoch, range); + auto status = CollectionShardingRuntime::waitForClean( + opCtx, _nss, donorCollectionOptionsAndIndexes.uuid, range); if (!status.isOK()) { _setStateFail(redact(status.reason())); @@ -832,8 +830,12 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx) { opCtx->sleepFor(Milliseconds(1000)); } - RangeDeletionTask recipientDeletionTask( - _migrationId, _nss, collectionUuid, _fromShard, range, CleanWhenEnum::kNow); + RangeDeletionTask recipientDeletionTask(_migrationId, + _nss, + donorCollectionOptionsAndIndexes.uuid, + _fromShard, + range, + CleanWhenEnum::kNow); recipientDeletionTask.setPending(true); migrationutil::persistRangeDeletionTaskLocally(opCtx, recipientDeletionTask); @@ -842,20 +844,34 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx) { // being moved, and wait for completion auto cleanupCompleteFuture = _notePending(opCtx, range); - // Wait for the range deletion to report back - if (!cleanupCompleteFuture.getNoThrow(opCtx).isOK()) { - _setStateFail(redact(cleanupCompleteFuture.getNoThrow(opCtx).reason())); + auto cleanupStatus = cleanupCompleteFuture.getNoThrow(opCtx); + // Wait for the range deletion to report back. Swallow + // RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist error since the + // collection could either never exist or get dropped directly from the shard after the + // range deletion task got scheduled. + if (!cleanupStatus.isOK() && + cleanupStatus != + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist) { + _setStateFail(redact(cleanupStatus.reason())); return; } // Wait for any other, overlapping queued deletions to drain - auto status = CollectionShardingRuntime::waitForClean(opCtx, _nss, _epoch, range); - if (!status.isOK()) { - _setStateFail(redact(status.reason())); + cleanupStatus = CollectionShardingRuntime::waitForClean( + opCtx, _nss, donorCollectionOptionsAndIndexes.uuid, range); + if (!cleanupStatus.isOK()) { + _setStateFail(redact(cleanupStatus.reason())); return; } } + timing.done(1); + migrateThreadHangAtStep1.pauseWhileSet(); + } + + { + cloneCollectionIndexesAndOptions(opCtx, _nss, donorCollectionOptionsAndIndexes); + timing.done(2); migrateThreadHangAtStep2.pauseWhileSet(); } diff --git a/src/mongo/db/s/migration_destination_manager.h b/src/mongo/db/s/migration_destination_manager.h index b97a9b60217..78ea4741e8e 100644 --- a/src/mongo/db/s/migration_destination_manager.h +++ b/src/mongo/db/s/migration_destination_manager.h @@ -59,6 +59,13 @@ namespace repl { class OpTime; } +struct CollectionOptionsAndIndexes { + UUID uuid; + std::vector<BSONObj> indexSpecs; + BSONObj idIndexSpec; + BSONObj options; +}; + /** * Drives the receiving side of the MongoD migration process. One instance exists per shard. */ @@ -129,11 +136,19 @@ public: Status startCommit(const MigrationSessionId& sessionId); /** - * Creates the collection nss on the shard and clones the indexes and options from fromShardId. + * Gets the collection uuid, options and indexes from fromShardId. + */ + static CollectionOptionsAndIndexes getCollectionIndexesAndOptions(OperationContext* opCtx, + const NamespaceString& nss, + const ShardId& fromShardId); + + /** + * Creates the collection on the shard and clones the indexes and options. */ - static void cloneCollectionIndexesAndOptions(OperationContext* opCtx, - const NamespaceString& nss, - const ShardId& fromShardId); + static void cloneCollectionIndexesAndOptions( + OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptionsAndIndexes& collectionOptionsAndIndexes); private: /** diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 0380e137b4b..935f903c511 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -658,8 +658,8 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig() { log() << "Waiting for cleanup of " << getNss().ns() << " range " << redact(range.toString()); - auto deleteStatus = - CollectionShardingRuntime::waitForClean(_opCtx, getNss(), _collectionEpoch, range); + auto deleteStatus = CollectionShardingRuntime::waitForClean( + _opCtx, getNss(), _collectionUuid.get(), range); if (!deleteStatus.isOK()) { return {ErrorCodes::OrphanedRangeCleanUpFailed, diff --git a/src/mongo/db/s/range_deletion_util.cpp b/src/mongo/db/s/range_deletion_util.cpp index a6aa47c0a14..561b032a452 100644 --- a/src/mongo/db/s/range_deletion_util.cpp +++ b/src/mongo/db/s/range_deletion_util.cpp @@ -232,8 +232,8 @@ ExecutorFuture<int> deleteBatchAndWaitForReplication( AutoGetCollection autoColl(opCtx, nss, MODE_IX); auto* const collection = autoColl.getCollection(); - // Ensure the collection has not been dropped or dropped and recreated. - uassert(ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop, + // Ensure the collection exists and has not been dropped or dropped and recreated. + uassert(ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist, "Collection has been dropped since enqueuing this range " "deletion task. No need to delete documents.", !collectionUuidHasChanged(nss, collection, collectionUuid)); @@ -278,7 +278,8 @@ ExecutorFuture<void> deleteRangeInBatches(const std::shared_ptr<executor::TaskEx // Continue iterating until there are no more documents to delete, retrying on // any error that doesn't indicate that this node is stepping down. return (swNumDeleted.isOK() && swNumDeleted.getValue() == 0) || - swNumDeleted.getStatus() == ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop || + swNumDeleted.getStatus() == + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist || ErrorCodes::isShutdownError(swNumDeleted.getStatus()) || ErrorCodes::isNotMasterError(swNumDeleted.getStatus()); }) @@ -373,7 +374,9 @@ SharedSemiFuture<void> removeDocumentsInRange( << redact(range.toString()) << causedBy(redact(s)); } - if (s.isOK() || s.code() == ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop) { + if (s.isOK() || + s.code() == + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist) { removePersistentRangeDeletionTask(nss, collectionUuid, range); LOG(1) << "Completed removal of persistent range deletion task for " << nss.ns() diff --git a/src/mongo/db/s/range_deletion_util_test.cpp b/src/mongo/db/s/range_deletion_util_test.cpp index b1b6fd582f7..a2d245e185c 100644 --- a/src/mongo/db/s/range_deletion_util_test.cpp +++ b/src/mongo/db/s/range_deletion_util_test.cpp @@ -297,8 +297,9 @@ TEST_F(RangeDeleterTest, Milliseconds(0) /* delayBetweenBatches */); - ASSERT_THROWS_CODE( - cleanupComplete.get(), DBException, ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop); + ASSERT_THROWS_CODE(cleanupComplete.get(), + DBException, + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist); ASSERT_EQUALS(dbclient.count(kNss, BSONObj()), numDocsToInsert); } @@ -316,8 +317,9 @@ TEST_F(RangeDeleterTest, RemoveDocumentsInRangeThrowsErrorWhenCollectionDoesNotE Milliseconds(0) /* delayBetweenBatches */); - ASSERT_THROWS_CODE( - cleanupComplete.get(), DBException, ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop); + ASSERT_THROWS_CODE(cleanupComplete.get(), + DBException, + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist); } @@ -631,8 +633,9 @@ TEST_F(RangeDeleterTest, Seconds(0) /* delayForActiveQueriesOnSecondariesToComplete */, Milliseconds(0) /* delayBetweenBatches */); - ASSERT_THROWS_CODE( - cleanupComplete.get(), DBException, ErrorCodes::RangeDeletionAbandonedDueToCollectionDrop); + ASSERT_THROWS_CODE(cleanupComplete.get(), + DBException, + ErrorCodes::RangeDeletionAbandonedBecauseCollectionWithUUIDDoesNotExist); // Document should have been deleted. ASSERT_EQUALS(countDocsInConfigRangeDeletions(store, operationContext()), 0); |