From 8d6112714189fdb6c652ad06a9496c5ade6c0cdc Mon Sep 17 00:00:00 2001 From: Vesselina Ratcheva Date: Tue, 30 Jun 2020 23:38:02 +0000 Subject: SERVER-48816 Make a TenantDatabaseCloner skeleton class --- src/mongo/db/repl/SConscript | 60 ++++++++- src/mongo/db/repl/database_cloner.cpp | 6 +- src/mongo/db/repl/database_cloner.idl | 5 +- src/mongo/db/repl/database_cloner_common.cpp | 42 ++++++ src/mongo/db/repl/database_cloner_common.h | 39 ++++++ src/mongo/db/repl/tenant_collection_cloner.cpp | 93 ++++++++++++++ src/mongo/db/repl/tenant_collection_cloner.h | 106 +++++++++++++++ src/mongo/db/repl/tenant_database_cloner.cpp | 171 +++++++++++++++++++++++++ src/mongo/db/repl/tenant_database_cloner.h | 130 +++++++++++++++++++ 9 files changed, 638 insertions(+), 14 deletions(-) create mode 100644 src/mongo/db/repl/database_cloner_common.cpp create mode 100644 src/mongo/db/repl/database_cloner_common.h create mode 100644 src/mongo/db/repl/tenant_collection_cloner.cpp create mode 100644 src/mongo/db/repl/tenant_collection_cloner.h create mode 100644 src/mongo/db/repl/tenant_database_cloner.cpp create mode 100644 src/mongo/db/repl/tenant_database_cloner.h diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 7c68f650174..c9aeb038459 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -689,8 +689,8 @@ env.Library( '$BUILD_DIR/mongo/rpc/metadata', '$BUILD_DIR/mongo/transport/transport_layer_common', '$BUILD_DIR/mongo/util/fail_point', - 'initial_syncer', 'data_replicator_external_state_initial_sync', + 'initial_syncer', 'repl_coordinator_interface', 'repl_settings', 'replica_set_messages', @@ -698,6 +698,7 @@ env.Library( 'replication_process', 'reporter', 'scatter_gather', + 'tenant_migration_cloners', 'topology_coordinator', ], LIBDEPS_PRIVATE=[ @@ -967,16 +968,16 @@ env.Library( target='initial_sync_cloners', source=[ 'all_database_cloner.cpp', - 'base_cloner.cpp', 'collection_cloner.cpp', 'database_cloner.cpp', - env.Idlc('database_cloner.idl')[0] ], LIBDEPS = [ - 'task_runner', + 'base_cloner', + 'database_cloner_common', 'initial_sync_shared_data', 'member_data', 'replication_consistency_markers_impl', + 'task_runner', '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/client/clientdriver_network', '$BUILD_DIR/mongo/util/concurrency/thread_pool', @@ -985,8 +986,6 @@ env.Library( LIBDEPS_PRIVATE=[ 'repl_server_parameters', 'replication_auth', - '$BUILD_DIR/mongo/idl/idl_parser', - '$BUILD_DIR/mongo/db/catalog/collection_options', '$BUILD_DIR/mongo/db/commands/list_collections_filter', '$BUILD_DIR/mongo/db/index_builds_coordinator_interface', '$BUILD_DIR/mongo/db/index_build_entry_helpers', @@ -994,6 +993,23 @@ env.Library( ] ) +env.Library( + target='tenant_migration_cloners', + source=[ + 'tenant_collection_cloner.cpp', + 'tenant_database_cloner.cpp', + ], + LIBDEPS = [ + 'base_cloner', + 'database_cloner_common', + 'initial_sync_shared_data', + '$BUILD_DIR/mongo/base', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/commands/list_collections_filter', + ] +) + env.Library( target='task_runner', source=[ @@ -1084,6 +1100,38 @@ env.Library( ] ) +env.Library( + target='base_cloner', + source=[ + 'base_cloner.cpp', + ], + LIBDEPS=[ + 'initial_sync_shared_data', + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/client/clientdriver_network', + '$BUILD_DIR/mongo/util/fail_point', + ], + LIBDEPS_PRIVATE=[ + 'repl_server_parameters', + 'replication_consistency_markers_impl', + ] +) + +env.Library( + target='database_cloner_common', + source=[ + 'database_cloner_common.cpp', + env.Idlc('database_cloner.idl')[0], + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/catalog/collection_options', + '$BUILD_DIR/mongo/idl/idl_parser', + ] +) + env.Library( target='initial_syncer', source=[ diff --git a/src/mongo/db/repl/database_cloner.cpp b/src/mongo/db/repl/database_cloner.cpp index ce5bb9053cc..f9bcd83fc05 100644 --- a/src/mongo/db/repl/database_cloner.cpp +++ b/src/mongo/db/repl/database_cloner.cpp @@ -34,6 +34,7 @@ #include "mongo/base/string_data.h" #include "mongo/db/commands/list_collections_filter.h" #include "mongo/db/repl/database_cloner.h" +#include "mongo/db/repl/database_cloner_common.h" #include "mongo/db/repl/database_cloner_gen.h" #include "mongo/logv2/log.h" #include "mongo/util/assert_util.h" @@ -58,11 +59,6 @@ BaseCloner::ClonerStages DatabaseCloner::getStages() { return {&_listCollectionsStage}; } -/* static */ -CollectionOptions DatabaseCloner::parseCollectionOptions(const BSONObj& obj) { - return uassertStatusOK(CollectionOptions::parse(obj, CollectionOptions::parseForStorage)); -} - void DatabaseCloner::preStage() { stdx::lock_guard lk(_mutex); _stats.start = getSharedData()->getClock()->now(); diff --git a/src/mongo/db/repl/database_cloner.idl b/src/mongo/db/repl/database_cloner.idl index 738098a087d..c5d5d3342d9 100644 --- a/src/mongo/db/repl/database_cloner.idl +++ b/src/mongo/db/repl/database_cloner.idl @@ -28,8 +28,7 @@ global: cpp_namespace: mongo::repl cpp_includes: - - "mongo/db/catalog/collection_options.h" - - "mongo/db/repl/database_cloner.h" + - "mongo/db/repl/database_cloner_common.h" imports: - "mongo/idl/basic_types.idl" @@ -39,7 +38,7 @@ types: description: "CollectionOptions as passed to createCollection()" cpp_type: "mongo::CollectionOptions" bson_serialization_type: object - deserializer: mongo::repl::DatabaseCloner::parseCollectionOptions + deserializer: mongo::repl::parseCollectionOptionsForDatabaseCloner serializer: mongo::CollectionOptions::toBSON structs: diff --git a/src/mongo/db/repl/database_cloner_common.cpp b/src/mongo/db/repl/database_cloner_common.cpp new file mode 100644 index 00000000000..68ebd7c333a --- /dev/null +++ b/src/mongo/db/repl/database_cloner_common.cpp @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2020-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. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/repl/database_cloner_common.h" + +namespace mongo { +namespace repl { + +CollectionOptions parseCollectionOptionsForDatabaseCloner(const BSONObj& obj) { + return uassertStatusOK(CollectionOptions::parse(obj, CollectionOptions::parseForStorage)); +} + +} // namespace repl +} // namespace mongo \ No newline at end of file diff --git a/src/mongo/db/repl/database_cloner_common.h b/src/mongo/db/repl/database_cloner_common.h new file mode 100644 index 00000000000..24f43cfb066 --- /dev/null +++ b/src/mongo/db/repl/database_cloner_common.h @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2020-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/catalog/collection_options.h" + +namespace mongo { +namespace repl { + +CollectionOptions parseCollectionOptionsForDatabaseCloner(const BSONObj& obj); +} +} // namespace mongo \ No newline at end of file diff --git a/src/mongo/db/repl/tenant_collection_cloner.cpp b/src/mongo/db/repl/tenant_collection_cloner.cpp new file mode 100644 index 00000000000..be1d6c0a3de --- /dev/null +++ b/src/mongo/db/repl/tenant_collection_cloner.cpp @@ -0,0 +1,93 @@ +/** + * Copyright (C) 2020-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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kReplicationInitialSync + +#include "mongo/platform/basic.h" + +#include "mongo/base/string_data.h" +#include "mongo/db/commands/list_collections_filter.h" +#include "mongo/db/repl/database_cloner_gen.h" +#include "mongo/db/repl/tenant_collection_cloner.h" +#include "mongo/logv2/log.h" +#include "mongo/util/assert_util.h" + +namespace mongo { +namespace repl { + +TenantCollectionCloner::TenantCollectionCloner(const NamespaceString& sourceNss, + const CollectionOptions& collectionOptions, + InitialSyncSharedData* sharedData, + const HostAndPort& source, + DBClientConnection* client, + StorageInterface* storageInterface, + ThreadPool* dbPool) + : BaseCloner("TenantCollectionCloner"_sd, sharedData, source, client, storageInterface, dbPool), + _sourceNss(sourceNss), + _collectionOptions(collectionOptions), + _sourceDbAndUuid(NamespaceString("UNINITIALIZED")), + _placeholderStage("placeholder", this, &TenantCollectionCloner::placeholderStage) { + invariant(sourceNss.isValid()); + invariant(collectionOptions.uuid); + _sourceDbAndUuid = NamespaceStringOrUUID(sourceNss.db().toString(), *collectionOptions.uuid); + _stats.ns = _sourceNss.ns(); +} + +BaseCloner::ClonerStages TenantCollectionCloner::getStages() { + return {&_placeholderStage}; +} + +BaseCloner::AfterStageBehavior TenantCollectionCloner::placeholderStage() { + return kContinueNormally; +} + +TenantCollectionCloner::Stats TenantCollectionCloner::getStats() const { + stdx::lock_guard lk(_mutex); + return _stats; +} + +void TenantCollectionCloner::Stats::append(BSONObjBuilder* builder) const { + builder->appendNumber(kDocumentsToCopyFieldName, documentToCopy); + builder->appendNumber(kDocumentsCopiedFieldName, documentsCopied); + builder->appendNumber("indexes", indexes); + builder->appendNumber("insertedBatches", insertedBatches); + if (start != Date_t()) { + builder->appendDate("start", start); + if (end != Date_t()) { + builder->appendDate("end", end); + auto elapsed = end - start; + long long elapsedMillis = duration_cast(elapsed).count(); + builder->appendNumber("elapsedMillis", elapsedMillis); + } + } + builder->appendNumber("receivedBatches", receivedBatches); +} + +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/tenant_collection_cloner.h b/src/mongo/db/repl/tenant_collection_cloner.h new file mode 100644 index 00000000000..ee8c9bf2ced --- /dev/null +++ b/src/mongo/db/repl/tenant_collection_cloner.h @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2020-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 +#include + +#include "mongo/db/repl/base_cloner.h" +#include "mongo/db/repl/task_runner.h" +#include "mongo/util/progress_meter.h" + +namespace mongo { +namespace repl { + +class TenantCollectionCloner : public BaseCloner { +public: + struct Stats { + static constexpr StringData kDocumentsToCopyFieldName = "documentsToCopy"_sd; + static constexpr StringData kDocumentsCopiedFieldName = "documentsCopied"_sd; + + std::string ns; + Date_t start; + Date_t end; + size_t documentToCopy{0}; + size_t documentsCopied{0}; + size_t indexes{0}; + size_t insertedBatches{0}; + size_t receivedBatches{0}; + + std::string toString() const; + BSONObj toBSON() const; + void append(BSONObjBuilder* builder) const; + }; + + TenantCollectionCloner(const NamespaceString& ns, + const CollectionOptions& collectionOptions, + InitialSyncSharedData* sharedData, + const HostAndPort& source, + DBClientConnection* client, + StorageInterface* storageInterface, + ThreadPool* dbPool); + + virtual ~TenantCollectionCloner() = default; + + Stats getStats() const; + +protected: + ClonerStages getStages() final; + +private: + std::string describeForFuzzer(BaseClonerStage* stage) const final { + return _sourceNss.db() + " db: { " + stage->getName() + ": UUID(\"" + + _sourceDbAndUuid.uuid()->toString() + "\") coll: " + _sourceNss.coll() + " }"; + } + + /** + * Temporary no-op stage. + */ + AfterStageBehavior placeholderStage(); + + // All member variables are labeled with one of the following codes indicating the + // synchronization rules for accessing them. + // + // (R) Read-only in concurrent operation; no synchronization required. + // (S) Self-synchronizing; access according to class's own rules. + // (M) Reads and writes guarded by _mutex (defined in base class). + // (X) Access only allowed from the main flow of control called from run() or constructor. + const NamespaceString _sourceNss; // (R) + const CollectionOptions _collectionOptions; // (R) + // Despite the type name, this member must always contain a UUID. + NamespaceStringOrUUID _sourceDbAndUuid; // (R) + + ClonerStage _placeholderStage; // (R) + + Stats _stats; // (M) +}; + +} // namespace repl +} // namespace mongo \ No newline at end of file diff --git a/src/mongo/db/repl/tenant_database_cloner.cpp b/src/mongo/db/repl/tenant_database_cloner.cpp new file mode 100644 index 00000000000..9e9fbc5c72b --- /dev/null +++ b/src/mongo/db/repl/tenant_database_cloner.cpp @@ -0,0 +1,171 @@ +/** + * Copyright (C) 2020-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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kReplicationInitialSync + +#include "mongo/platform/basic.h" + +#include "mongo/base/string_data.h" +#include "mongo/db/commands/list_collections_filter.h" +#include "mongo/db/repl/database_cloner_gen.h" +#include "mongo/db/repl/tenant_collection_cloner.h" +#include "mongo/db/repl/tenant_database_cloner.h" +#include "mongo/logv2/log.h" +#include "mongo/util/assert_util.h" + +namespace mongo { +namespace repl { + +TenantDatabaseCloner::TenantDatabaseCloner(const std::string& dbName, + InitialSyncSharedData* sharedData, + const HostAndPort& source, + DBClientConnection* client, + StorageInterface* storageInterface, + ThreadPool* dbPool) + : BaseCloner("TenantDatabaseCloner"_sd, sharedData, source, client, storageInterface, dbPool), + _dbName(dbName), + _listCollectionsStage("listCollections", this, &TenantDatabaseCloner::listCollectionsStage) { + invariant(!dbName.empty()); + _stats.dbname = dbName; +} + +BaseCloner::ClonerStages TenantDatabaseCloner::getStages() { + return {&_listCollectionsStage}; +} + +void TenantDatabaseCloner::preStage() { + stdx::lock_guard lk(_mutex); + _stats.start = getSharedData()->getClock()->now(); +} + +BaseCloner::AfterStageBehavior TenantDatabaseCloner::listCollectionsStage() { + // TODO(SERVER-48816): Implement this stage. + return kContinueNormally; +} + +bool TenantDatabaseCloner::isMyFailPoint(const BSONObj& data) const { + return data["database"].str() == _dbName && BaseCloner::isMyFailPoint(data); +} + +void TenantDatabaseCloner::postStage() { + { + stdx::lock_guard lk(_mutex); + _stats.collections = _collections.size(); + _stats.collectionStats.reserve(_collections.size()); + for (const auto& coll : _collections) { + _stats.collectionStats.emplace_back(); + _stats.collectionStats.back().ns = coll.first.ns(); + } + } + for (const auto& coll : _collections) { + auto& sourceNss = coll.first; + auto& collectionOptions = coll.second; + { + stdx::lock_guard lk(_mutex); + _currentCollectionCloner = + std::make_unique(sourceNss, + collectionOptions, + getSharedData(), + getSource(), + getClient(), + getStorageInterface(), + getDBPool()); + } + auto collStatus = _currentCollectionCloner->run(); + if (collStatus.isOK()) { + LOGV2_DEBUG( + 4881600, 1, "Tenant collection clone finished", "namespace"_attr = sourceNss); + } else { + LOGV2_ERROR(4881601, + "Tenant collection clone failed", + "namespace"_attr = sourceNss, + "error"_attr = collStatus.toString()); + setInitialSyncFailedStatus( + {collStatus.code(), + collStatus + .withContext(str::stream() + << "Error cloning collection '" << sourceNss.toString() << "'") + .toString()}); + } + { + stdx::lock_guard lk(_mutex); + _stats.collectionStats[_stats.clonedCollections] = _currentCollectionCloner->getStats(); + _currentCollectionCloner = nullptr; + // Abort the tenant database cloner if the collection clone failed. + if (!collStatus.isOK()) + return; + _stats.clonedCollections++; + } + } + stdx::lock_guard lk(_mutex); + _stats.end = getSharedData()->getClock()->now(); +} + +TenantDatabaseCloner::Stats TenantDatabaseCloner::getStats() const { + stdx::lock_guard lk(_mutex); + TenantDatabaseCloner::Stats stats = _stats; + if (_currentCollectionCloner) { + stats.collectionStats[_stats.clonedCollections] = _currentCollectionCloner->getStats(); + } + return stats; +} + +std::string TenantDatabaseCloner::Stats::toString() const { + return toBSON().toString(); +} + +BSONObj TenantDatabaseCloner::Stats::toBSON() const { + BSONObjBuilder bob; + bob.append("dbname", dbname); + append(&bob); + return bob.obj(); +} + +void TenantDatabaseCloner::Stats::append(BSONObjBuilder* builder) const { + builder->appendNumber("collections", collections); + builder->appendNumber("clonedCollections", clonedCollections); + if (start != Date_t()) { + builder->appendDate("start", start); + if (end != Date_t()) { + builder->appendDate("end", end); + auto elapsed = end - start; + long long elapsedMillis = duration_cast(elapsed).count(); + builder->appendNumber("elapsedMillis", elapsedMillis); + } + } + + for (auto&& collection : collectionStats) { + BSONObjBuilder collectionBuilder(builder->subobjStart(collection.ns)); + collection.append(&collectionBuilder); + collectionBuilder.doneFast(); + } +} + +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/tenant_database_cloner.h b/src/mongo/db/repl/tenant_database_cloner.h new file mode 100644 index 00000000000..eaa681118f2 --- /dev/null +++ b/src/mongo/db/repl/tenant_database_cloner.h @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2020-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 + +#include "mongo/db/repl/base_cloner.h" +#include "mongo/db/repl/tenant_collection_cloner.h" + +namespace mongo { +namespace repl { + +class TenantDatabaseCloner final : public BaseCloner { +public: + struct Stats { + std::string dbname; + Date_t start; + Date_t end; + size_t collections{0}; + size_t clonedCollections{0}; + std::vector collectionStats; + + std::string toString() const; + BSONObj toBSON() const; + void append(BSONObjBuilder* builder) const; + }; + + TenantDatabaseCloner(const std::string& dbName, + InitialSyncSharedData* sharedData, + const HostAndPort& source, + DBClientConnection* client, + StorageInterface* storageInterface, + ThreadPool* dbPool); + + virtual ~TenantDatabaseCloner() = default; + + Stats getStats() const; + + std::string toString() const; + +protected: + ClonerStages getStages() final; + + bool isMyFailPoint(const BSONObj& data) const final; + +private: + // TODO(SERVER-48816): implement unit tests + // friend class TenantDatabaseclonerTest; + + class TenantDatabaseClonerStage : public ClonerStage { + public: + TenantDatabaseClonerStage(std::string name, + TenantDatabaseCloner* cloner, + ClonerRunFn stageFunc) + : ClonerStage(name, cloner, stageFunc) {} + + bool isTransientError(const Status& status) override { + // Always abort on error. + return false; + } + }; + + /** + * Stage function that retrieves collection information from the donor. + */ + AfterStageBehavior listCollectionsStage(); + + /** + * The preStage sets the start time in _stats. + */ + void preStage() final; + + /** + * The postStage creates and runs the individual TenantCollectionCloners on each database found + * on the sync source, and sets the end time in _stats when done. + */ + void postStage() final; + + std::string describeForFuzzer(BaseClonerStage* stage) const final { + return _dbName + " db: { " + stage->getName() + ": 1 } "; + } + + // All member variables are labeled with one of the following codes indicating the + // synchronization rules for accessing them. + // + // (R) Read-only in concurrent operation; no synchronization required. + // (S) Self-synchronizing; access according to class's own rules. + // (M) Reads and writes guarded by _mutex (defined in base class). + // (X) Access only allowed from the main flow of control called from run() or constructor. + // (MX) Write access with mutex from main flow of control, read access with mutex from other + // threads, read access allowed from main flow without mutex. + const std::string _dbName; // (R) + std::vector> _collections; // (X) + std::unique_ptr _currentCollectionCloner; // (MX) + + TenantDatabaseClonerStage _listCollectionsStage; // (R) + + Stats _stats; // (MX) +}; + + +} // namespace repl +} // namespace mongo \ No newline at end of file -- cgit v1.2.1