diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2020-02-12 16:20:43 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2020-02-12 16:20:43 +0000 |
commit | 3e59bad319da75f2ad51a13ac3239bd21e74c41e (patch) | |
tree | 3c0f47597781502016ba5e0509d14cbbef29722b /src/mongo | |
parent | 436b0e57a57f8f5ae23d2a58c25ac488d5a8cef3 (diff) | |
download | mongo-3e59bad319da75f2ad51a13ac3239bd21e74c41e.tar.gz |
SERVER-45900 Check for unsharded collection when submitting range deletion task
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/s/migration_util.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/s/migration_util_test.cpp | 73 |
2 files changed, 86 insertions, 8 deletions
diff --git a/src/mongo/db/s/migration_util.cpp b/src/mongo/db/s/migration_util.cpp index ff3d10e6537..58f9198057c 100644 --- a/src/mongo/db/s/migration_util.cpp +++ b/src/mongo/db/s/migration_util.cpp @@ -144,15 +144,18 @@ ExecutorFuture<bool> submitRangeDeletionTask(OperationContext* opCtx, autoColl.emplace(opCtx, deletionTask.getNss(), MODE_IS); auto css = CollectionShardingRuntime::get(opCtx, deletionTask.getNss()); - if (!css->getCurrentMetadataIfKnown() || + if (!css->getCurrentMetadataIfKnown() || !css->getCurrentMetadata()->isSharded() || !css->getCurrentMetadata()->uuidMatches(deletionTask.getCollectionUuid())) { - // If the collection's filtering metadata is not known or its UUID does not match - // the UUID of the deletion task, force a filtering metadata refresh once, because - // this node may have just stepped up and therefore may have a stale cache. + // If the collection's filtering metadata is not known, is unsharded, or its UUID + // does not match the UUID of the deletion task, force a filtering metadata refresh + // once, because this node may have just stepped up and therefore may have a stale + // cache. LOG(0) << "Filtering metadata for namespace in deletion task " << deletionTask.toBSON() << (css->getCurrentMetadataIfKnown() - ? " has UUID that does not match UUID of the deletion task" + ? (css->getCurrentMetadata()->isSharded() + ? " has UUID that does not match UUID of the deletion task" + : " is unsharded") : " is not known") << ", forcing a refresh of " << deletionTask.getNss(); @@ -173,14 +176,16 @@ ExecutorFuture<bool> submitRangeDeletionTask(OperationContext* opCtx, } autoColl.emplace(opCtx, deletionTask.getNss(), MODE_IS); - if (!css->getCurrentMetadataIfKnown() || + if (!css->getCurrentMetadataIfKnown() || !css->getCurrentMetadata()->isSharded() || !css->getCurrentMetadata()->uuidMatches(deletionTask.getCollectionUuid())) { LOG(0) << "Even after forced refresh, filtering metadata for namespace in deletion " "task " << deletionTask.toBSON() << (css->getCurrentMetadataIfKnown() - ? "has UUID that does not match UUID of the deletion task" - : "is not known") + ? (css->getCurrentMetadata()->isSharded() + ? " has UUID that does not match UUID of the deletion task" + : " is unsharded") + : " is not known") << ", deleting the task."; autoColl.reset(); diff --git a/src/mongo/db/s/migration_util_test.cpp b/src/mongo/db/s/migration_util_test.cpp index 14547873f36..fa8b6197552 100644 --- a/src/mongo/db/s/migration_util_test.cpp +++ b/src/mongo/db/s/migration_util_test.cpp @@ -534,6 +534,54 @@ TEST_F(SubmitRangeDeletionTaskTest, ASSERT_EQ(store.count(opCtx), 0); } +TEST_F(SubmitRangeDeletionTaskTest, FailsAndDeletesTaskIfNamespaceIsUnshardedEvenAfterRefresh) { + auto opCtx = operationContext(); + + auto deletionTask = createDeletionTask(kNss, kDefaultUUID, 0, 10); + + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + store.add(opCtx, deletionTask); + ASSERT_EQ(store.count(opCtx), 1); + + // Make the refresh triggered by submitting the task return an empty result when loading the + // collection so it is considered unsharded. + _mockCatalogCacheLoader->setDatabaseRefreshReturnValue(kDefaultDatabaseType); + _mockCatalogCacheLoader->setCollectionRefreshReturnValue( + Status(ErrorCodes::NamespaceNotFound, "dummy errmsg")); + + auto submitTaskFuture = migrationutil::submitRangeDeletionTask(opCtx, deletionTask); + + // The task should not have been submitted, and the task's entry should have been removed from + // the persistent store. + ASSERT_FALSE(submitTaskFuture.get(opCtx)); + ASSERT_EQ(store.count(opCtx), 0); +} + +TEST_F(SubmitRangeDeletionTaskTest, + FailsAndDeletesTaskIfNamespaceIsUnshardedBeforeAndAfterRefresh) { + auto opCtx = operationContext(); + + auto deletionTask = createDeletionTask(kNss, kDefaultUUID, 0, 10); + + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + store.add(opCtx, deletionTask); + ASSERT_EQ(store.count(opCtx), 1); + + // Mock an empty result for the task's collection and force a refresh so the node believes the + // collection is unsharded. + _mockCatalogCacheLoader->setDatabaseRefreshReturnValue(kDefaultDatabaseType); + _mockCatalogCacheLoader->setCollectionRefreshReturnValue( + Status(ErrorCodes::NamespaceNotFound, "dummy errmsg")); + forceShardFilteringMetadataRefresh(opCtx, kNss, true); + + auto submitTaskFuture = migrationutil::submitRangeDeletionTask(opCtx, deletionTask); + + // The task should not have been submitted, and the task's entry should have been removed from + // the persistent store. + ASSERT_FALSE(submitTaskFuture.get(opCtx)); + ASSERT_EQ(store.count(opCtx), 0); +} + TEST_F(SubmitRangeDeletionTaskTest, SucceedsIfFilteringMetadataUUIDMatchesTaskUUID) { auto opCtx = operationContext(); @@ -574,6 +622,31 @@ TEST_F( } TEST_F(SubmitRangeDeletionTaskTest, + SucceedsIfTaskNamespaceInitiallyUnshardedButUUIDMatchesAfterRefresh) { + auto opCtx = operationContext(); + + // Force a metadata refresh with no collection entry so the node believes the namespace is + // unsharded when the task is submitted. + _mockCatalogCacheLoader->setDatabaseRefreshReturnValue(kDefaultDatabaseType); + _mockCatalogCacheLoader->setCollectionRefreshReturnValue( + Status(ErrorCodes::NamespaceNotFound, "dummy errmsg")); + forceShardFilteringMetadataRefresh(opCtx, kNss, true); + + auto deletionTask = createDeletionTask(kNss, kDefaultUUID, 0, 10); + + // Make the refresh triggered by submitting the task return a UUID that matches the task's UUID. + auto matchingColl = makeCollectionType(kDefaultUUID, kEpoch); + _mockCatalogCacheLoader->setCollectionRefreshReturnValue(matchingColl); + _mockCatalogCacheLoader->setChunkRefreshReturnValue( + makeChangedChunks(ChunkVersion(10, 0, kEpoch))); + _mockCatalogClient->setCollections({matchingColl}); + + // The task should have been submitted successfully. + auto submitTaskFuture = migrationutil::submitRangeDeletionTask(opCtx, deletionTask); + ASSERT(submitTaskFuture.get(opCtx)); +} + +TEST_F(SubmitRangeDeletionTaskTest, SucceedsIfFilteringMetadataUUIDInitiallyDifferentFromTaskUUIDButMatchesAfterRefresh) { auto opCtx = operationContext(); |