summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/client/embedded/SConscript14
-rw-r--r--src/mongo/client/embedded/libmongodbcapi.cpp62
-rw-r--r--src/mongo/client/embedded/libmongodbcapi.h2
-rw-r--r--src/mongo/client/embedded/libmongodbcapi_test.cpp16
-rw-r--r--src/mongo/db/mongod_options.cpp2
-rw-r--r--src/mongo/db/service_context.cpp15
-rw-r--r--src/mongo/db/service_context.h11
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.
*