diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2018-03-12 11:14:15 -0400 |
---|---|---|
committer | Henrik Edin <henrik.edin@mongodb.com> | 2018-03-26 15:54:16 -0400 |
commit | af600c3876a26f62d8dde93bf769fc4ca3054072 (patch) | |
tree | ecef32a9b3c6c54501651168cce48093e76e9858 /src/mongo | |
parent | 2676a176759359c8614c0e37b267198259b6789f (diff) | |
download | mongo-af600c3876a26f62d8dde93bf769fc4ca3054072.tar.gz |
SERVER-30170 Embedded can now shutdown and re-initialize.
- ServiceContext* is now closer to be an instance context for the database. We still don't support multiple instances but I wrote the new code with this in mind. Teardown and reinitialize then becomes a matter of being able to delete and re-create the ServiceContext*.
- Use the new MONGO_INITIALIZER that supports deinit/reinit to be able to re-initialize global systems that are decorations on ServiceContext.
- Move creation/destruction of ServiceContext* out of MONGO_INITIALIZER. This so we can hold an exclusive lock during as much as possible of the shutdown (like how mongod does)
- New ServiceContext registrer where we can link in different implementations of ServiceContext (replaces the SetGlobalEnvironment MONGO_INITIALIZER)
- As a result the SetGlobalEnvironment prerequisite for MONGO_INITIALIZERs is gone.
- The ServiceContext is passed to runGlobalInitializers, put in InitializationContext/DeinitializationContext so the initializers know which context they operate on.
Diffstat (limited to 'src/mongo')
52 files changed, 472 insertions, 321 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index a2451a9cb54..c5d91a883b6 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -56,14 +56,12 @@ env.Library( 'base/data_type.cpp', 'base/data_type_string_data.cpp', 'base/data_type_terminated.cpp', - 'base/deinitializer_context.cpp', 'base/error_codes.cpp', 'base/error_extra_info.cpp', 'base/global_initializer.cpp', 'base/global_initializer_registerer.cpp', 'base/init.cpp', 'base/initializer.cpp', - 'base/initializer_context.cpp', 'base/initializer_dependency_graph.cpp', 'base/make_string_vector.cpp', 'base/parse_number.cpp', diff --git a/src/mongo/base/deinitializer_context.h b/src/mongo/base/deinitializer_context.h index 0e8edc32066..0db3d773c05 100644 --- a/src/mongo/base/deinitializer_context.h +++ b/src/mongo/base/deinitializer_context.h @@ -27,14 +27,14 @@ #pragma once +#include "mongo/base/disallow_copying.h" +#include "mongo/db/service_context_fwd.h" + #include <map> #include <string> #include <vector> -#include "mongo/base/disallow_copying.h" - namespace mongo { - /** * Context of a deinitialization process. Passed as a parameter to deinitialization functions. * @@ -42,10 +42,18 @@ namespace mongo { */ class DeinitializerContext { public: - DeinitializerContext() = default; + explicit DeinitializerContext(ServiceContext* serviceContext) + : _serviceContext(serviceContext) {} DeinitializerContext(DeinitializerContext const&) = delete; DeinitializerContext& operator=(DeinitializerContext const&) = delete; + + ServiceContext* serviceContext() const { + return _serviceContext; + } + +private: + ServiceContext* _serviceContext; }; } // namespace mongo diff --git a/src/mongo/base/init.h b/src/mongo/base/init.h index 5fc8aed2c86..1d6595592aa 100644 --- a/src/mongo/base/init.h +++ b/src/mongo/base/init.h @@ -40,6 +40,7 @@ #pragma once +#include "mongo/base/deinitializer_context.h" #include "mongo/base/global_initializer.h" #include "mongo/base/global_initializer_registerer.h" #include "mongo/base/initializer.h" diff --git a/src/mongo/base/initializer.cpp b/src/mongo/base/initializer.cpp index 9939057b070..34625b7cd65 100644 --- a/src/mongo/base/initializer.cpp +++ b/src/mongo/base/initializer.cpp @@ -39,13 +39,14 @@ Initializer::Initializer() {} Initializer::~Initializer() {} Status Initializer::executeInitializers(const InitializerContext::ArgumentVector& args, - const InitializerContext::EnvironmentMap& env) { + const InitializerContext::EnvironmentMap& env, + ServiceContext* serviceContext) { std::vector<std::string> sortedNodes; Status status = _graph.topSort(&sortedNodes); if (Status::OK() != status) return status; - InitializerContext context(args, env); + InitializerContext context(args, env, serviceContext); for (size_t i = 0; i < sortedNodes.size(); ++i) { InitializerDependencyNode* node = _graph.getInitializerNode(sortedNodes[i]); @@ -75,13 +76,13 @@ Status Initializer::executeInitializers(const InitializerContext::ArgumentVector return Status::OK(); } -Status Initializer::executeDeinitializers() { +Status Initializer::executeDeinitializers(ServiceContext* serviceContext) { std::vector<std::string> sortedNodes; Status status = _graph.topSort(&sortedNodes); if (Status::OK() != status) return status; - DeinitializerContext context; + DeinitializerContext context(serviceContext); // Execute deinitialization in reverse order from initialization. for (auto it = sortedNodes.rbegin(), end = sortedNodes.rend(); it != end; ++it) { @@ -104,11 +105,15 @@ Status Initializer::executeDeinitializers() { } Status runGlobalInitializers(const InitializerContext::ArgumentVector& args, - const InitializerContext::EnvironmentMap& env) { - return getGlobalInitializer().executeInitializers(args, env); + const InitializerContext::EnvironmentMap& env, + ServiceContext* serviceContext) { + return getGlobalInitializer().executeInitializers(args, env, serviceContext); } -Status runGlobalInitializers(int argc, const char* const* argv, const char* const* envp) { +Status runGlobalInitializers(int argc, + const char* const* argv, + const char* const* envp, + ServiceContext* serviceContext) { InitializerContext::ArgumentVector args(argc); std::copy(argv, argv + argc, args.begin()); @@ -124,15 +129,18 @@ Status runGlobalInitializers(int argc, const char* const* argv, const char* cons } } - return runGlobalInitializers(args, env); + return runGlobalInitializers(args, env, serviceContext); } -Status runGlobalDeinitializers() { - return getGlobalInitializer().executeDeinitializers(); +Status runGlobalDeinitializers(ServiceContext* serviceContext) { + return getGlobalInitializer().executeDeinitializers(serviceContext); } -void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* const* envp) { - Status status = runGlobalInitializers(argc, argv, envp); +void runGlobalInitializersOrDie(int argc, + const char* const* argv, + const char* const* envp, + ServiceContext* serviceContext) { + Status status = runGlobalInitializers(argc, argv, envp, serviceContext); if (!status.isOK()) { std::cerr << "Failed global initialization: " << status << std::endl; quickExit(1); diff --git a/src/mongo/base/initializer.h b/src/mongo/base/initializer.h index 904356fdbef..924569ab138 100644 --- a/src/mongo/base/initializer.h +++ b/src/mongo/base/initializer.h @@ -66,9 +66,10 @@ public: * and the thing being initialized should be considered dead in the water. */ Status executeInitializers(const InitializerContext::ArgumentVector& args, - const InitializerContext::EnvironmentMap& env); + const InitializerContext::EnvironmentMap& env, + ServiceContext* serviceContext); - Status executeDeinitializers(); + Status executeDeinitializers(ServiceContext* serviceContext); private: InitializerDependencyGraph _graph; @@ -84,15 +85,22 @@ private: * should probably arrange to terminate the process themselves. */ Status runGlobalInitializers(const InitializerContext::ArgumentVector& args, - const InitializerContext::EnvironmentMap& env); + const InitializerContext::EnvironmentMap& env, + ServiceContext* serviceContext); -Status runGlobalInitializers(int argc, const char* const* argv, const char* const* envp); +Status runGlobalInitializers(int argc, + const char* const* argv, + const char* const* envp, + ServiceContext* serviceContext); /** * Same as runGlobalInitializers(), except prints a brief message to std::cerr * and terminates the process on failure. */ -void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* const* envp); +void runGlobalInitializersOrDie(int argc, + const char* const* argv, + const char* const* envp, + ServiceContext* serviceContext); /** * Run the global deinitializers. They will execute in reverse order from initialization. @@ -103,6 +111,6 @@ void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* c * This means that the few initializers that might want to terminate the program by failing * should probably arrange to terminate the process themselves. */ -Status runGlobalDeinitializers(); +Status runGlobalDeinitializers(ServiceContext* serviceContext); } // namespace mongo diff --git a/src/mongo/base/initializer_context.cpp b/src/mongo/base/initializer_context.cpp deleted file mode 100644 index 40299c134ba..00000000000 --- a/src/mongo/base/initializer_context.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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 - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * 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 GNU Affero General 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/base/initializer_context.h" - -namespace mongo { - -InitializerContext::InitializerContext(const ArgumentVector& args, const EnvironmentMap& env) - : _args(args), _env(env) {} - -} // namespace mongo diff --git a/src/mongo/base/initializer_context.h b/src/mongo/base/initializer_context.h index 4414439065d..b1a9ab329e9 100644 --- a/src/mongo/base/initializer_context.h +++ b/src/mongo/base/initializer_context.h @@ -27,14 +27,14 @@ #pragma once +#include "mongo/base/disallow_copying.h" +#include "mongo/db/service_context_fwd.h" + #include <map> #include <string> #include <vector> -#include "mongo/base/disallow_copying.h" - namespace mongo { - /** * Context of an initialization process. Passed as a parameter to initialization functions. * @@ -47,7 +47,10 @@ public: typedef std::vector<std::string> ArgumentVector; typedef std::map<std::string, std::string> EnvironmentMap; - InitializerContext(const ArgumentVector& args, const EnvironmentMap& env); + InitializerContext(const ArgumentVector& args, + const EnvironmentMap& env, + ServiceContext* serviceContext) + : _args(args), _env(env), _serviceContext(serviceContext) {} const ArgumentVector& args() const { return _args; @@ -56,9 +59,14 @@ public: return _env; } + ServiceContext* serviceContext() const { + return _serviceContext; + } + private: ArgumentVector _args; EnvironmentMap _env; + ServiceContext* _serviceContext; }; } // namespace mongo diff --git a/src/mongo/base/initializer_test.cpp b/src/mongo/base/initializer_test.cpp index 9be5f0eb6f5..31b87f5771d 100644 --- a/src/mongo/base/initializer_test.cpp +++ b/src/mongo/base/initializer_test.cpp @@ -160,8 +160,8 @@ TEST(InitializerTest, SuccessfulInitialization) { set7, set8); clearCounts(); - ASSERT_OK(initializer.executeInitializers(InitializerContext::ArgumentVector(), - InitializerContext::EnvironmentMap())); + ASSERT_OK(initializer.executeInitializers( + InitializerContext::ArgumentVector(), InitializerContext::EnvironmentMap(), nullptr)); for (int i = 0; i < 9; ++i) ASSERT_EQUALS(1, globalCounts[i]); } @@ -181,7 +181,8 @@ TEST(InitializerTest, Step5Misimplemented) { clearCounts(); ASSERT_EQUALS(ErrorCodes::UnknownError, initializer.executeInitializers(InitializerContext::ArgumentVector(), - InitializerContext::EnvironmentMap())); + InitializerContext::EnvironmentMap(), + nullptr)); ASSERT_EQUALS(1, globalCounts[0]); ASSERT_EQUALS(1, globalCounts[1]); ASSERT_EQUALS(1, globalCounts[2]); diff --git a/src/mongo/client/embedded/embedded.cpp b/src/mongo/client/embedded/embedded.cpp index 9e1c71ec791..fdcf98975b9 100644 --- a/src/mongo/client/embedded/embedded.cpp +++ b/src/mongo/client/embedded/embedded.cpp @@ -38,6 +38,7 @@ #include "mongo/client/embedded/service_context_embedded.h" #include "mongo/client/embedded/service_entry_point_embedded.h" #include "mongo/config.h" +#include "mongo/db/catalog/database_holder.h" #include "mongo/db/catalog/health_log.h" #include "mongo/db/catalog/uuid_catalog.h" #include "mongo/db/client.h" @@ -53,6 +54,7 @@ #include "mongo/db/op_observer_registry.h" #include "mongo/db/repair_database_and_check_version.h" #include "mongo/db/repl/storage_interface_impl.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/session_catalog.h" #include "mongo/db/session_killer.h" #include "mongo/db/startup_warnings_mongod.h" @@ -97,17 +99,26 @@ MONGO_INITIALIZER_GENERAL(ForkServer, ("EndStartupOptionHandling"), ("default")) // Create a minimalistic replication coordinator to provide a limited interface for users. Not // functional to provide any replication logic. -MONGO_INITIALIZER_WITH_PREREQUISITES(CreateReplicationManager, - ("SetGlobalEnvironment", "SSLManager", "default")) -(InitializerContext* context) { - auto serviceContext = getGlobalServiceContext(); - repl::StorageInterface::set(serviceContext, stdx::make_unique<repl::StorageInterfaceImpl>()); - - auto replCoord = stdx::make_unique<ReplicationCoordinatorEmbedded>(serviceContext); - repl::ReplicationCoordinator::set(serviceContext, std::move(replCoord)); - repl::setOplogCollectionName(serviceContext); - return Status::OK(); -} +GlobalInitializerRegisterer replicationManagerInitializer( + "CreateReplicationManager", + {"SSLManager", "default"}, + [](InitializerContext* context) { + auto serviceContext = context->serviceContext(); + repl::StorageInterface::set(serviceContext, std::make_unique<repl::StorageInterfaceImpl>()); + + auto replCoord = std::make_unique<ReplicationCoordinatorEmbedded>(serviceContext); + repl::ReplicationCoordinator::set(serviceContext, std::move(replCoord)); + repl::setOplogCollectionName(serviceContext); + return Status::OK(); + }, + [](DeinitializerContext* context) { + auto serviceContext = context->serviceContext(); + + repl::ReplicationCoordinator::set(serviceContext, nullptr); + repl::StorageInterface::set(serviceContext, nullptr); + + return Status::OK(); + }); MONGO_INITIALIZER(fsyncLockedForWriting)(InitializerContext* context) { setLockedForWritingImpl([]() { return false; }); @@ -118,56 +129,52 @@ MONGO_INITIALIZER(fsyncLockedForWriting)(InitializerContext* context) { using logger::LogComponent; using std::endl; -void shutdown() { - Client::initThreadIfNotAlready(); +void shutdown(ServiceContext* srvContext) { + Client::initThreadIfNotAlready(); auto const client = Client::getCurrent(); auto const serviceContext = client->getServiceContext(); + invariant(srvContext == serviceContext); serviceContext->setKillAllOperations(); - // Shut down the background periodic task runner - if (auto runner = serviceContext->getPeriodicRunner()) { - runner->shutdown(); - } - // We should always be able to acquire the global lock at shutdown. - // - // TODO: This call chain uses the locker directly, because we do not want to start an - // operation context, which also instantiates a recovery unit. Also, using the - // lockGlobalBegin/lockGlobalComplete sequence, we avoid taking the flush lock. - // - // For a Windows service, dbexit does not call exit(), so we must leak the lock outside - // of this function to prevent any operations from running that need a lock. - // - DefaultLockerImpl* globalLocker = new DefaultLockerImpl(); - LockResult result = globalLocker->lockGlobalBegin(MODE_X, Date_t::max()); - if (result == LOCK_WAITING) { - result = globalLocker->lockGlobalComplete(Date_t::max()); - } + // Close all open databases, shutdown storage engine and run all deinitializers. + auto shutdownOpCtx = serviceContext->makeOperationContext(client); + { + Lock::GlobalLock lk(shutdownOpCtx.get(), MODE_X, Date_t::max()); + dbHolder().closeAll(shutdownOpCtx.get(), "shutdown"); - invariant(LOCK_OK == result); + // Shut down the background periodic task runner + if (auto runner = serviceContext->getPeriodicRunner()) { + runner->shutdown(); + } - // Global storage engine may not be started in all cases before we exit - if (serviceContext->getGlobalStorageEngine()) { - serviceContext->shutdownGlobalStorageEngineCleanly(); + // Global storage engine may not be started in all cases before we exit + if (serviceContext->getGlobalStorageEngine()) { + serviceContext->shutdownGlobalStorageEngineCleanly(); + } + + Status status = mongo::runGlobalDeinitializers(serviceContext); + uassertStatusOKWithContext(status, "Global deinitilization failed"); } + shutdownOpCtx.reset(); + + if (Client::getCurrent()) + Client::destroy(); + + setGlobalServiceContext(nullptr); log(LogComponent::kControl) << "now exiting"; } -int initialize(int argc, char* argv[], char** envp) { - registerShutdownTask(shutdown); - +ServiceContext* initialize(int argc, char* argv[], char** envp) { srand(static_cast<unsigned>(curTimeMicros64())); - // - Status status = mongo::runGlobalInitializers(argc, argv, envp); - if (!status.isOK()) { - severe(LogComponent::kControl) << "Failed global initializations: " << status; - return EXIT_FAILURE; - } + setGlobalServiceContext(createServiceContext()); + Status status = mongo::runGlobalInitializers(argc, argv, envp, getGlobalServiceContext()); + uassertStatusOKWithContext(status, "Global initilization failed"); Client::initThread("initandlisten"); @@ -175,9 +182,9 @@ int initialize(int argc, char* argv[], char** envp) { auto serviceContext = checked_cast<ServiceContextMongoEmbedded*>(getGlobalServiceContext()); - auto opObserverRegistry = stdx::make_unique<OpObserverRegistry>(); - opObserverRegistry->addObserver(stdx::make_unique<OpObserverImpl>()); - opObserverRegistry->addObserver(stdx::make_unique<UUIDCatalogObserver>()); + auto opObserverRegistry = std::make_unique<OpObserverRegistry>(); + opObserverRegistry->addObserver(std::make_unique<OpObserverImpl>()); + opObserverRegistry->addObserver(std::make_unique<UUIDCatalogObserver>()); serviceContext->setOpObserver(std::move(opObserverRegistry)); DBDirectClientFactory::get(serviceContext).registerImplementation([](OperationContext* opCtx) { @@ -201,16 +208,10 @@ int initialize(int argc, char* argv[], char** envp) { serviceContext->createLockFile(); serviceContext->setServiceEntryPoint( - stdx::make_unique<ServiceEntryPointEmbedded>(serviceContext)); + std::make_unique<ServiceEntryPointEmbedded>(serviceContext)); serviceContext->initializeGlobalStorageEngine(); -#ifdef MONGO_CONFIG_WIREDTIGER_ENABLED - if (EncryptionHooks::get(serviceContext)->restartRequired()) { - quickExit(EXIT_CLEAN); - } -#endif - // Warn if we detect configurations for multiple registered storage engines in the same // configuration file/environment. if (serverGlobalParams.parsedOpts.hasField("storage")) { @@ -313,7 +314,7 @@ int initialize(int argc, char* argv[], char** envp) { serviceContext->notifyStartupComplete(); - return 0; + return serviceContext; } } // namespace embedded } // namespace mongo diff --git a/src/mongo/client/embedded/embedded.h b/src/mongo/client/embedded/embedded.h index b3e91953e04..714c6c1c90a 100644 --- a/src/mongo/client/embedded/embedded.h +++ b/src/mongo/client/embedded/embedded.h @@ -31,8 +31,10 @@ #include "mongo/platform/basic.h" namespace mongo { +class ServiceContext; + namespace embedded { -int initialize(int argc, char* argv[], char** envp); -void shutdown(); +ServiceContext* initialize(int argc, char* argv[], char** envp); +void shutdown(ServiceContext* serviceContext); } // namespace embedded } // namespace mongo diff --git a/src/mongo/client/embedded/libmongodbcapi.cpp b/src/mongo/client/embedded/libmongodbcapi.cpp index a58b36c5f01..3309a06f544 100644 --- a/src/mongo/client/embedded/libmongodbcapi.cpp +++ b/src/mongo/client/embedded/libmongodbcapi.cpp @@ -82,7 +82,6 @@ namespace { bool libraryInitialized_ = false; libmongodbcapi_db* global_db = nullptr; thread_local int last_error = LIBMONGODB_CAPI_SUCCESS; -bool run_setup = false; libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexcept try { last_error = LIBMONGODB_CAPI_SUCCESS; @@ -93,40 +92,33 @@ libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexce } global_db = new libmongodbcapi_db; - if (!run_setup) { - // iterate over argv and copy them to argvStorage - for (int i = 0; i < argc; i++) { - // allocate space for the null terminator - auto s = mongo::stdx::make_unique<char[]>(std::strlen(argv[i]) + 1); - // copy the string + null terminator - std::strncpy(s.get(), argv[i], std::strlen(argv[i]) + 1); - global_db->argvPointers.push_back(s.get()); - global_db->argvStorage.push_back(std::move(s)); - } - global_db->argvPointers.push_back(nullptr); - - // iterate over envp and copy them to envpStorage - while (envp != nullptr && *envp != nullptr) { - auto s = mongo::stdx::make_unique<char[]>(std::strlen(*envp) + 1); - std::strncpy(s.get(), *envp, std::strlen(*envp) + 1); - global_db->envpPointers.push_back(s.get()); - global_db->envpStorage.push_back(std::move(s)); - envp++; - } - global_db->envpPointers.push_back(nullptr); + // iterate over argv and copy them to argvStorage + for (int i = 0; i < argc; i++) { + // allocate space for the null terminator + auto s = mongo::stdx::make_unique<char[]>(std::strlen(argv[i]) + 1); + // copy the string + null terminator + std::strncpy(s.get(), argv[i], std::strlen(argv[i]) + 1); + global_db->argvPointers.push_back(s.get()); + global_db->argvStorage.push_back(std::move(s)); + } + global_db->argvPointers.push_back(nullptr); + + // iterate over envp and copy them to envpStorage + while (envp != nullptr && *envp != nullptr) { + auto s = mongo::stdx::make_unique<char[]>(std::strlen(*envp) + 1); + std::strncpy(s.get(), *envp, std::strlen(*envp) + 1); + global_db->envpPointers.push_back(s.get()); + global_db->envpStorage.push_back(std::move(s)); + envp++; + } + global_db->envpPointers.push_back(nullptr); + global_db->serviceContext = embedded::initialize(argc, global_db->argvPointers.data(), global_db->envpPointers.data()); - - // wait until the global service context is not null - global_db->serviceContext = waitAndGetGlobalServiceContext(); - - // block until the global service context is initialized - global_db->serviceContext->waitForStartupComplete(); - - run_setup = true; - } else { - // wait until the global service context is not null - global_db->serviceContext = waitAndGetGlobalServiceContext(); + if (!global_db->serviceContext) { + delete global_db; + global_db = nullptr; + throw std::runtime_error("Initialization failed"); } // creating mock transport layer to be able to create sessions @@ -138,12 +130,13 @@ libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexce return nullptr; } -void db_destroy(libmongodbcapi_db* db) noexcept { - // todo, we can't teardown and re-initialize yet. - /*if (run_setup) { - embedded::shutdown(); - run_setup = false; - }*/ +int db_destroy(libmongodbcapi_db* db) noexcept { + if (!db->open_clients.empty()) { + last_error = LIBMONGODB_CAPI_ERROR_UNKNOWN; + return last_error; + } + + embedded::shutdown(global_db->serviceContext); delete db; invariant(!db || db == global_db); @@ -151,6 +144,7 @@ void db_destroy(libmongodbcapi_db* db) noexcept { global_db = nullptr; } last_error = LIBMONGODB_CAPI_SUCCESS; + return last_error; } int db_pump(libmongodbcapi_db* db) noexcept try { @@ -239,7 +233,7 @@ libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char return mongo::db_new(argc, argv, envp); } -void libmongodbcapi_db_destroy(libmongodbcapi_db* db) { +int libmongodbcapi_db_destroy(libmongodbcapi_db* db) { return mongo::db_destroy(db); } diff --git a/src/mongo/client/embedded/libmongodbcapi.h b/src/mongo/client/embedded/libmongodbcapi.h index a3763978e12..8c1646dd9b6 100644 --- a/src/mongo/client/embedded/libmongodbcapi.h +++ b/src/mongo/client/embedded/libmongodbcapi.h @@ -95,8 +95,10 @@ libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char * * @param * A pointer to a db handle to be destroyed +* +* @return A libmongo error code */ -void libmongodbcapi_db_destroy(libmongodbcapi_db* db); +int libmongodbcapi_db_destroy(libmongodbcapi_db* db); /** * Let the database do background work. Returns an int from the error enum diff --git a/src/mongo/client/embedded/libmongodbcapi_test.cpp b/src/mongo/client/embedded/libmongodbcapi_test.cpp index f1087e4f849..967b59b1acd 100644 --- a/src/mongo/client/embedded/libmongodbcapi_test.cpp +++ b/src/mongo/client/embedded/libmongodbcapi_test.cpp @@ -138,10 +138,10 @@ TEST_F(MongodbCAPITest, CreateAndDestroyDBAndClient) { auto client = createClient(); } -// This test is to make sure that destroying the db will destroy all of its clients -// This test will only fail under ASAN +// This test is to make sure that destroying the db will fail if there's remaining clients left. TEST_F(MongodbCAPITest, DoNotDestroyClient) { - createClient().release(); + auto client = createClient(); + ASSERT(libmongodbcapi_db_destroy(getDB()) != LIBMONGODB_CAPI_SUCCESS); } TEST_F(MongodbCAPITest, CreateMultipleClients) { @@ -415,7 +415,7 @@ int main(int argc, char** argv, char** envp) { return EXIT_FAILURE; } - auto result = ::mongo::unittest::Suite::run(std::vector<std::string>(), "", 1); + ::mongo::unittest::Suite::run(std::vector<std::string>(), "", 1); int fini = libmongodbcapi_fini(); if (fini != LIBMONGODB_CAPI_SUCCESS) { @@ -424,5 +424,4 @@ int main(int argc, char** argv, char** envp) { } globalTempDir.reset(); - mongo::quickExit(result); } diff --git a/src/mongo/client/embedded/service_context_embedded.cpp b/src/mongo/client/embedded/service_context_embedded.cpp index 597792a7846..6558ea3b897 100644 --- a/src/mongo/client/embedded/service_context_embedded.cpp +++ b/src/mongo/client/embedded/service_context_embedded.cpp @@ -37,6 +37,7 @@ #include "mongo/db/client.h" #include "mongo/db/concurrency/lock_state.h" #include "mongo/db/operation_context.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/storage/storage_engine_lock_file.h" #include "mongo/db/storage/storage_engine_metadata.h" @@ -51,19 +52,14 @@ namespace mongo { namespace { -auto makeMongoEmbeddedServiceContext() { - auto service = stdx::make_unique<ServiceContextMongoEmbedded>(); - service->setServiceEntryPoint(stdx::make_unique<ServiceEntryPointEmbedded>(service.get())); - service->setTickSource(stdx::make_unique<SystemTickSource>()); - service->setFastClockSource(stdx::make_unique<SystemClockSource>()); - service->setPreciseClockSource(stdx::make_unique<SystemClockSource>()); +ServiceContextRegistrar serviceContextCreator([]() { + auto service = std::make_unique<ServiceContextMongoEmbedded>(); + service->setServiceEntryPoint(std::make_unique<ServiceEntryPointEmbedded>(service.get())); + service->setTickSource(std::make_unique<SystemTickSource>()); + service->setFastClockSource(std::make_unique<SystemClockSource>()); + service->setPreciseClockSource(std::make_unique<SystemClockSource>()); return service; -} - -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(makeMongoEmbeddedServiceContext()); - return Status::OK(); -} +}); } // namespace extern bool _supportsDocLocking; @@ -76,7 +72,7 @@ StorageEngine* ServiceContextMongoEmbedded::getGlobalStorageEngine() { // We don't check that globalStorageEngine is not-NULL here intentionally. We can encounter // an error before it's initialized and proceed to exitCleanly which is equipped to deal // with a NULL storage engine. - return _storageEngine; + return _storageEngine.get(); } void ServiceContextMongoEmbedded::createLockFile() { @@ -134,10 +130,10 @@ void ServiceContextMongoEmbedded::initializeGlobalStorageEngine() { if (storageGlobalParams.engineSetByUser) { // Verify that the name of the user-supplied storage engine matches the contents of // the metadata file. - const StorageEngine::Factory* factory = - mapFindWithDefault(_storageFactories, - storageGlobalParams.engine, - static_cast<const StorageEngine::Factory*>(nullptr)); + const StorageEngine::Factory* factory = nullptr; + auto it = _storageFactories.find(storageGlobalParams.engine); + if (it != _storageFactories.end()) + factory = it->second.get(); if (factory) { uassert(50667, @@ -185,7 +181,7 @@ void ServiceContextMongoEmbedded::initializeGlobalStorageEngine() { << " is only supported by the mmapv1 storage engine", repairpath.empty() || repairpath == dbpath || storageGlobalParams.engine == "mmapv1"); - const StorageEngine::Factory* factory = _storageFactories[storageGlobalParams.engine]; + const auto& factory = _storageFactories[storageGlobalParams.engine]; uassert(50681, str::stream() << "Cannot start server with an unknown storage engine: " @@ -221,7 +217,7 @@ void ServiceContextMongoEmbedded::initializeGlobalStorageEngine() { } }); - _storageEngine = factory->create(storageGlobalParams, _lockFile.get()); + _storageEngine.reset(factory->create(storageGlobalParams, _lockFile.get())); _storageEngine->finishInit(); if (_lockFile) { @@ -261,7 +257,7 @@ void ServiceContextMongoEmbedded::registerStorageEngine(const std::string& name, // and all factories should be added before we pick a storage engine. invariant(NULL == _storageEngine); - _storageFactories[name] = factory; + _storageFactories[name].reset(factory); } bool ServiceContextMongoEmbedded::isRegisteredStorageEngine(const std::string& name) { @@ -282,7 +278,7 @@ bool StorageFactoriesIteratorMongoEmbedded::more() const { } const StorageEngine::Factory* StorageFactoriesIteratorMongoEmbedded::next() { - return _curr++->second; + return _curr++->second.get(); } std::unique_ptr<OperationContext> ServiceContextMongoEmbedded::_newOpCtx(Client* client, diff --git a/src/mongo/client/embedded/service_context_embedded.h b/src/mongo/client/embedded/service_context_embedded.h index 661c96d4677..5954060cd0e 100644 --- a/src/mongo/client/embedded/service_context_embedded.h +++ b/src/mongo/client/embedded/service_context_embedded.h @@ -39,7 +39,7 @@ class StorageEngineLockFile; class ServiceContextMongoEmbedded final : public ServiceContext { public: - using FactoryMap = std::map<std::string, const StorageEngine::Factory*>; + using FactoryMap = std::map<std::string, std::unique_ptr<const StorageEngine::Factory>>; ServiceContextMongoEmbedded(); @@ -65,8 +65,7 @@ private: std::unique_ptr<StorageEngineLockFile> _lockFile; - // logically owned here, but never deleted by anyone. - StorageEngine* _storageEngine = nullptr; + std::unique_ptr<StorageEngine> _storageEngine; // All possible storage engines are registered here through MONGO_INIT. FactoryMap _storageFactories; diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 99287b19945..1cc6e1ba889 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -470,6 +470,7 @@ env.Library( 'operation_context_group.cpp', 'service_context.cpp', 'service_context_noop.cpp', + 'service_context_registrar.cpp', 'unclean_shutdown.cpp', ], LIBDEPS=[ diff --git a/src/mongo/db/auth/auth_decorations.cpp b/src/mongo/db/auth/auth_decorations.cpp index bf1b31ca148..b0c1e79f4a9 100644 --- a/src/mongo/db/auth/auth_decorations.cpp +++ b/src/mongo/db/auth/auth_decorations.cpp @@ -86,10 +86,7 @@ AuthorizationManager* AuthorizationManager::get(ServiceContext& service) { void AuthorizationManager::set(ServiceContext* service, std::unique_ptr<AuthorizationManager> authzManager) { - auto& manager = getAuthorizationManager(service); - invariant(authzManager); - invariant(!manager); - manager = std::move(authzManager); + getAuthorizationManager(service) = std::move(authzManager); service->registerClientObserver(stdx::make_unique<AuthzClientObserver>()); } diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp index 3172d7e1626..39505fab014 100644 --- a/src/mongo/db/auth/authorization_manager_global.cpp +++ b/src/mongo/db/auth/authorization_manager_global.cpp @@ -90,20 +90,24 @@ AuthorizationManager* getGlobalAuthorizationManager() { MONGO_EXPORT_STARTUP_SERVER_PARAMETER(startupAuthSchemaValidation, bool, true); -MONGO_INITIALIZER_WITH_PREREQUISITES(CreateAuthorizationManager, - ("SetupInternalSecurityUser", - "OIDGeneration", - "SetGlobalEnvironment", - "CreateAuthorizationExternalStateFactory", - "EndStartupOptionStorage")) -(InitializerContext* context) { - auto authzManager = - stdx::make_unique<AuthorizationManager>(AuthzManagerExternalState::create()); - authzManager->setAuthEnabled(serverGlobalParams.authState == - ServerGlobalParams::AuthState::kEnabled); - authzManager->setShouldValidateAuthSchemaOnStartup(startupAuthSchemaValidation); - AuthorizationManager::set(getGlobalServiceContext(), std::move(authzManager)); - return Status::OK(); -} +GlobalInitializerRegisterer authorizationManagerInitializer( + "CreateAuthorizationManager", + {"SetupInternalSecurityUser", + "OIDGeneration", + "CreateAuthorizationExternalStateFactory", + "EndStartupOptionStorage"}, + [](InitializerContext* context) { + auto authzManager = + stdx::make_unique<AuthorizationManager>(AuthzManagerExternalState::create()); + authzManager->setAuthEnabled(serverGlobalParams.authState == + ServerGlobalParams::AuthState::kEnabled); + authzManager->setShouldValidateAuthSchemaOnStartup(startupAuthSchemaValidation); + AuthorizationManager::set(context->serviceContext(), std::move(authzManager)); + return Status::OK(); + }, + [](DeinitializerContext* context) { + AuthorizationManager::set(context->serviceContext(), nullptr); + return Status::OK(); + }); } // namespace mongo diff --git a/src/mongo/db/auth/sasl_mechanism_registry.cpp b/src/mongo/db/auth/sasl_mechanism_registry.cpp index b46ba9978f3..1572acb2794 100644 --- a/src/mongo/db/auth/sasl_mechanism_registry.cpp +++ b/src/mongo/db/auth/sasl_mechanism_registry.cpp @@ -164,16 +164,22 @@ bool SASLServerMechanismRegistry::_mechanismSupportedByConfig(StringData mechNam return sequenceContains(saslGlobalParams.authenticationMechanisms, mechName); } -MONGO_INITIALIZER_WITH_PREREQUISITES(CreateSASLServerMechanismRegistry, ("SetGlobalEnvironment")) -(::mongo::InitializerContext* context) { - if (saslGlobalParams.hostName.empty()) - saslGlobalParams.hostName = getHostNameCached(); - if (saslGlobalParams.serviceName.empty()) - saslGlobalParams.serviceName = "mongodb"; - - auto registry = stdx::make_unique<SASLServerMechanismRegistry>(); - SASLServerMechanismRegistry::set(getGlobalServiceContext(), std::move(registry)); - return Status::OK(); -} +GlobalInitializerRegisterer SASLServerMechanismRegistryInitializer( + "CreateSASLServerMechanismRegistry", + [](InitializerContext* context) { + if (saslGlobalParams.hostName.empty()) + saslGlobalParams.hostName = getHostNameCached(); + if (saslGlobalParams.serviceName.empty()) + saslGlobalParams.serviceName = "mongodb"; + + auto registry = stdx::make_unique<SASLServerMechanismRegistry>(); + SASLServerMechanismRegistry::set(context->serviceContext(), std::move(registry)); + return Status::OK(); + }, + [](DeinitializerContext* context) { + SASLServerMechanismRegistry::set(context->serviceContext(), nullptr); + + return Status::OK(); + }); } // namespace mongo diff --git a/src/mongo/db/catalog/database_holder_impl.cpp b/src/mongo/db/catalog/database_holder_impl.cpp index 1c999013e33..d5b5560df67 100644 --- a/src/mongo/db/catalog/database_holder_impl.cpp +++ b/src/mongo/db/catalog/database_holder_impl.cpp @@ -51,16 +51,24 @@ namespace mongo { namespace { +DatabaseHolder* _dbHolder = nullptr; + DatabaseHolder& dbHolderImpl() { - static DatabaseHolder _dbHolder; - return _dbHolder; + return *_dbHolder; } -MONGO_INITIALIZER_WITH_PREREQUISITES(InitializeDbHolderimpl, ("InitializeDatabaseHolderFactory")) -(InitializerContext* const) { - registerDbHolderImpl(dbHolderImpl); - return Status::OK(); -} +GlobalInitializerRegisterer dbHolderImplInitializer("InitializeDbHolderimpl", + {"InitializeDatabaseHolderFactory"}, + [](InitializerContext* const) { + _dbHolder = new DatabaseHolder(); + registerDbHolderImpl(dbHolderImpl); + return Status::OK(); + }, + [](DeinitializerContext* const) { + delete _dbHolder; + _dbHolder = nullptr; + return Status::OK(); + }); MONGO_INITIALIZER(InitializeDatabaseHolderFactory)(InitializerContext* const) { DatabaseHolder::registerFactory([] { return stdx::make_unique<DatabaseHolderImpl>(); }); diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index cacb7f941a3..beb87a5d086 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -118,6 +118,7 @@ #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_d.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/service_entry_point_mongod.h" #include "mongo/db/session_catalog.h" #include "mongo/db/session_killer.h" @@ -757,8 +758,7 @@ auto makeReplicationExecutor(ServiceContext* serviceContext) { "NetworkInterfaceASIO-Replication", nullptr, std::move(hookList))); } -MONGO_INITIALIZER_WITH_PREREQUISITES(CreateReplicationManager, - ("SetGlobalEnvironment", "SSLManager", "default")) +MONGO_INITIALIZER_WITH_PREREQUISITES(CreateReplicationManager, ("SSLManager", "default")) (InitializerContext* context) { auto serviceContext = getGlobalServiceContext(); repl::StorageInterface::set(serviceContext, stdx::make_unique<repl::StorageInterfaceImpl>()); @@ -958,7 +958,8 @@ int mongoDbMain(int argc, char* argv[], char** envp) { srand(static_cast<unsigned>(curTimeMicros64())); - Status status = mongo::runGlobalInitializers(argc, argv, envp); + setGlobalServiceContext(createServiceContext()); + Status status = mongo::runGlobalInitializers(argc, argv, envp, getGlobalServiceContext()); if (!status.isOK()) { severe(LogComponent::kControl) << "Failed global initialization: " << status; quickExit(EXIT_FAILURE); diff --git a/src/mongo/db/pipeline/document_source_sample_test.cpp b/src/mongo/db/pipeline/document_source_sample_test.cpp index c1c85924c50..439e0ce3e36 100644 --- a/src/mongo/db/pipeline/document_source_sample_test.cpp +++ b/src/mongo/db/pipeline/document_source_sample_test.cpp @@ -40,7 +40,6 @@ #include "mongo/db/pipeline/document_source_sample_from_random_cursor.h" #include "mongo/db/pipeline/document_value_test_util.h" #include "mongo/db/pipeline/expression_context.h" -#include "mongo/db/service_context.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" diff --git a/src/mongo/db/query/collation/collator_factory_icu_decoration.cpp b/src/mongo/db/query/collation/collator_factory_icu_decoration.cpp index 46ddbf54d8b..e37ce036511 100644 --- a/src/mongo/db/query/collation/collator_factory_icu_decoration.cpp +++ b/src/mongo/db/query/collation/collator_factory_icu_decoration.cpp @@ -37,7 +37,7 @@ namespace mongo { namespace { -MONGO_INITIALIZER_WITH_PREREQUISITES(CreateCollatorFactory, ("SetGlobalEnvironment", "LoadICUData")) +MONGO_INITIALIZER_WITH_PREREQUISITES(CreateCollatorFactory, ("LoadICUData")) (InitializerContext* context) { CollatorFactoryInterface::set(getGlobalServiceContext(), stdx::make_unique<CollatorFactoryICU>()); diff --git a/src/mongo/db/query/datetime/init_timezone_data.cpp b/src/mongo/db/query/datetime/init_timezone_data.cpp index b86159e3976..0c17cca0457 100644 --- a/src/mongo/db/query/datetime/init_timezone_data.cpp +++ b/src/mongo/db/query/datetime/init_timezone_data.cpp @@ -39,8 +39,8 @@ namespace mongo { -MONGO_INITIALIZER_WITH_PREREQUISITES( - LoadTimeZoneDB, ("GlobalLogManager", "SetGlobalEnvironment", "EndStartupOptionStorage")) +MONGO_INITIALIZER_WITH_PREREQUISITES(LoadTimeZoneDB, + ("GlobalLogManager", "EndStartupOptionStorage")) (InitializerContext* context) { auto serviceContext = getGlobalServiceContext(); if (!serverGlobalParams.timeZoneInfoPath.empty()) { diff --git a/src/mongo/db/repl/service_context_repl_mock_init.cpp b/src/mongo/db/repl/service_context_repl_mock_init.cpp index 720457b3469..c35b47f61d7 100644 --- a/src/mongo/db/repl/service_context_repl_mock_init.cpp +++ b/src/mongo/db/repl/service_context_repl_mock_init.cpp @@ -31,17 +31,18 @@ #include "mongo/base/init.h" #include "mongo/db/repl/service_context_repl_mock.h" #include "mongo/db/service_context.h" -#include "mongo/stdx/memory.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/util/clock_source_mock.h" +#include <memory> + namespace mongo { namespace repl { namespace { -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextReplMock>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextCreator([]() { + return std::make_unique<ServiceContextReplMock>(); +}); } // namespace } // namespace repl diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp index 48004bf0174..b3392b684bc 100644 --- a/src/mongo/db/service_context.cpp +++ b/src/mongo/db/service_context.cpp @@ -69,9 +69,13 @@ ServiceContext* waitAndGetGlobalServiceContext() { } void setGlobalServiceContext(std::unique_ptr<ServiceContext>&& serviceContext) { - fassert(17509, serviceContext.get()); - - delete globalServiceContext; + if (globalServiceContext) { + // Make sure that calling getGlobalServiceContext() during the destructor results in + // nullptr. Decorations might try and do this. + auto oldServiceContext = globalServiceContext; + globalServiceContext = nullptr; + delete oldServiceContext; + } stdx::lock_guard<stdx::mutex> lk(globalServiceContextMutex); diff --git a/src/mongo/db/service_context_d.cpp b/src/mongo/db/service_context_d.cpp index 3dad551125c..95459a6e41e 100644 --- a/src/mongo/db/service_context_d.cpp +++ b/src/mongo/db/service_context_d.cpp @@ -37,6 +37,7 @@ #include "mongo/db/client.h" #include "mongo/db/concurrency/lock_state.h" #include "mongo/db/operation_context.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/service_entry_point_mongod.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/storage/storage_engine_lock_file.h" @@ -53,19 +54,14 @@ namespace mongo { namespace { -auto makeMongoDServiceContext() { - auto service = stdx::make_unique<ServiceContextMongoD>(); - service->setServiceEntryPoint(stdx::make_unique<ServiceEntryPointMongod>(service.get())); - service->setTickSource(stdx::make_unique<SystemTickSource>()); - service->setFastClockSource(stdx::make_unique<SystemClockSource>()); - service->setPreciseClockSource(stdx::make_unique<SystemClockSource>()); +ServiceContextRegistrar serviceContextCreator([]() { + auto service = std::make_unique<ServiceContextMongoD>(); + service->setServiceEntryPoint(std::make_unique<ServiceEntryPointMongod>(service.get())); + service->setTickSource(std::make_unique<SystemTickSource>()); + service->setFastClockSource(std::make_unique<SystemClockSource>()); + service->setPreciseClockSource(std::make_unique<SystemClockSource>()); return service; -} - -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(makeMongoDServiceContext()); - return Status::OK(); -} +}); } // namespace extern bool _supportsDocLocking; diff --git a/src/mongo/base/deinitializer_context.cpp b/src/mongo/db/service_context_fwd.h index 1708587da36..48c36da674f 100644 --- a/src/mongo/base/deinitializer_context.cpp +++ b/src/mongo/db/service_context_fwd.h @@ -1,4 +1,5 @@ -/* Copyright 2018 MongoDB Inc. +/** + * Copyright (C) 2018 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, @@ -16,15 +17,19 @@ * 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 GNU Affero General 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. + * must comply with the GNU Affero General 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/base/deinitializer_context.h" +#pragma once -namespace mongo {} // namespace mongo +namespace mongo { + +class ServiceContext; + +} // namespace mongo diff --git a/src/mongo/db/service_context_noop_init.cpp b/src/mongo/db/service_context_noop_init.cpp index 8c66da1bd5a..27e4306ad49 100644 --- a/src/mongo/db/service_context_noop_init.cpp +++ b/src/mongo/db/service_context_noop_init.cpp @@ -31,16 +31,16 @@ #include "mongo/base/init.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/stdx/memory.h" namespace mongo { namespace { -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextEmbeddedFactory([]() { + return std::make_unique<ServiceContextNoop>(); +}); } // namespace } // namespace mongo diff --git a/src/mongo/db/service_context_registrar.cpp b/src/mongo/db/service_context_registrar.cpp new file mode 100644 index 00000000000..26aa48ac15b --- /dev/null +++ b/src/mongo/db/service_context_registrar.cpp @@ -0,0 +1,54 @@ +/** +* Copyright (C) 2018 MongoDB Inc. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, +* as published by the Free Software Foundation. +* +* 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 +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* 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 GNU Affero General 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/service_context_registrar.h" + +#include "mongo/db/service_context.h" + +namespace mongo { +namespace { +std::function<std::unique_ptr<ServiceContext>()>& getServiceContextFactory() { + static std::function<std::unique_ptr<ServiceContext>()> factory; + return factory; +} +} + +ServiceContextRegistrar::ServiceContextRegistrar( + std::function<std::unique_ptr<ServiceContext>()> fn) { + invariant(!hasServiceContextFactory()); + getServiceContextFactory() = std::move(fn); +} + +bool hasServiceContextFactory() { + return getServiceContextFactory() ? true : false; +} + +std::unique_ptr<ServiceContext> createServiceContext() { + return getServiceContextFactory()(); +} +} // namespace mongo diff --git a/src/mongo/db/service_context_registrar.h b/src/mongo/db/service_context_registrar.h new file mode 100644 index 00000000000..2317d8862f6 --- /dev/null +++ b/src/mongo/db/service_context_registrar.h @@ -0,0 +1,48 @@ +/** +* Copyright (C) 2018 MongoDB Inc. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, +* as published by the Free Software Foundation. +* +* 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 +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* 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 GNU Affero General 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 <functional> +#include <memory> + +namespace mongo { +class ServiceContext; + +// This is a initialization registration system similar to MONGO_INITIALIZER. But it cannot be an +// MONGO_INITIALIZER because we need to create the service context before the MONGO_INITIALIZERS +// execute. This class should probably be refactored to use the shim system from this ticket: +// https://jira.mongodb.org/browse/SERVER-32645 +class ServiceContextRegistrar { +public: + explicit ServiceContextRegistrar(std::function<std::unique_ptr<ServiceContext>()> fn); +}; + +bool hasServiceContextFactory(); +std::unique_ptr<ServiceContext> createServiceContext(); +} // namespace mongo diff --git a/src/mongo/db/sorter/sorter_test.cpp b/src/mongo/db/sorter/sorter_test.cpp index 6a85cbfaef2..3ba4e8a98c3 100644 --- a/src/mongo/db/sorter/sorter_test.cpp +++ b/src/mongo/db/sorter/sorter_test.cpp @@ -38,7 +38,7 @@ #include "mongo/config.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" -#include "mongo/stdx/memory.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/stdx/thread.h" #include "mongo/unittest/temp_dir.h" #include "mongo/unittest/unittest.h" @@ -47,6 +47,8 @@ // Need access to internal classes #include "mongo/db/sorter/sorter.cpp" +#include <memory> + namespace mongo { using namespace mongo::sorter; using std::make_shared; @@ -55,10 +57,9 @@ using std::pair; namespace { // Stub to avoid including the server environment library. -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextCreator([]() { + return std::make_unique<ServiceContextNoop>(); +}); } // namespace // diff --git a/src/mongo/db/storage/devnull/devnull_init.cpp b/src/mongo/db/storage/devnull/devnull_init.cpp index 7403a5d2fb9..dff10077427 100644 --- a/src/mongo/db/storage/devnull/devnull_init.cpp +++ b/src/mongo/db/storage/devnull/devnull_init.cpp @@ -1,5 +1,3 @@ -// devnull_init.cpp - /** * Copyright (C) 2014 MongoDB Inc. * @@ -66,7 +64,7 @@ public: }; } // namespace -MONGO_INITIALIZER_WITH_PREREQUISITES(DevNullEngineInit, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(DevNullEngineInit) (InitializerContext* context) { getGlobalServiceContext()->registerStorageEngine("devnull", new DevNullStorageEngineFactory()); return Status::OK(); diff --git a/src/mongo/db/storage/encryption_hooks.cpp b/src/mongo/db/storage/encryption_hooks.cpp index 9ee9a317dbe..8a81d20dd2d 100644 --- a/src/mongo/db/storage/encryption_hooks.cpp +++ b/src/mongo/db/storage/encryption_hooks.cpp @@ -41,7 +41,7 @@ namespace mongo { /* Make a EncryptionHooks pointer a decoration on the global ServiceContext */ -MONGO_INITIALIZER_WITH_PREREQUISITES(SetEncryptionHooks, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(SetEncryptionHooks) (InitializerContext* context) { auto encryptionHooks = stdx::make_unique<EncryptionHooks>(); EncryptionHooks::set(getGlobalServiceContext(), std::move(encryptionHooks)); diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_init.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_init.cpp index df936cfacb8..b52507c20df 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_init.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_init.cpp @@ -72,7 +72,7 @@ public: } // namespace -MONGO_INITIALIZER_WITH_PREREQUISITES(EphemeralForTestEngineInit, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(EphemeralForTestEngineInit) (InitializerContext* context) { getGlobalServiceContext()->registerStorageEngine("ephemeralForTest", new EphemeralForTestFactory()); diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_init.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_init.cpp index 10eb30243f4..08f586f2035 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_init.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_init.cpp @@ -76,7 +76,7 @@ public: } // namespace -MONGO_INITIALIZER_WITH_PREREQUISITES(MMAPV1EngineInit, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(MMAPV1EngineInit) (InitializerContext* context) { getGlobalServiceContext()->registerStorageEngine("mmapv1", new MMAPV1Factory()); return Status::OK(); diff --git a/src/mongo/db/storage/mobile/mobile_init.cpp b/src/mongo/db/storage/mobile/mobile_init.cpp index 08d078cd2fc..c9d895d0332 100644 --- a/src/mongo/db/storage/mobile/mobile_init.cpp +++ b/src/mongo/db/storage/mobile/mobile_init.cpp @@ -70,10 +70,12 @@ public: }; } // namespace -MONGO_INITIALIZER_WITH_PREREQUISITES(MobileKVEngineInit, ("SetGlobalEnvironment")) -(InitializerContext* context) { - getGlobalServiceContext()->registerStorageEngine("mobile", new MobileFactory()); - return Status::OK(); -} +GlobalInitializerRegisterer mobileKVEngineInitializer( + "MobileKVEngineInit", + [](InitializerContext* context) { + context->serviceContext()->registerStorageEngine("mobile", new MobileFactory()); + return Status::OK(); + }, + [](DeinitializerContext* const) { return Status::OK(); }); } // namespace mongo diff --git a/src/mongo/db/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h index 486360ba35d..fc2d9d99a08 100644 --- a/src/mongo/db/storage/storage_engine.h +++ b/src/mongo/db/storage/storage_engine.h @@ -139,6 +139,11 @@ public: }; /** + * The destructor should only be called if we are tearing down but not exiting the process. + */ + virtual ~StorageEngine() {} + + /** * Called after the globalStorageEngine pointer has been set up, before any other methods * are called. Any initialization work that requires the ability to create OperationContexts * should be done here rather than in the constructor. @@ -389,12 +394,6 @@ public: * implementation. */ virtual Timestamp getAllCommittedTimestamp(OperationContext* opCtx) const = 0; - -protected: - /** - * The destructor will never be called. See cleanShutdown instead. - */ - virtual ~StorageEngine() {} }; } // namespace mongo diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.cpp index e40d3a58edb..dfc59b26f3f 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.cpp @@ -39,7 +39,7 @@ namespace mongo { /* Make a WiredTigerCustomizationHooks pointer a decoration on the global ServiceContext */ -MONGO_INITIALIZER_WITH_PREREQUISITES(SetWiredTigerCustomizationHooks, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(SetWiredTigerCustomizationHooks) (InitializerContext* context) { auto customizationHooks = stdx::make_unique<WiredTigerCustomizationHooks>(); WiredTigerCustomizationHooks::set(getGlobalServiceContext(), std::move(customizationHooks)); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_extensions.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_extensions.cpp index f9bd90126e2..b0149c0b5aa 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_extensions.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_extensions.cpp @@ -38,7 +38,7 @@ namespace mongo { -MONGO_INITIALIZER_WITH_PREREQUISITES(SetWiredTigerExtensions, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(SetWiredTigerExtensions) (InitializerContext* context) { auto configHooks = stdx::make_unique<WiredTigerExtensions>(); WiredTigerExtensions::set(getGlobalServiceContext(), std::move(configHooks)); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_init.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_init.cpp index 1e839e2c1ac..5b7d2cc2239 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_init.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_init.cpp @@ -166,7 +166,7 @@ public: }; } // namespace -MONGO_INITIALIZER_WITH_PREREQUISITES(WiredTigerEngineInit, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(WiredTigerEngineInit) (InitializerContext* context) { getGlobalServiceContext()->registerStorageEngine(kWiredTigerEngineName, new WiredTigerFactory()); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mock.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mock.cpp index 770b1d9b3cd..118471655ad 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mock.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mock.cpp @@ -35,8 +35,10 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h" -#include "mongo/stdx/memory.h" + +#include <memory> namespace mongo { namespace { @@ -50,9 +52,8 @@ MONGO_INITIALIZER(SetInitRsOplogBackgroundThreadCallback)(InitializerContext* co return Status::OK(); } -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextCreator([]() { + return std::make_unique<ServiceContextNoop>(); +}); } // namespace } // namespace mongo diff --git a/src/mongo/dbtests/dbtests.cpp b/src/mongo/dbtests/dbtests.cpp index 5e51f5c5c0b..07db83f45ac 100644 --- a/src/mongo/dbtests/dbtests.cpp +++ b/src/mongo/dbtests/dbtests.cpp @@ -50,6 +50,7 @@ #include "mongo/db/repl/storage_interface_mock.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_d.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/wire_version.h" #include "mongo/dbtests/framework.h" #include "mongo/scripting/engine.h" @@ -129,7 +130,9 @@ int dbtestsMain(int argc, char** argv, char** envp) { ::mongo::setTestCommandsEnabled(true); ::mongo::setupSynchronousSignalHandlers(); mongo::dbtests::initWireSpec(); - mongo::runGlobalInitializersOrDie(argc, argv, envp); + + setGlobalServiceContext(createServiceContext()); + mongo::runGlobalInitializersOrDie(argc, argv, envp, getGlobalServiceContext()); serverGlobalParams.featureCompatibility.setVersion( ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40); repl::ReplSettings replSettings; diff --git a/src/mongo/executor/connection_pool.cpp b/src/mongo/executor/connection_pool.cpp index 43d061db5a8..c00fe1c739b 100644 --- a/src/mongo/executor/connection_pool.cpp +++ b/src/mongo/executor/connection_pool.cpp @@ -280,7 +280,9 @@ ConnectionPool::ConnectionPool(std::unique_ptr<DependentTypeFactoryInterface> im } ConnectionPool::~ConnectionPool() { - if (_manager) { + // If we're currently destroying the service context the _manager is already deleted and this + // pointer dangles. No need for cleanup in that case. + if (hasGlobalServiceContext() && _manager) { _manager->remove(this); } } diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp index 449f51389db..cedcf00ff64 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -61,6 +61,7 @@ #include "mongo/db/server_options.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/db/session_killer.h" #include "mongo/db/startup_warnings_common.h" #include "mongo/db/wire_version.h" @@ -549,13 +550,14 @@ MONGO_INITIALIZER(CreateAuthorizationExternalStateFactory)(InitializerContext* c return Status::OK(); } -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>()); - getGlobalServiceContext()->setTickSource(stdx::make_unique<SystemTickSource>()); - getGlobalServiceContext()->setFastClockSource(stdx::make_unique<SystemClockSource>()); - getGlobalServiceContext()->setPreciseClockSource(stdx::make_unique<SystemClockSource>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextCreator([]() { + auto service = std::make_unique<ServiceContextNoop>(); + service->setTickSource(std::make_unique<SystemTickSource>()); + service->setFastClockSource(std::make_unique<SystemClockSource>()); + service->setPreciseClockSource(std::make_unique<SystemClockSource>()); + return service; +}); + #ifdef MONGO_CONFIG_SSL MONGO_INITIALIZER_GENERAL(setSSLManagerType, MONGO_NO_PREREQUISITES, ("SSLManager")) @@ -577,7 +579,8 @@ ExitCode mongoSMain(int argc, char* argv[], char** envp) { setupSignalHandlers(); - Status status = runGlobalInitializers(argc, argv, envp); + setGlobalServiceContext(createServiceContext()); + Status status = runGlobalInitializers(argc, argv, envp, getGlobalServiceContext()); if (!status.isOK()) { severe(LogComponent::kDefault) << "Failed global initialization: " << status; return EXIT_ABRUPT; diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp index 1d58305a883..a85e8a16f92 100644 --- a/src/mongo/shell/dbshell.cpp +++ b/src/mongo/shell/dbshell.cpp @@ -47,6 +47,7 @@ #include "mongo/db/client.h" #include "mongo/db/log_process_details.h" #include "mongo/db/server_options.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/logger/console_appender.h" #include "mongo/logger/logger.h" #include "mongo/logger/message_event_utf8_encoder.h" @@ -740,7 +741,8 @@ int _main(int argc, char* argv[], char** envp) { mongo::shell_utils::RecordMyLocation(argv[0]); - mongo::runGlobalInitializersOrDie(argc, argv, envp); + setGlobalServiceContext(createServiceContext()); + mongo::runGlobalInitializersOrDie(argc, argv, envp, getGlobalServiceContext()); // TODO This should use a TransportLayerManager or TransportLayerFactory auto serviceContext = getGlobalServiceContext(); diff --git a/src/mongo/tools/bridge.cpp b/src/mongo/tools/bridge.cpp index 375c88bbc1b..5e5fcbf7417 100644 --- a/src/mongo/tools/bridge.cpp +++ b/src/mongo/tools/bridge.cpp @@ -39,6 +39,7 @@ #include "mongo/db/dbmessage.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/platform/atomic_word.h" #include "mongo/platform/random.h" #include "mongo/rpc/command_request.h" @@ -391,10 +392,9 @@ private: std::unique_ptr<mongo::BridgeListener> listener; -MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) { - setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>()); - return Status::OK(); -} +ServiceContextRegistrar serviceContextCreator([]() { + return std::make_unique<ServiceContextNoop>(); +}); } // namespace @@ -409,7 +409,8 @@ int bridgeMain(int argc, char** argv, char** envp) { }); setupSignalHandlers(); - runGlobalInitializersOrDie(argc, argv, envp); + setGlobalServiceContext(createServiceContext()); + runGlobalInitializersOrDie(argc, argv, envp, getGlobalServiceContext()); startSignalProcessingThread(LogFileStatus::kNoLogFileToRotate); auto serviceContext = getGlobalServiceContext(); diff --git a/src/mongo/transport/transport_layer_egress_init.cpp b/src/mongo/transport/transport_layer_egress_init.cpp index 20a4fe5a47a..279bd05b6ce 100644 --- a/src/mongo/transport/transport_layer_egress_init.cpp +++ b/src/mongo/transport/transport_layer_egress_init.cpp @@ -38,7 +38,7 @@ namespace mongo { namespace { // Linking with this file will configure an egress-only TransportLayer on a ServiceContextNoop. // Use this for unit/integration tests that require only egress networking. -MONGO_INITIALIZER_WITH_PREREQUISITES(ConfigureEgressTransportLayer, ("SetGlobalEnvironment")) +MONGO_INITIALIZER(ConfigureEgressTransportLayer) (InitializerContext* context) { auto sc = getGlobalServiceContext(); invariant(!sc->getTransportLayer()); diff --git a/src/mongo/unittest/SConscript b/src/mongo/unittest/SConscript index 50c94ac7abf..dbc75f2f62f 100644 --- a/src/mongo/unittest/SConscript +++ b/src/mongo/unittest/SConscript @@ -21,6 +21,7 @@ env.Library(target="unittest", env.Library("unittest_main", ['unittest_main.cpp'], LIBDEPS=[ 'unittest', + '$BUILD_DIR/mongo/db/service_context', ]) env.Library(target="integration_test_main", @@ -47,6 +48,7 @@ bmEnv.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/third_party/shim_benchmark', ], ) diff --git a/src/mongo/unittest/benchmark_main.cpp b/src/mongo/unittest/benchmark_main.cpp index a992ddb06bf..b714ace268a 100644 --- a/src/mongo/unittest/benchmark_main.cpp +++ b/src/mongo/unittest/benchmark_main.cpp @@ -33,13 +33,21 @@ #include <benchmark/benchmark.h> #include "mongo/base/initializer.h" +#include "mongo/db/service_context.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/util/signal_handlers_synchronous.h" int main(int argc, char** argv, char** envp) { ::mongo::clearSignalMask(); ::mongo::setupSynchronousSignalHandlers(); - ::mongo::runGlobalInitializersOrDie(argc, argv, envp); + + ::mongo::ServiceContext* serviceContext = nullptr; + if (::mongo::hasServiceContextFactory()) { + ::mongo::setGlobalServiceContext(::mongo::createServiceContext()); + serviceContext = ::mongo::getGlobalServiceContext(); + } + ::mongo::runGlobalInitializersOrDie(argc, argv, envp, serviceContext); // Copied from the BENCHMARK_MAIN macro. ::benchmark::Initialize(&argc, argv); diff --git a/src/mongo/unittest/integration_test_main.cpp b/src/mongo/unittest/integration_test_main.cpp index aaaf12f8c23..382ea69b087 100644 --- a/src/mongo/unittest/integration_test_main.cpp +++ b/src/mongo/unittest/integration_test_main.cpp @@ -37,6 +37,7 @@ #include "mongo/base/initializer.h" #include "mongo/client/connection_string.h" #include "mongo/db/service_context.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/transport/transport_layer_asio.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" @@ -70,7 +71,13 @@ ConnectionString getFixtureConnectionString() { int main(int argc, char** argv, char** envp) { setupSynchronousSignalHandlers(); - runGlobalInitializersOrDie(argc, argv, envp); + + ::mongo::ServiceContext* serviceContext = nullptr; + if (::mongo::hasServiceContextFactory()) { + ::mongo::setGlobalServiceContext(::mongo::createServiceContext()); + serviceContext = ::mongo::getGlobalServiceContext(); + } + runGlobalInitializersOrDie(argc, argv, envp, serviceContext); quickExit(unittest::Suite::run(std::vector<std::string>(), "", 1)); } diff --git a/src/mongo/unittest/unittest_main.cpp b/src/mongo/unittest/unittest_main.cpp index cd259f4e7f5..0b4adf11d3d 100644 --- a/src/mongo/unittest/unittest_main.cpp +++ b/src/mongo/unittest/unittest_main.cpp @@ -33,6 +33,8 @@ #include "mongo/base/initializer.h" #include "mongo/base/status.h" +#include "mongo/db/service_context.h" +#include "mongo/db/service_context_registrar.h" #include "mongo/unittest/unittest.h" #include "mongo/util/options_parser/environment.h" #include "mongo/util/options_parser/option_section.h" @@ -44,7 +46,13 @@ using mongo::Status; int main(int argc, char** argv, char** envp) { ::mongo::clearSignalMask(); ::mongo::setupSynchronousSignalHandlers(); - ::mongo::runGlobalInitializersOrDie(argc, argv, envp); + + ::mongo::ServiceContext* serviceContext = nullptr; + if (::mongo::hasServiceContextFactory()) { + ::mongo::setGlobalServiceContext(::mongo::createServiceContext()); + serviceContext = ::mongo::getGlobalServiceContext(); + } + ::mongo::runGlobalInitializersOrDie(argc, argv, envp, serviceContext); namespace moe = ::mongo::optionenvironment; moe::OptionsParser parser; |