/** * Copyright (C) 2018-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 * . * * 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/database_sharding_state.h" #include "mongo/s/request_types/move_primary_gen.h" #include "mongo/s/shard_id.h" #include "mongo/util/timer.h" namespace mongo { class OperationContext; class Shard; struct ShardingStatistics; class Status; /** * The donor-side movePrimary state machine. This object must be created and owned by a single * thread, which controls its lifetime and should not be passed across threads. Unless explicitly * indicated its methods must not be called from more than one thread and must not be called while * any locks are held. * * The intended workflow is as follows: * - Acquire a distributed lock on the database whose primary is about to be moved. * - Instantiate a MovePrimarySourceManager on the stack. * - Call clone to start and finish cloning of the unsharded collections. * - Call enterCriticalSection to cause the shard to enter in 'read only' mode while the config * server is notified of the new primary. * - Call commitOnConfig to indicate the new primary in the config server metadata. * - Call cleanStaleData to drop now-unused collections (and potentially databases) on the * old primary. * * At any point in time it is safe to let the MovePrimarySourceManager object go out of scope in * which case the destructor will take care of clean up based on how far we have advanced. */ class MovePrimarySourceManager { MovePrimarySourceManager(const MovePrimarySourceManager&) = delete; MovePrimarySourceManager& operator=(const MovePrimarySourceManager&) = delete; public: /** * Instantiates a new movePrimary source manager. Must be called with the distributed lock * acquired in advance (not asserted). * * May throw any exception. Known exceptions (TODO) are: * - InvalidOptions if the operation context is missing database version * - StaleConfigException if the expected database version does not match what we find it * to be after acquiring the distributed lock. */ MovePrimarySourceManager(OperationContext* opCtx, ShardMovePrimary requestArgs, StringData dbname, ShardId& fromShard, ShardId& toShard); ~MovePrimarySourceManager(); /** * Returns the namespace for which this source manager is active. */ NamespaceString getNss() const; /** * Contacts the recipient shard and tells it to start cloning the specified chunk. This method * will fail if for any reason the recipient shard fails to complete the cloning sequence. * * Expected state: kCreated * Resulting state: kCloning on success, kDone on failure */ Status clone(OperationContext* opCtx); /** * Once this call returns successfully, no writes will be happening on this shard until the * movePrimary is committed. Therefore, commitMovePrimaryMetadata must be called as soon as * possible afterwards. * * Expected state: kCloneCaughtUp * Resulting state: kCriticalSection on success, kDone on failure */ Status enterCriticalSection(OperationContext* opCtx); /** * Persists the updated DatabaseVersion on the config server and leaves the critical section. * * Expected state: kCriticalSection * Resulting state: kNeedCleanStaleData */ Status commitOnConfig(OperationContext* opCtx); /** * Clears stale collections (and potentially databases) on the old primary. * * Expected state: kNeedCleanStaleData * Resulting state: kDone */ Status cleanStaleData(OperationContext* opCtx); /** * May be called at any time. Unregisters the movePrimary source manager from the database and * logs an error in the change log to indicate that the migration has failed. * * Expected state: Any * Resulting state: kDone */ void cleanupOnError(OperationContext* opCtx); private: static BSONObj _buildMoveLogEntry(const std::string& db, const std::string& from, const std::string& to) { BSONObjBuilder details; details.append("database", db); details.append("from", from); details.append("to", to); return details.obj(); } /** * Updates CSRS metadata in config.databases collection to move the given primary database on * its new shard. */ Status _commitOnConfig(OperationContext* opCtx); // Used to track the current state of the source manager. See the methods above, which have // comments explaining the various state transitions. enum State { kCreated, kCloning, kCloneCaughtUp, kCriticalSection, kCloneCompleted, kNeedCleanStaleData, kDone }; /** * Called when any of the states fails. May only be called once and will put the migration * manager into the kDone state. */ void _cleanup(OperationContext* opCtx); // The parameters to the movePrimary command const ShardMovePrimary _requestArgs; // The database whose primary we are moving. const StringData _dbname; // The donor shard const ShardId& _fromShard; // The recipient shard const ShardId& _toShard; // Collections that were cloned to the new primary std::vector _clonedColls; // Indicates whether sharded collections exist on the old primary. bool _shardedCollectionsExistOnDb; // Times the entire movePrimary operation const Timer _entireOpTimer; // The current state. Used only for diagnostics and validation. State _state{kCreated}; }; } // namespace mongo