From 797ff5702922bc004ef251269281397d3d8e4d68 Mon Sep 17 00:00:00 2001 From: Matt Broadstone Date: Tue, 21 Sep 2021 09:51:57 +0000 Subject: SERVER-59679 Provide a skeleton implementation for slice split --- jstests/core/views/views_all_commands.js | 3 + .../db_reads_while_recovering_all_commands.js | 3 + .../read_write_concern_defaults_application.js | 3 + src/mongo/db/SConscript | 2 + src/mongo/db/namespace_string.cpp | 3 + src/mongo/db/namespace_string.h | 3 + src/mongo/db/repl/SConscript | 3 +- src/mongo/db/serverless/SConscript | 45 ++++++ src/mongo/db/serverless/tenant_split_commands.cpp | 170 +++++++++++++++++++++ src/mongo/db/serverless/tenant_split_commands.idl | 93 +++++++++++ .../db/serverless/tenant_split_donor_service.cpp | 67 ++++++++ .../db/serverless/tenant_split_donor_service.h | 85 +++++++++++ .../db/serverless/tenant_split_state_machine.idl | 67 ++++++++ 13 files changed, 546 insertions(+), 1 deletion(-) create mode 100644 src/mongo/db/serverless/SConscript create mode 100644 src/mongo/db/serverless/tenant_split_commands.cpp create mode 100644 src/mongo/db/serverless/tenant_split_commands.idl create mode 100644 src/mongo/db/serverless/tenant_split_donor_service.cpp create mode 100644 src/mongo/db/serverless/tenant_split_donor_service.h create mode 100644 src/mongo/db/serverless/tenant_split_state_machine.idl diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 922cfd509e4..f40ed053b54 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -277,6 +277,9 @@ let viewsCommandTests = { donorForgetMigration: {skip: isUnrelated}, donorStartMigration: {skip: isUnrelated}, donorWaitForMigrationToCommit: {skip: isUnrelated}, + donorAbortSplit: {skip: isUnrelated}, + donorForgetSplit: {skip: isUnrelated}, + donorStartSplit: {skip: isUnrelated}, driverOIDTest: {skip: isUnrelated}, drop: {command: {drop: "view"}}, dropAllRolesFromDatabase: {skip: isUnrelated}, diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js index d8fc65eb22c..ab8aea876f4 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -157,6 +157,9 @@ const allCommands = { donorForgetMigration: {skip: isPrimaryOnly}, donorStartMigration: {skip: isPrimaryOnly}, donorWaitForMigrationToCommit: {skip: isPrimaryOnly}, + donorAbortSplit: {skip: isPrimaryOnly}, + donorForgetSplit: {skip: isPrimaryOnly}, + donorStartSplit: {skip: isPrimaryOnly}, driverOIDTest: {skip: isNotAUserDataRead}, drop: {skip: isPrimaryOnly}, dropAllRolesFromDatabase: {skip: isPrimaryOnly}, diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index dff96eb9bba..bbb0207ef02 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -333,6 +333,9 @@ let testCases = { donorForgetMigration: {skip: "does not accept read or write concern"}, donorStartMigration: {skip: "does not accept read or write concern"}, donorWaitForMigrationToCommit: {skip: "does not accept read or write concern"}, + donorAbortSplit: {skip: "does not accept read or write concern"}, + donorForgetSplit: {skip: "does not accept read or write concern"}, + donorStartSplit: {skip: "does not accept read or write concern"}, driverOIDTest: {skip: "internal command"}, drop: { setUp: function(conn) { diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 028c0d3d3f5..74e28f13ddf 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -38,6 +38,7 @@ env.SConscript( 'query', 'repl', 's', + 'serverless', 'sorter', 'stats', 'storage', @@ -2159,6 +2160,7 @@ env.Library( 'repl/storage_interface_impl', 'repl/topology_coordinator', 'rw_concern_d', + 'serverless/tenant_split_commands', 'service_liaison_mongod', 'sessions_collection_rs', 'sessions_collection_standalone', diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp index 4840b8cd402..b57e1054a0f 100644 --- a/src/mongo/db/namespace_string.cpp +++ b/src/mongo/db/namespace_string.cpp @@ -78,6 +78,9 @@ const NamespaceString NamespaceString::kTenantMigrationRecipientsNamespace( const NamespaceString NamespaceString::kTenantMigrationOplogView( NamespaceString::kLocalDb, "system.tenantMigration.oplogView"); +const NamespaceString NamespaceString::kTenantSplitDonorsNamespace(NamespaceString::kConfigDb, + "tenantSplitDonors"); + 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 078fe8a9d47..ca1a0bbd4bc 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -133,6 +133,9 @@ public: // Namespace for view on local.oplog.rs for tenant migrations. static const NamespaceString kTenantMigrationOplogView; + // Namespace for storing the persisted state of tenant split donors. + static const NamespaceString kTenantSplitDonorsNamespace; + // Namespace for replica set configuration settings. static const NamespaceString kSystemReplSetNamespace; diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 1cb28229770..071d88b0f99 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -1305,7 +1305,8 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/util/future_util', - "repl_server_parameters", + 'repl_coordinator_interface', + 'repl_server_parameters', 'wait_for_majority_service', ], LIBDEPS_PRIVATE=[ diff --git a/src/mongo/db/serverless/SConscript b/src/mongo/db/serverless/SConscript new file mode 100644 index 00000000000..0eda40c2aa4 --- /dev/null +++ b/src/mongo/db/serverless/SConscript @@ -0,0 +1,45 @@ +# -*- mode: python -*- + +Import("env") +env = env.Clone() + +env.Library( + target='tenant_split_state_machine', + source=[ + 'tenant_split_state_machine.idl', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/client/connection_string', + '$BUILD_DIR/mongo/db/repl/tenant_migration_utils', + '$BUILD_DIR/mongo/idl/idl_parser' + ], +) + +env.Library( + target='tenant_split_commands', + source=[ + 'tenant_split_commands.idl', + 'tenant_split_commands.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/client/connection_string', + '$BUILD_DIR/mongo/db/repl/tenant_migration_utils', + '$BUILD_DIR/mongo/idl/idl_parser', + 'tenant_split_state_machine', + ] +) + +env.Library( + target='tenant_split_donor_service', + source=[ + 'tenant_split_donor_service.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/repl/primary_only_service', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/namespace_string', + ] +) diff --git a/src/mongo/db/serverless/tenant_split_commands.cpp b/src/mongo/db/serverless/tenant_split_commands.cpp new file mode 100644 index 00000000000..060e7a5fd15 --- /dev/null +++ b/src/mongo/db/serverless/tenant_split_commands.cpp @@ -0,0 +1,170 @@ +/** + * Copyright (C) 2021-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/db/auth/authorization_session.h" +#include "mongo/db/serverless/tenant_split_commands_gen.h" + +namespace mongo { +namespace { + +class DonorStartSplitCmd : public TypedCommand { +public: + using Request = DonorStartSplit; + using Response = DonorStartSplitResponse; + + class Invocation : public InvocationBase { + + public: + using InvocationBase::InvocationBase; + + Response typedRun(OperationContext* opCtx) { + return Response(TenantSplitDonorStateEnum::kCommitted); + } + + private: + void doCheckAuthorization(OperationContext* opCtx) const final { + uassert(ErrorCodes::Unauthorized, + "Unauthorized", + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::runTenantMigration)); + } + + bool supportsWriteConcern() const override { + return true; + } + + NamespaceString ns() const { + return NamespaceString(request().getDbName(), ""); + } + }; + + std::string help() const { + return "Start an opereation to split a tenant into its own slice."; + } + + bool adminOnly() const override { + return true; + } + + BasicCommand::AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return BasicCommand::AllowedOnSecondary::kNever; + } +} donorStartSplitCmd; + +class DonorForgetSplitCmd : public TypedCommand { +public: + using Request = DonorForgetSplit; + + class Invocation : public InvocationBase { + + public: + using InvocationBase::InvocationBase; + + void typedRun(OperationContext* opCtx) { + return; + } + + private: + void doCheckAuthorization(OperationContext* opCtx) const final { + uassert(ErrorCodes::Unauthorized, + "Unauthorized", + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::runTenantMigration)); + } + + bool supportsWriteConcern() const override { + return true; + } + + NamespaceString ns() const { + return NamespaceString(request().getDbName(), ""); + } + }; + + std::string help() const override { + return "Forget a tenant split operation."; + } + + bool adminOnly() const override { + return true; + } + + BasicCommand::AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return BasicCommand::AllowedOnSecondary::kNever; + } +} donorForgetSplitCmd; + +class DonorAbortSplitCmd : public TypedCommand { +public: + using Request = DonorAbortSplit; + + class Invocation : public InvocationBase { + + public: + using InvocationBase::InvocationBase; + + void typedRun(OperationContext* opCtx) { + return; + } + + private: + void doCheckAuthorization(OperationContext* opCtx) const final { + uassert(ErrorCodes::Unauthorized, + "Unauthorized", + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::runTenantMigration)); + } + + bool supportsWriteConcern() const override { + return true; + } + + NamespaceString ns() const { + return NamespaceString(request().getDbName(), ""); + } + }; + + std::string help() const override { + return "Abort a tenant split operation."; + } + + bool adminOnly() const override { + return true; + } + + BasicCommand::AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return BasicCommand::AllowedOnSecondary::kNever; + } +} donorAbortSplitCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/serverless/tenant_split_commands.idl b/src/mongo/db/serverless/tenant_split_commands.idl new file mode 100644 index 00000000000..037d8624294 --- /dev/null +++ b/src/mongo/db/serverless/tenant_split_commands.idl @@ -0,0 +1,93 @@ +# Copyright (C) 2021-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. +# + +global: + cpp_namespace: "mongo" + cpp_includes: + - "mongo/db/repl/tenant_migration_util.h" + +imports: + - "mongo/db/serverless/tenant_split_state_machine.idl" + - "mongo/idl/basic_types.idl" + +structs: + DonorStartSplitResponse: + description: "Response for the `donorStartSplit` command." + strict: false + fields: + state: + type: TenantSplitDonorState + description: "The state of the tenant split operation." + abortReason: + type: object + description: "The error that caused the tenant split operation to abort." + optional: true + +commands: + donorStartSplit: + description: "Parser for the `donorStartSplit` command." + command_name: donorStartSplit + strict: true + namespace: ignored + api_version: "" + fields: + migrationId: + description: "Unique identifier for the tenant split operation." + type: uuid + recipientConnectionString: + description: "The connection string for the recipient slice." + type: string + validator: + callback: "tenant_migration_util::validateConnectionString" + tenantId: + description: "The identifier for the tenant being migrated." + type: string + validator: + callback: "tenant_migration_util::validateDatabasePrefix" + + donorForgetSplit: + description: "Parser for the `donorForgetSplit` command." + command_name: donorForgetSplit + strict: true + namespace: ignored + api_version: "" + fields: + migrationId: + description: "Unique identifier for the tenant split operation." + type: uuid + + donorAbortSplit: + description: "Parser for the `donorAbortSplit` command." + command_name: donorAbortSplit + strict: true + namespace: ignored + api_version: "" + fields: + migrationId: + description: "Unique identifier for the tenant split operation." + type: uuid diff --git a/src/mongo/db/serverless/tenant_split_donor_service.cpp b/src/mongo/db/serverless/tenant_split_donor_service.cpp new file mode 100644 index 00000000000..54e5b28e8a2 --- /dev/null +++ b/src/mongo/db/serverless/tenant_split_donor_service.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (C) 2021-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::kTenantMigration + +#include "mongo/db/serverless/tenant_split_donor_service.h" + +namespace mongo { + +ThreadPool::Limits TenantSplitDonorService::getThreadPoolLimits() const { + return ThreadPool::Limits(); +} + +std::shared_ptr TenantSplitDonorService::constructInstance( + BSONObj initialState) { + return std::make_shared(this, initialState); +} + +TenantSplitDonorService::DonorStateMachine::DonorStateMachine( + const TenantSplitDonorService* donorService, const BSONObj& initialState) + : repl::PrimaryOnlyService::TypedInstance(), _donorService(donorService) {} + +boost::optional TenantSplitDonorService::DonorStateMachine::reportForCurrentOp( + MongoProcessInterface::CurrentOpConnectionsMode connMode, + MongoProcessInterface::CurrentOpSessionsMode sessionMode) noexcept { + + stdx::lock_guard lg(_mutex); + BSONObjBuilder bob; + bob.append("desc", "tenant split operation"); + return bob.obj(); +} + +void TenantSplitDonorService::DonorStateMachine::interrupt(Status status) {} + +SemiFuture TenantSplitDonorService::DonorStateMachine::run( + std::shared_ptr executor, + const CancellationToken& token) noexcept { + return SemiFuture(); +} + +} // namespace mongo diff --git a/src/mongo/db/serverless/tenant_split_donor_service.h b/src/mongo/db/serverless/tenant_split_donor_service.h new file mode 100644 index 00000000000..8e964040341 --- /dev/null +++ b/src/mongo/db/serverless/tenant_split_donor_service.h @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2021-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/repl/primary_only_service.h" + +namespace mongo { + +class TenantSplitDonorService final : public repl::PrimaryOnlyService { +public: + static constexpr StringData kServiceName = "TenantSplitDonorService"_sd; + + explicit TenantSplitDonorService(ServiceContext* const serviceContext) + : PrimaryOnlyService(serviceContext) {} + ~TenantSplitDonorService() = default; + + class DonorStateMachine; + + StringData getServiceName() const override { + return kServiceName; + } + + NamespaceString getStateDocumentsNS() const override { + return NamespaceString::kTenantSplitDonorsNamespace; + } + + ThreadPool::Limits getThreadPoolLimits() const override; + +protected: + std::shared_ptr constructInstance(BSONObj initialState) override; +}; + +class TenantSplitDonorService::DonorStateMachine final + : public repl::PrimaryOnlyService::TypedInstance { +public: + explicit DonorStateMachine(const TenantSplitDonorService* donorService, + const BSONObj& initialState); + + ~DonorStateMachine() = default; + + SemiFuture run(std::shared_ptr executor, + const CancellationToken& token) noexcept override; + + void interrupt(Status status) override; + + /** + * Report TenantMigrationDonorService Instances in currentOp(). + */ + boost::optional reportForCurrentOp( + MongoProcessInterface::CurrentOpConnectionsMode connMode, + MongoProcessInterface::CurrentOpSessionsMode sessionMode) noexcept override; + +private: + const TenantSplitDonorService* const _donorService; + mutable Mutex _mutex = MONGO_MAKE_LATCH("TenantSplitDonorService::_mutex"); +}; + +} // namespace mongo diff --git a/src/mongo/db/serverless/tenant_split_state_machine.idl b/src/mongo/db/serverless/tenant_split_state_machine.idl new file mode 100644 index 00000000000..c3f03bb4400 --- /dev/null +++ b/src/mongo/db/serverless/tenant_split_state_machine.idl @@ -0,0 +1,67 @@ +# Copyright (C) 2021-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. +# +global: + cpp_namespace: "mongo" + cpp_includes: + - "mongo/db/repl/tenant_migration_util.h" + +imports: + - "mongo/idl/basic_types.idl" + +enums: + TenantSplitDonorState: + description: "The state of a tenant split operation." + type: string + values: + kUninitialized: "uninitialized" + kDataSync: "data sync" + kBlocking: "blocking" + kCommitted: "committed" + kAborted: "aborted" + +structs: + TenantSplitDonorDocument: + description: "The state document for an in-progress tenant split operation." + strict: true + fields: + _id: + type: uuid + description: "Unique identifier for the tenant split operation." + cpp_name: id + recipientConnectionString: + type: string + description: "The connection string for the recipient slice." + validator: + callback: "tenant_migration_util::validateConnectionString" + tenantId: + type: string + description: "The identifier for the tenant being migrated." + state: + type: TenantSplitDonorState + description: "The current state of the tenant split operation." + default: kUninitialized -- cgit v1.2.1