summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEsha Maharishi <esha.maharishi@mongodb.com>2017-11-16 12:52:42 -0500
committerEsha Maharishi <esha.maharishi@mongodb.com>2017-11-21 11:47:33 -0500
commitdb79fdfb42475212dcc902a00420bf693b980d17 (patch)
tree87d7718230d0f973ea7cf7f0dcca6d3d3f663aed /src
parent808fca641401392a5f45102ad6d018266cec1bc2 (diff)
downloadmongo-db79fdfb42475212dcc902a00420bf693b980d17.tar.gz
SERVER-31909 Recipient shard should fail migration if it already has the collection with a different UUID
(cherry picked from commit 545c11242d737bf1a8ec19c2f2d7a7f14cc08f46)
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp78
1 files changed, 54 insertions, 24 deletions
diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp
index 9efdc9c0c4c..95d6db11dc4 100644
--- a/src/mongo/db/s/migration_destination_manager.cpp
+++ b/src/mongo/db/s/migration_destination_manager.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/auth/authorization_manager_global.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/catalog/collection.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/catalog/document_validation.h"
#include "mongo/db/catalog/index_create.h"
@@ -208,6 +209,7 @@ MONGO_FP_DECLARE(migrateThreadHangAtStep4);
MONGO_FP_DECLARE(migrateThreadHangAtStep5);
MONGO_FP_DECLARE(migrateThreadHangAtStep6);
+MONGO_FP_DECLARE(failMigrationLeaveOrphans);
MONGO_FP_DECLARE(failMigrationReceivedOutOfRangeOperation);
} // namespace
@@ -447,7 +449,7 @@ void MigrationDestinationManager::_migrateThread(BSONObj min,
setStateFail("migrate failed with unknown exception: UNKNOWN ERROR");
}
- if (getState() != DONE) {
+ if (getState() != DONE && !MONGO_FAIL_POINT(failMigrationLeaveOrphans)) {
_forgetPending(opCtx.get(), _nss, epoch, ChunkRange(min, max));
}
@@ -493,9 +495,9 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
DisableDocumentValidation validationDisabler(opCtx);
- std::vector<BSONObj> indexSpecs;
- BSONObj idIndexSpec;
- BSONObj options;
+ std::vector<BSONObj> donorIndexSpecs;
+ BSONObj donorIdIndexSpec;
+ BSONObj donorOptions;
{
// 0. Get the collection indexes and options from the donor shard.
@@ -505,11 +507,11 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
// Get indexes by calling listIndexes against the donor.
auto indexes = conn->getIndexSpecs(_nss.ns());
for (auto&& spec : indexes) {
- indexSpecs.push_back(spec);
+ donorIndexSpecs.push_back(spec);
if (auto indexNameElem = spec[IndexDescriptor::kIndexNameFieldName]) {
if (indexNameElem.type() == BSONType::String &&
indexNameElem.valueStringData() == "_id_"_sd) {
- idIndexSpec = spec;
+ donorIdIndexSpec = spec;
}
}
}
@@ -532,10 +534,10 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
// The entire options include both the settable options under the 'options' field in the
// listCollections response, and the UUID under the 'info' field.
- BSONObjBuilder optionsBob;
+ BSONObjBuilder donorOptionsBob;
if (entry["options"].isABSONObj()) {
- optionsBob.appendElements(entry["options"].Obj());
+ donorOptionsBob.appendElements(entry["options"].Obj());
}
if (serverGlobalParams.featureCompatibility.isSchemaVersion36()) {
@@ -555,9 +557,9 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
"compatibility version across the cluster.");
return;
}
- optionsBob.append(info["uuid"]);
+ donorOptionsBob.append(info["uuid"]);
}
- options = optionsBob.obj();
+ donorOptions = donorOptionsBob.obj();
}
{
@@ -581,44 +583,66 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
}
Database* const db = ctx.db();
- if (!db->getCollection(opCtx, _nss)) {
+ Collection* collection = db->getCollection(opCtx, _nss);
+ if (collection) {
+ // We have an entry for a collection by this name. Check that our collection's UUID
+ // matches the donor's.
+ boost::optional<UUID> donorUUID;
+ if (!donorOptions["uuid"].eoo()) {
+ donorUUID.emplace(UUID::parse(donorOptions));
+ }
+
+ if (!collection->getCatalogEntry()->isEqualToMetadataUUID(opCtx, donorUUID)) {
+ setStateFailWarn(
+ str::stream()
+ << "Cannot receive chunk "
+ << ChunkRange(min, max).toString()
+ << " for collection "
+ << _nss.ns()
+ << " because we already have an identically named collection with UUID "
+ << (collection->uuid() ? collection->uuid()->toString() : "(none)")
+ << ", which differs from the donor's UUID "
+ << (donorUUID ? donorUUID->toString() : "(none)")
+ << ". Manually drop the collection on this shard if it contains data from a "
+ "previous incarnation of "
+ << _nss.ns());
+ return;
+ }
+ } else {
+ // We do not have a collection by this name. Create the collection with the donor's
+ // options.
WriteUnitOfWork wuow(opCtx);
const bool createDefaultIndexes = true;
Status status = userCreateNS(opCtx,
db,
_nss.ns(),
- options,
+ donorOptions,
CollectionOptions::parseForStorage,
createDefaultIndexes,
- idIndexSpec);
+ donorIdIndexSpec);
if (!status.isOK()) {
warning() << "failed to create collection [" << _nss << "] "
- << " with options " << options << ": " << redact(status);
+ << " with options " << donorOptions << ": " << redact(status);
}
wuow.commit();
- }
-
- Collection* const collection = db->getCollection(opCtx, _nss);
- if (!collection) {
- setStateFailWarn(str::stream() << "collection dropped during migration: " << _nss.ns());
- return;
+ collection = db->getCollection(opCtx, _nss);
}
MultiIndexBlock indexer(opCtx, collection);
- indexer.removeExistingIndexes(&indexSpecs);
+ indexer.removeExistingIndexes(&donorIndexSpecs);
- if (!indexSpecs.empty()) {
+ if (!donorIndexSpecs.empty()) {
// Only copy indexes if the collection does not have any documents.
if (collection->numRecords(opCtx) > 0) {
setStateFailWarn(str::stream() << "aborting migration, shard is missing "
- << indexSpecs.size()
+ << donorIndexSpecs.size()
<< " indexes and "
<< "collection is not empty. Non-trivial "
<< "index creation should be scheduled manually");
return;
}
- auto indexInfoObjs = indexer.init(indexSpecs);
+ auto indexInfoObjs = indexer.init(donorIndexSpecs);
if (!indexInfoObjs.isOK()) {
setStateFailWarn(str::stream() << "failed to create index before migrating data. "
<< " error: "
@@ -752,6 +776,12 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx,
timing.done(3);
MONGO_FAIL_POINT_PAUSE_WHILE_SET(migrateThreadHangAtStep3);
+
+ if (MONGO_FAIL_POINT(failMigrationLeaveOrphans)) {
+ setStateFail(str::stream() << "failing migration after cloning " << _numCloned
+ << " docs due to failMigrationLeaveOrphans failpoint");
+ return;
+ }
}
// If running on a replicated system, we'll need to flush the docs we cloned to the