diff options
-rw-r--r-- | jstests/sharding/migration_fails_if_exists_in_rangedeletions.js | 2 | ||||
-rw-r--r-- | jstests/sharding/resubmit_rangedeletions_on_stepup.js | 4 | ||||
-rw-r--r-- | jstests/sharding/updates_to_rangedeletions_collection_trigger_range_deletions.js | 4 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 3 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/s/migration_coordinator.cpp | 103 | ||||
-rw-r--r-- | src/mongo/db/s/migration_coordinator.h | 88 | ||||
-rw-r--r-- | src/mongo/db/s/migration_coordinator_document.idl | 65 | ||||
-rw-r--r-- | src/mongo/db/s/migration_util.cpp | 108 | ||||
-rw-r--r-- | src/mongo/db/s/migration_util.h | 57 | ||||
-rw-r--r-- | src/mongo/db/s/migration_util_test.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/s/range_deletion_task.idl | 26 | ||||
-rw-r--r-- | src/mongo/s/catalog/type_chunk.h | 7 | ||||
-rw-r--r-- | src/mongo/s/chunk_range.idl | 48 | ||||
-rw-r--r-- | src/mongo/util/uuid.h | 1 |
16 files changed, 508 insertions, 25 deletions
diff --git a/jstests/sharding/migration_fails_if_exists_in_rangedeletions.js b/jstests/sharding/migration_fails_if_exists_in_rangedeletions.js index 371cd678281..969d296c957 100644 --- a/jstests/sharding/migration_fails_if_exists_in_rangedeletions.js +++ b/jstests/sharding/migration_fails_if_exists_in_rangedeletions.js @@ -24,8 +24,10 @@ assert.commandWorked(st.s.adminCommand({split: ns, middle: {x: 50}})); const collectionUuid = getUUIDFromConfigCollections(st.s, ns); let deletionTask = { + _id: UUID(), nss: ns, collectionUuid: collectionUuid, + donorShardId: "unused", pending: true, range: {min: {x: 70}, max: {x: 90}}, whenToClean: "now" diff --git a/jstests/sharding/resubmit_rangedeletions_on_stepup.js b/jstests/sharding/resubmit_rangedeletions_on_stepup.js index c8c98cd6e92..3d288f07ef6 100644 --- a/jstests/sharding/resubmit_rangedeletions_on_stepup.js +++ b/jstests/sharding/resubmit_rangedeletions_on_stepup.js @@ -52,8 +52,10 @@ function setup() { const collectionUuid = getUUIDFromConfigCollections(st.s, ns); let deletionTask = { + _id: UUID(), nss: ns, collectionUuid: collectionUuid, + donorShardId: "unused", range: {min: {x: 50}, max: {x: MaxKey}}, whenToClean: "now" }; @@ -117,8 +119,10 @@ function setup() { const collectionUuid = getUUIDFromConfigCollections(st.s, ns); let deletionTask = { + _id: UUID(), nss: ns, collectionUuid: collectionUuid, + donorShardId: "unused", pending: true, range: {min: {x: 50}, max: {x: MaxKey}}, whenToClean: "now" diff --git a/jstests/sharding/updates_to_rangedeletions_collection_trigger_range_deletions.js b/jstests/sharding/updates_to_rangedeletions_collection_trigger_range_deletions.js index adc031541b4..19b10e35cbc 100644 --- a/jstests/sharding/updates_to_rangedeletions_collection_trigger_range_deletions.js +++ b/jstests/sharding/updates_to_rangedeletions_collection_trigger_range_deletions.js @@ -64,8 +64,10 @@ let testColl = testDB.foo; const collectionUuid = getUUIDFromConfigCollections(st.s, ns); let deletionTask = { + _id: UUID(), nss: ns, collectionUuid: collectionUuid, + donorShardId: "unused", pending: true, range: {min: {x: 70}, max: {x: 90}}, whenToClean: "now" @@ -112,8 +114,10 @@ let testColl = testDB.foo; assert.eq(shard1Coll.find().itcount(), expectedNumDocsShard1); let deletionTask = { + _id: UUID(), nss: ns, collectionUuid: UUID(), + donorShardId: "unused", pending: true, range: {min: {x: 70}, max: {x: 90}}, whenToClean: "now" diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp index 8d8656b8ec4..2397e3c1d0d 100644 --- a/src/mongo/db/namespace_string.cpp +++ b/src/mongo/db/namespace_string.cpp @@ -66,6 +66,9 @@ const NamespaceString NamespaceString::kSessionTransactionsTableNamespace( const NamespaceString NamespaceString::kTransactionCoordinatorsNamespace( NamespaceString::kConfigDb, "transaction_coordinators"); +const NamespaceString NamespaceString::kMigrationCoordinatorsNamespace(NamespaceString::kConfigDb, + "migrationCoordinators"); + const NamespaceString NamespaceString::kShardConfigCollectionsNamespace(NamespaceString::kConfigDb, "cache.collections"); const NamespaceString NamespaceString::kShardConfigDatabasesNamespace(NamespaceString::kConfigDb, diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index 653f0ed1546..add77a0dfaf 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -95,6 +95,9 @@ public: // Namespace for storing the persisted state of transaction coordinators. static const NamespaceString kTransactionCoordinatorsNamespace; + // Namespace for storing the persisted state of migration coordinators. + static const NamespaceString kMigrationCoordinatorsNamespace; + // Namespace for replica set configuration settings. static const NamespaceString kSystemReplSetNamespace; diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index bbed7e25b50..6e4080a39b1 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -47,6 +47,7 @@ env.Library( 'metadata_manager.cpp', 'migration_chunk_cloner_source_legacy.cpp', 'migration_chunk_cloner_source.cpp', + 'migration_coordinator.cpp', 'migration_destination_manager.cpp', 'migration_session_id.cpp', 'migration_source_manager.cpp', @@ -74,7 +75,7 @@ env.Library( 'start_chunk_clone_request.cpp', env.Idlc('sharding_runtime_d_params.idl')[0], env.Idlc('range_deletion_task.idl')[0], - + env.Idlc('migration_coordinator_document.idl')[0], ], LIBDEPS=[ '$BUILD_DIR/mongo/db/catalog/multi_index_block', diff --git a/src/mongo/db/s/migration_coordinator.cpp b/src/mongo/db/s/migration_coordinator.cpp new file mode 100644 index 00000000000..f1deb950a17 --- /dev/null +++ b/src/mongo/db/s/migration_coordinator.cpp @@ -0,0 +1,103 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding + +#include "mongo/platform/basic.h" + +#include "mongo/db/s/migration_coordinator.h" + +#include "mongo/db/s/migration_util.h" +#include "mongo/db/s/range_deletion_task_gen.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace migrationutil { + +MigrationCoordinator::MigrationCoordinator(OperationContext* opCtx, + UUID migrationId, + ShardId donorShard, + ShardId recipientShard, + NamespaceString collectionNamespace, + UUID collectionUuid, + ChunkRange range) + : _migrationInfo(migrationId, + std::move(collectionNamespace), + collectionUuid, + std::move(donorShard), + std::move(recipientShard), + std::move(range)) {} + +MigrationCoordinator::~MigrationCoordinator() = default; + +void MigrationCoordinator::startMigration(OperationContext* opCtx, bool waitForDelete) { + migrationutil::persistMigrationCoordinatorLocally(opCtx, _migrationInfo); + + RangeDeletionTask donorDeletionTask(_migrationInfo.getId(), + _migrationInfo.getNss(), + _migrationInfo.getCollectionUuid(), + _migrationInfo.getDonorShardId(), + _migrationInfo.getRange(), + waitForDelete ? CleanWhenEnum::kNow + : CleanWhenEnum::kDelayed); + donorDeletionTask.setPending(true); + + LOG(0) << "Persisting range deletion task on donor for migration " << _migrationInfo.getId(); + migrationutil::persistRangeDeletionTaskLocally(opCtx, donorDeletionTask); +} + +void MigrationCoordinator::commitMigrationOnDonorAndRecipient(OperationContext* opCtx) { + LOG(0) << "Committing migration on donor and recipient for migration " + << _migrationInfo.getId(); + LOG(0) << "Deleting range deletion task on recipient for migration " << _migrationInfo.getId(); + + migrationutil::deleteRangeDeletionTaskOnRecipient( + opCtx, _migrationInfo.getRecipientShardId(), _migrationInfo.getId()); + + LOG(0) << "Marking range deletion task on donor as ready for processing for migration " + << _migrationInfo.getId(); + migrationutil::markAsReadyRangeDeletionTaskLocally(opCtx, _migrationInfo.getId()); +} + +void MigrationCoordinator::abortMigrationOnDonorAndRecipient(OperationContext* opCtx) { + LOG(0) << "Aborting migration on donor and recipient for migration " << _migrationInfo.getId(); + LOG(0) << "Deleting range deletion task on donor for migration " << _migrationInfo.getId(); + + migrationutil::deleteRangeDeletionTaskLocally(opCtx, _migrationInfo.getId()); + + LOG(0) << "Marking range deletion task on recipient as ready for processing for migration " + << _migrationInfo.getId(); + + migrationutil::markAsReadyRangeDeletionTaskOnRecipient( + opCtx, _migrationInfo.getRecipientShardId(), _migrationInfo.getId()); +} + +} // namespace migrationutil + +} // namespace mongo diff --git a/src/mongo/db/s/migration_coordinator.h b/src/mongo/db/s/migration_coordinator.h new file mode 100644 index 00000000000..c0c2327a2c2 --- /dev/null +++ b/src/mongo/db/s/migration_coordinator.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/s/migration_coordinator_document_gen.h" +#include "mongo/s/catalog/type_chunk.h" + +namespace mongo { + +namespace migrationutil { +/** + * Manages the migration commit/abort process, including updates to config.rangeDeletions on the + * donor and the recipient, and updates to the routing table on the config server. + * + * TODO (SERVER-44716): Implement commit/abort/recovery logic on the config server. + */ +class MigrationCoordinator { +public: + MigrationCoordinator(OperationContext* opCtx, + UUID migrationId, + ShardId donorShard, + ShardId recipientShard, + NamespaceString collectionNamespace, + UUID collectionUuid, + ChunkRange range); + MigrationCoordinator(const MigrationCoordinator&) = delete; + MigrationCoordinator& operator=(const MigrationCoordinator&) = delete; + MigrationCoordinator(MigrationCoordinator&&) = delete; + MigrationCoordinator& operator=(MigrationCoordinator&&) = delete; + + ~MigrationCoordinator(); + + /** + * Initializes persistent state required to ensure that orphaned ranges are properly handled, + * even after failover, by doing the following: + * + * 1) Inserts a document into the local config.migrationCoordinators with the lsid, txnNumber, + * and recipientId and waits for majority writeConcern. + * 2) Inserts a document into the local config.rangeDeletions with the collectionUUID, range to + * delete, and "pending: true" and waits for majority writeConcern. + */ + void startMigration(OperationContext* opCtx, bool waitForDelete); + + /** + * Deletes the range deletion task from the recipient node and marks the range deletion task on + * the donor as ready to be processed. + */ + void commitMigrationOnDonorAndRecipient(OperationContext* opCtx); + + /** + * Deletes the range deletion task from the donor node and marks the range deletion task on the + * recipient node as ready to be processed. + */ + void abortMigrationOnDonorAndRecipient(OperationContext* opCtx); + +private: + MigrationCoordinatorDocument _migrationInfo; +}; + +} // namespace migrationutil +} // namespace mongo diff --git a/src/mongo/db/s/migration_coordinator_document.idl b/src/mongo/db/s/migration_coordinator_document.idl new file mode 100644 index 00000000000..ff12d7e51f5 --- /dev/null +++ b/src/mongo/db/s/migration_coordinator_document.idl @@ -0,0 +1,65 @@ +# Copyright (C) 2019-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# <http://www.mongodb.com/licensing/server-side-public-license>. +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# + +# This file defines the format of documents stored in config.rangeDeletions. Each document +# represents a chunk range to be deleted by the CollectionRangeDeleter. + +global: + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" + - "mongo/s/sharding_types.idl" + - "mongo/s/chunk_range.idl" + - "mongo/db/logical_session_id.idl" + +structs: + migrationCoordinatorDocument: + description: "Represents an in-progress migration on the migration donor." + generate_comparison_operators: false + strict: true + fields: + _id: + type: uuid + description: "A unique identifier for the migration." + cpp_name: id + nss: + type: namespacestring + description: "The namespace of the collection that the chunk belongs to." + collectionUuid: + type: uuid + description: "The UUID of the collection that the chunk belongs to." + donorShardId: + type: shard_id + description: "The shard from which the chunk is being migrated." + recipientShardId: + type: shard_id + description: "The shard to which the chunk is being migrated." + range: + type: chunk_range + description: "The range being migrated." diff --git a/src/mongo/db/s/migration_util.cpp b/src/mongo/db/s/migration_util.cpp index afda204d544..bd5e2ac09da 100644 --- a/src/mongo/db/s/migration_util.cpp +++ b/src/mongo/db/s/migration_util.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018-present MongoDB, Inc. + * Copyright (C) 2019-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, @@ -37,12 +37,19 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/client/query.h" #include "mongo/db/catalog_raii.h" +#include "mongo/db/dbdirectclient.h" +#include "mongo/db/logical_session_cache.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/ops/write_ops.h" +#include "mongo/db/repl/repl_client_info.h" #include "mongo/db/s/collection_sharding_runtime.h" #include "mongo/db/s/shard_filtering_metadata_refresh.h" +#include "mongo/db/write_concern.h" #include "mongo/executor/task_executor_pool.h" #include "mongo/executor/thread_pool_task_executor.h" +#include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/catalog/type_chunk.h" +#include "mongo/s/client/shard.h" #include "mongo/s/grid.h" #include "mongo/util/log.h" @@ -55,6 +62,27 @@ const char kDestinationShard[] = "destination"; const char kIsDonorShard[] = "isDonorShard"; const char kChunk[] = "chunk"; const char kCollection[] = "collection"; + +const WriteConcernOptions kMajorityWriteConcern(WriteConcernOptions::kMajority, + WriteConcernOptions::SyncMode::UNSET, + WriteConcernOptions::kNoTimeout); + +template <typename Cmd> +void sendToRecipient(OperationContext* opCtx, const ShardId& recipientId, const Cmd& cmd) { + auto recipientShard = + uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, recipientId)); + + LOG(1) << "Sending request " << cmd.toBSON({}) << " to recipient."; + + auto response = recipientShard->runCommandWithFixedRetryAttempts( + opCtx, + ReadPreferenceSetting{ReadPreference::PrimaryOnly}, + "config", + cmd.toBSON({}), + Shard::RetryPolicy::kIdempotent); + uassertStatusOK(Shard::CommandResponse::getEffectiveStatus(response)); +} + } // namespace BSONObj makeMigrationStatusDocument(const NamespaceString& nss, @@ -118,7 +146,7 @@ bool submitRangeDeletionTask(OperationContext* opCtx, const RangeDeletionTask& d return false; } - auto notification = css->cleanUpRange(*deletionTask.getRange(), whenToClean); + auto notification = css->cleanUpRange(deletionTask.getRange(), whenToClean); if (notification.ready() && !notification.waitStatus(opCtx).isOK()) { LOG(0) << "Failed to resubmit range for deletion: " @@ -170,6 +198,80 @@ void resubmitRangeDeletionsOnStepUp(ServiceContext* serviceContext) { }); } -} // namespace migrationutil +void persistMigrationCoordinatorLocally(OperationContext* opCtx, + const MigrationCoordinatorDocument& migrationDoc) { + PersistentTaskStore<MigrationCoordinatorDocument> store( + opCtx, NamespaceString::kMigrationCoordinatorsNamespace); + try { + store.add(opCtx, migrationDoc); + } catch (const ExceptionFor<ErrorCodes::DuplicateKey>& e) { + // Convert a DuplicateKey error to an anonymous error. + uasserted( + 31374, + str::stream() << "While attempting to write migration information for migration " + << ", found document with the same migration id. Attempted migration: " + << migrationDoc.toBSON()); + } +} + +void persistRangeDeletionTaskLocally(OperationContext* opCtx, + const RangeDeletionTask& deletionTask) { + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + try { + store.add(opCtx, deletionTask); + } catch (const ExceptionFor<ErrorCodes::DuplicateKey>& e) { + // Convert a DuplicateKey error to an anonymous error. + uasserted(31375, + str::stream() << "While attempting to write range deletion task for migration " + << ", found document with the same migration id. Attempted range " + "deletion task: " + << deletionTask.toBSON()); + } +} + +void deleteRangeDeletionTaskOnRecipient(OperationContext* opCtx, + const ShardId& recipientId, + const UUID& migrationId) { + write_ops::Delete deleteOp(NamespaceString::kRangeDeletionNamespace); + write_ops::DeleteOpEntry query(BSON(RangeDeletionTask::kIdFieldName << migrationId), + false /*multi*/); + deleteOp.setDeletes({query}); + sendToRecipient(opCtx, recipientId, deleteOp); +} + +void deleteRangeDeletionTaskLocally(OperationContext* opCtx, const UUID& deletionTaskId) { + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + store.remove(opCtx, QUERY(RangeDeletionTask::kIdFieldName << deletionTaskId)); +} + +void deleteRangeDeletionTasksForCollectionLocally(OperationContext* opCtx, + const UUID& collectionUuid) { + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + store.remove(opCtx, QUERY(RangeDeletionTask::kCollectionUuidFieldName << collectionUuid)); +} + +void markAsReadyRangeDeletionTaskOnRecipient(OperationContext* opCtx, + const ShardId& recipientId, + const UUID& migrationId) { + write_ops::Update updateOp(NamespaceString::kRangeDeletionNamespace); + auto queryFilter = BSON(RangeDeletionTask::kIdFieldName << migrationId); + auto updateModification = write_ops::UpdateModification( + BSON("$unset" << BSON(RangeDeletionTask::kPendingFieldName << ""))); + write_ops::UpdateOpEntry updateEntry(queryFilter, updateModification); + updateEntry.setMulti(false); + updateEntry.setUpsert(false); + updateOp.setUpdates({updateEntry}); + + sendToRecipient(opCtx, recipientId, updateOp); +} + +void markAsReadyRangeDeletionTaskLocally(OperationContext* opCtx, const UUID& migrationId) { + PersistentTaskStore<RangeDeletionTask> store(opCtx, NamespaceString::kRangeDeletionNamespace); + auto query = QUERY(RangeDeletionTask::kIdFieldName << migrationId); + auto update = BSON("$unset" << BSON(RangeDeletionTask::kPendingFieldName << "")); + + store.update(opCtx, query, update); +} +} // namespace migrationutil } // namespace mongo diff --git a/src/mongo/db/s/migration_util.h b/src/mongo/db/s/migration_util.h index 6ba282e321b..f3119de0ef6 100644 --- a/src/mongo/db/s/migration_util.h +++ b/src/mongo/db/s/migration_util.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018-present MongoDB, Inc. + * Copyright (C) 2019-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, @@ -29,6 +29,9 @@ #pragma once +#include "mongo/db/logical_session_id.h" +#include "mongo/db/repl/optime.h" +#include "mongo/db/s/migration_coordinator_document_gen.h" #include "mongo/db/s/persistent_task_store.h" #include "mongo/db/s/range_deletion_task_gen.h" #include "mongo/s/catalog/type_chunk.h" @@ -81,6 +84,56 @@ void submitPendingDeletions(OperationContext* opCtx); // Asynchronously calls submitPendingDeletions using the fixed executor pool. void resubmitRangeDeletionsOnStepUp(ServiceContext* serviceContext); -} // namespace migrationutil +/** + * Writes the migration coordinator document to config.migrationCoordinators and waits for majority + * write concern. + */ +void persistMigrationCoordinatorLocally(OperationContext* opCtx, + const MigrationCoordinatorDocument& migrationDoc); + +/** + * Writes the range deletion task document to config.rangeDeletions and waits for majority write + * concern. + */ +void persistRangeDeletionTaskLocally(OperationContext* opCtx, + const RangeDeletionTask& deletionTask); + +/** + * Deletes the range deletion task document with the specified id from config.rangeDeletions and + * waits for majority write concern. + */ +void deleteRangeDeletionTaskLocally(OperationContext* opCtx, const UUID& deletionTaskId); + +/** + * Deletes all range deletion task documents with the specified collection UUID from + * config.rangeDeletions and waits for majority write concern. + */ +void deleteRangeDeletionTasksForCollectionLocally(OperationContext* opCtx, + const UUID& collectionUuid); + +/** + * Deletes the range deletion task document with the specified id from config.rangeDeletions on the + * specified shard and waits for majority write concern. + */ +void deleteRangeDeletionTaskOnRecipient(OperationContext* opCtx, + const ShardId& recipientId, + const UUID& migrationId); +/** + * Removes the 'pending' flag from the range deletion task document with the specified id from + * config.rangeDeletions and waits for majority write concern. This marks the range as ready for + * deletion. + */ +void markAsReadyRangeDeletionTaskLocally(OperationContext* opCtx, const UUID& migrationId); + + +/** + * Removes the 'pending' flag from the range deletion task document with the specified id from + * config.rangeDeletions on the specified shard and waits for majority write concern. This marks the + * range as ready for deletion. + */ +void markAsReadyRangeDeletionTaskOnRecipient(OperationContext* opCtx, + const ShardId& recipientId, + const UUID& migrationId); +} // namespace migrationutil } // namespace mongo diff --git a/src/mongo/db/s/migration_util_test.cpp b/src/mongo/db/s/migration_util_test.cpp index 0496e64388c..f93471b2141 100644 --- a/src/mongo/db/s/migration_util_test.cpp +++ b/src/mongo/db/s/migration_util_test.cpp @@ -261,11 +261,12 @@ void addRangeToReceivingChunks(OperationContext* opCtx, } RangeDeletionTask createDeletionTask(NamespaceString nss, const UUID& uuid, int min, int max) { - RangeDeletionTask task{nss, uuid, CleanWhenEnum::kNow}; - - task.setRange(ChunkRange{BSON("_id" << min), BSON("_id" << max)}); - - return task; + return RangeDeletionTask(UUID::gen(), + nss, + uuid, + ShardId("donorShard"), + ChunkRange{BSON("_id" << min), BSON("_id" << max)}, + CleanWhenEnum::kDelayed); } // Test that overlappingRangeQuery() can handle the cases that we expect to encounter. diff --git a/src/mongo/db/s/range_deletion_task.idl b/src/mongo/db/s/range_deletion_task.idl index 9af29c5181d..1c265f2656a 100644 --- a/src/mongo/db/s/range_deletion_task.idl +++ b/src/mongo/db/s/range_deletion_task.idl @@ -31,19 +31,12 @@ global: cpp_namespace: "mongo" - cpp_includes : "mongo/s/catalog/type_chunk.h" imports: - "mongo/idl/basic_types.idl" - -types: - chunkRangeType: - description: "Represents the bounds of a chunk range. See ChunkRange for the semantics of - the bounds." - bson_serialization_type: object - cpp_type: "mongo::ChunkRange" - serializer: "mongo::ChunkRange::toBSON" - deserializer: "mongo::ChunkRange::fromBSONThrowing" + - "mongo/s/sharding_types.idl" + - "mongo/db/logical_session_id.idl" + - "mongo/s/chunk_range.idl" enums: CleanWhen: @@ -58,17 +51,22 @@ structs: description: "Represents a chunk range to be deleted by the range deleter." strict: false fields: + _id: + type: uuid + description: "A unique identifier for the migration." + cpp_name: id nss: type: namespacestring description: "The namespace of the collection that the chunk belongs to." collectionUuid: type: uuid description: "The UUID of the collection that the chunk belongs to." + donorShardId: + type: shard_id + description: "The shard from which the chunk was migrated." range: - type: chunkRangeType - description: "The range to be deleted. Needs to be optional since ChunkRange - doesn't have a default constructor." - optional: true + type: chunk_range + description: "The range to be deleted." pending: type: bool description: "Flag that is present if the range is not yet ready for deletion" diff --git a/src/mongo/s/catalog/type_chunk.h b/src/mongo/s/catalog/type_chunk.h index 1905280392b..2e64e86d3dc 100644 --- a/src/mongo/s/catalog/type_chunk.h +++ b/src/mongo/s/catalog/type_chunk.h @@ -117,6 +117,13 @@ public: ChunkRange unionWith(ChunkRange const& other) const; private: + // For use with IDL parsing - limited to friend access only. + ChunkRange() = default; + + // Make the IDL generated parser a friend + friend class RangeDeletionTask; + friend class MigrationCoordinatorDocument; + BSONObj _minKey; BSONObj _maxKey; }; diff --git a/src/mongo/s/chunk_range.idl b/src/mongo/s/chunk_range.idl new file mode 100644 index 00000000000..a60701bf952 --- /dev/null +++ b/src/mongo/s/chunk_range.idl @@ -0,0 +1,48 @@ +# Copyright (C) 2019-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# <http://www.mongodb.com/licensing/server-side-public-license>. +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# + +# IDL type for the ChunkRange class + +global: + cpp_namespace: "mongo" + cpp_includes: + - "mongo/s/catalog/type_chunk.h" + +imports: + - "mongo/idl/basic_types.idl" + +types: + # Note that in order to use this type for a non-optional field, you must add the IDL struct as a + # friend class of ChunkRange so that it can access its default constructor. + chunk_range: + description: "Represents the bounds of a chunk range. See ChunkRange for the semantics of + the bounds." + bson_serialization_type: object + cpp_type: "mongo::ChunkRange" + serializer: "mongo::ChunkRange::toBSON" + deserializer: "mongo::ChunkRange::fromBSONThrowing" diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h index ae82c800264..5f7e27d35b9 100644 --- a/src/mongo/util/uuid.h +++ b/src/mongo/util/uuid.h @@ -76,6 +76,7 @@ class UUID { friend class LogicalSessionToClient; friend class LogicalSessionIdToClient; friend class LogicalSessionFromClient; + friend class MigrationCoordinatorDocument; friend class RangeDeletionTask; friend class ResolvedKeyId; friend class repl::CollectionInfo; |