diff options
-rw-r--r-- | src/mongo/client/embedded/SConscript | 14 | ||||
-rw-r--r-- | src/mongo/client/embedded/libmongodbcapi.cpp | 62 | ||||
-rw-r--r-- | src/mongo/client/embedded/libmongodbcapi.h | 2 | ||||
-rw-r--r-- | src/mongo/client/embedded/libmongodbcapi_test.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/mongod_options.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/service_context.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/service_context.h | 11 |
7 files changed, 111 insertions, 11 deletions
diff --git a/src/mongo/client/embedded/SConscript b/src/mongo/client/embedded/SConscript index 6a8505acf63..d35d39bda14 100644 --- a/src/mongo/client/embedded/SConscript +++ b/src/mongo/client/embedded/SConscript @@ -10,19 +10,25 @@ capi = env.Library( 'libmongodbcapi.cpp', ], LIBDEPS=[ - '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/mongodmain', + '$BUILD_DIR/mongo/transport/transport_layer_mock', + '$BUILD_DIR/mongo/util/net/network', ] ) -env.Alias( 'embedded_capi', capi) +env.Alias('embedded_capi', capi) -env.CppUnitTest( +capiTest = env.Program( target='mongo_embedded_capi_test', source=[ 'libmongodbcapi_test.cpp', ], LIBDEPS=[ - '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/unittest/unittest', 'mongo_embedded_capi', ], ) + +env.RegisterUnitTest(capiTest[0]) diff --git a/src/mongo/client/embedded/libmongodbcapi.cpp b/src/mongo/client/embedded/libmongodbcapi.cpp index c4d5997bfef..135c1c245ba 100644 --- a/src/mongo/client/embedded/libmongodbcapi.cpp +++ b/src/mongo/client/embedded/libmongodbcapi.cpp @@ -29,12 +29,21 @@ #include "mongo/client/embedded/libmongodbcapi.h" #include <exception> +#include <thread> #include <unordered_map> #include <vector> +#include "mongo/db/client.h" +#include "mongo/db/dbmain.h" +#include "mongo/db/service_context.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/unordered_map.h" +#include "mongo/transport/service_entry_point.h" +#include "mongo/transport/transport_layer_mock.h" #include "mongo/util/assert_util.h" +#include "mongo/util/net/message.h" +#include "mongo/util/scopeguard.h" +#include "mongo/util/shared_buffer.h" struct libmongodbcapi_db { libmongodbcapi_db() = default; @@ -42,9 +51,11 @@ struct libmongodbcapi_db { libmongodbcapi_db(const libmongodbcapi_db&) = delete; libmongodbcapi_db& operator=(const libmongodbcapi_db&) = delete; - void* db_sc = nullptr; + mongo::ServiceContext* serviceContext = nullptr; + mongo::stdx::thread mongodThread; mongo::stdx::unordered_map<libmongodbcapi_client*, std::unique_ptr<libmongodbcapi_client>> open_clients; + std::unique_ptr<mongo::transport::TransportLayerMock> transportLayer; }; struct libmongodbcapi_client { libmongodbcapi_client(libmongodbcapi_db* db) : parent_db(db) {} @@ -55,6 +66,8 @@ struct libmongodbcapi_client { void* client_handle = nullptr; std::vector<unsigned char> output; libmongodbcapi_db* parent_db = nullptr; + mongo::ServiceContext::UniqueClient client; + mongo::DbResponse response; }; namespace mongo { @@ -62,13 +75,33 @@ namespace { libmongodbcapi_db* global_db = nullptr; thread_local int last_error = LIBMONGODB_CAPI_ERROR_SUCCESS; +bool run_setup = false; -libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexcept try { +libmongodbcapi_db* db_new(int argc, char** argv, char** envp) noexcept try { last_error = LIBMONGODB_CAPI_ERROR_SUCCESS; if (global_db) { throw std::runtime_error("DB already exists"); } global_db = new libmongodbcapi_db; + if (!run_setup) { + // call mongoDbMain() in a new thread because it currently does not terminate + global_db->mongodThread = stdx::thread([=] { mongoDbMain(argc, argv, envp); }); + global_db->mongodThread.detach(); + + // 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(); + } + // creating mock transport layer + global_db->transportLayer = stdx::make_unique<transport::TransportLayerMock>(); + return global_db; } catch (const std::exception& e) { last_error = LIBMONGODB_CAPI_ERROR_UNKNOWN; @@ -94,6 +127,10 @@ libmongodbcapi_client* client_new(libmongodbcapi_db* db) noexcept try { auto new_client = stdx::make_unique<libmongodbcapi_client>(db); libmongodbcapi_client* rv = new_client.get(); db->open_clients.insert(std::make_pair(rv, std::move(new_client))); + + auto session = global_db->transportLayer->createSession(); + rv->client = global_db->serviceContext->makeClient("embedded", std::move(session)); + last_error = LIBMONGODB_CAPI_ERROR_SUCCESS; return rv; } catch (const std::exception& e) { @@ -113,8 +150,25 @@ int client_wire_protocol_rpc(libmongodbcapi_client* client, const void* input, size_t input_size, void** output, - size_t* output_size) noexcept { + size_t* output_size) noexcept try { + mongo::Client::setCurrent(std::move(client->client)); + const auto guard = mongo::MakeGuard([&] { client->client = mongo::Client::releaseCurrent(); }); + + auto opCtx = cc().makeOperationContext(); + auto sep = client->parent_db->serviceContext->getServiceEntryPoint(); + + auto sb = SharedBuffer::allocate(input_size); + memcpy(sb.get(), input, input_size); + + Message msg(std::move(sb)); + + client->response = sep->handleRequest(opCtx.get(), msg); + *output_size = client->response.response.size(); + *output = (void*)client->response.response.buf(); + return LIBMONGODB_CAPI_ERROR_SUCCESS; +} catch (const std::exception& e) { + return LIBMONGODB_CAPI_ERROR_UNKNOWN; } int get_last_capi_error() noexcept { @@ -124,7 +178,7 @@ int get_last_capi_error() noexcept { } // namespace mongo extern "C" { -libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char** envp) { +libmongodbcapi_db* libmongodbcapi_db_new(int argc, char** argv, char** envp) { return mongo::db_new(argc, argv, envp); } diff --git a/src/mongo/client/embedded/libmongodbcapi.h b/src/mongo/client/embedded/libmongodbcapi.h index 2463bc784a7..0d0869dca57 100644 --- a/src/mongo/client/embedded/libmongodbcapi.h +++ b/src/mongo/client/embedded/libmongodbcapi.h @@ -54,7 +54,7 @@ typedef enum { * * @return A pointer to a db handle or null on error */ -libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char** envp); +libmongodbcapi_db* libmongodbcapi_db_new(int argc, char** argv, char** envp); /** * Shuts down the database diff --git a/src/mongo/client/embedded/libmongodbcapi_test.cpp b/src/mongo/client/embedded/libmongodbcapi_test.cpp index 48c7ccb50d9..3b2e67c0ee9 100644 --- a/src/mongo/client/embedded/libmongodbcapi_test.cpp +++ b/src/mongo/client/embedded/libmongodbcapi_test.cpp @@ -32,13 +32,16 @@ #include <set> #include "mongo/unittest/unittest.h" +#include "mongo/util/quick_exit.h" +#include "mongo/util/signal_handlers_synchronous.h" namespace { class MongodbCAPITest : public mongo::unittest::Test { protected: void setUp() { - db = libmongodbcapi_db_new(0, nullptr, nullptr); + char* argv[] = {(char*)"mongo_embedded_capi_test", (char*)"--port", (char*)"0"}; + db = libmongodbcapi_db_new(3, argv, nullptr); ASSERT(db != nullptr); } @@ -180,3 +183,14 @@ TEST_F(MongodbCAPITest, CreateMultipleDBs) { ASSERT_EQUALS(libmongodbcapi_get_last_error(), LIBMONGODB_CAPI_ERROR_UNKNOWN); } } // namespace + +// Define main function as an entry to these tests. +// These test functions cannot use the main() defined for unittests because they +// call runGlobalInitializers(). The embedded C API calls mongoDbMain() which +// calls runGlobalInitializers(). +int main(int argc, char** argv, char** envp) { + ::mongo::clearSignalMask(); + ::mongo::setupSynchronousSignalHandlers(); + auto result = ::mongo::unittest::Suite::run(std::vector<std::string>(), "", 1); + mongo::quickExit(result); +} diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp index 0f00b00d615..9a38888635d 100644 --- a/src/mongo/db/mongod_options.cpp +++ b/src/mongo/db/mongod_options.cpp @@ -1179,7 +1179,7 @@ Status storeMongodOptions(const moe::Environment& params) { } } } else { - if (serverGlobalParams.port <= 0 || serverGlobalParams.port > 65535) { + if (serverGlobalParams.port < 0 || serverGlobalParams.port > 65535) { return Status(ErrorCodes::BadValue, "bad --port number"); } } diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp index f4083be9901..72ef69afee8 100644 --- a/src/mongo/db/service_context.cpp +++ b/src/mongo/db/service_context.cpp @@ -46,6 +46,8 @@ namespace mongo { namespace { ServiceContext* globalServiceContext = nullptr; +stdx::mutex globalServiceContextMutex; +stdx::condition_variable globalServiceContextCV; } // namespace @@ -58,11 +60,24 @@ ServiceContext* getGlobalServiceContext() { return globalServiceContext; } +ServiceContext* waitAndGetGlobalServiceContext() { + stdx::unique_lock<stdx::mutex> lk(globalServiceContextMutex); + globalServiceContextCV.wait(lk, [] { return globalServiceContext; }); + fassert(40549, globalServiceContext); + return globalServiceContext; +} + void setGlobalServiceContext(std::unique_ptr<ServiceContext>&& serviceContext) { fassert(17509, serviceContext.get()); delete globalServiceContext; + stdx::lock_guard<stdx::mutex> lk(globalServiceContextMutex); + + if (!globalServiceContext) { + globalServiceContextCV.notify_all(); + } + globalServiceContext = serviceContext.release(); } diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index 3cf830c3fe7..9b3d97f1210 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -525,6 +525,17 @@ bool hasGlobalServiceContext(); ServiceContext* getGlobalServiceContext(); /** + * Warning - This function is temporary. Do not introduce new uses of this API. + * + * Returns the singleton ServiceContext for this server process. + * + * Waits until there is a valid global ServiceContext. + * + * Caller does not own pointer. + */ +ServiceContext* waitAndGetGlobalServiceContext(); + +/** * Sets the global ServiceContext. If 'serviceContext' is NULL, un-sets and deletes * the current global ServiceContext. * |