summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/repl/SConscript60
-rw-r--r--src/mongo/db/repl/database_cloner.cpp6
-rw-r--r--src/mongo/db/repl/database_cloner.idl5
-rw-r--r--src/mongo/db/repl/database_cloner_common.cpp42
-rw-r--r--src/mongo/db/repl/database_cloner_common.h39
-rw-r--r--src/mongo/db/repl/tenant_collection_cloner.cpp93
-rw-r--r--src/mongo/db/repl/tenant_collection_cloner.h106
-rw-r--r--src/mongo/db/repl/tenant_database_cloner.cpp171
-rw-r--r--src/mongo/db/repl/tenant_database_cloner.h130
9 files changed, 638 insertions, 14 deletions
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',
@@ -995,6 +994,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=[
'task_runner.cpp',
@@ -1085,6 +1101,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=[
'initial_syncer.cpp',
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<Latch> 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
+ * <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.
+ */
+
+#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
+ * <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/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
+ * <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_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<Latch> 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<Milliseconds>(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
+ * <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 <memory>
+#include <vector>
+
+#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<TenantCollectionCloner> _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
+ * <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_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<Latch> 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<Latch> 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<Latch> lk(_mutex);
+ _currentCollectionCloner =
+ std::make_unique<TenantCollectionCloner>(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<Latch> 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<Latch> lk(_mutex);
+ _stats.end = getSharedData()->getClock()->now();
+}
+
+TenantDatabaseCloner::Stats TenantDatabaseCloner::getStats() const {
+ stdx::lock_guard<Latch> 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<Milliseconds>(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
+ * <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 <vector>
+
+#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<TenantCollectionCloner::Stats> 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<TenantDatabaseCloner> {
+ public:
+ TenantDatabaseClonerStage(std::string name,
+ TenantDatabaseCloner* cloner,
+ ClonerRunFn stageFunc)
+ : ClonerStage<TenantDatabaseCloner>(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<std::pair<NamespaceString, CollectionOptions>> _collections; // (X)
+ std::unique_ptr<TenantCollectionCloner> _currentCollectionCloner; // (MX)
+
+ TenantDatabaseClonerStage _listCollectionsStage; // (R)
+
+ Stats _stats; // (MX)
+};
+
+
+} // namespace repl
+} // namespace mongo \ No newline at end of file