diff options
author | Andrew Morrow <acm@mongodb.com> | 2015-10-07 13:50:46 -0400 |
---|---|---|
committer | Andrew Morrow <acm@mongodb.com> | 2015-10-12 12:25:23 -0400 |
commit | 644e0a886850763603de5c40498c26f78c1f4751 (patch) | |
tree | 10183e54ab450ee4175200cbf1cda65229d9fa25 /src/mongo | |
parent | 86df469d26ef8482ffcf5753929b8a5102086b90 (diff) | |
download | mongo-644e0a886850763603de5c40498c26f78c1f4751.tar.gz |
SERVER-20678 Create a new JS scope for each mapreduce
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/mr.cpp | 6 | ||||
-rw-r--r-- | src/mongo/scripting/engine.h | 5 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/PosixNSPR.cpp | 23 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/engine.cpp | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/engine.h | 1 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/implscope.cpp | 15 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/implscope.h | 6 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/proxyscope.cpp | 67 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/proxyscope.h | 6 |
9 files changed, 99 insertions, 34 deletions
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index b786cb033a8..ddac287ba86 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -762,8 +762,10 @@ void State::init() { // setup js const string userToken = AuthorizationSession::get(ClientBasic::getCurrent())->getAuthenticatedUserNamesToken(); - _scope.reset(globalScriptEngine->getPooledScope(_txn, _config.dbname, "mapreduce" + userToken) - .release()); + _scope.reset(globalScriptEngine->newScopeForCurrentThread()); + _scope->registerOperation(_txn); + _scope->setLocalDB(_config.dbname); + _scope->loadStored(_txn, true); if (!_config.scopeSetup.isEmpty()) _scope->init(&_config.scopeSetup); diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h index 07dc3d24ce7..15c80c0da4e 100644 --- a/src/mongo/scripting/engine.h +++ b/src/mongo/scripting/engine.h @@ -237,6 +237,10 @@ public: return createScope(); } + virtual Scope* newScopeForCurrentThread() { + return createScopeForCurrentThread(); + } + virtual void runTest() = 0; virtual bool utf8Ok() const = 0; @@ -274,6 +278,7 @@ public: protected: virtual Scope* createScope() = 0; + virtual Scope* createScopeForCurrentThread() = 0; void (*_scopeInitCallback)(Scope&); private: diff --git a/src/mongo/scripting/mozjs/PosixNSPR.cpp b/src/mongo/scripting/mozjs/PosixNSPR.cpp index 17bda347a39..6d81ac14a9d 100644 --- a/src/mongo/scripting/mozjs/PosixNSPR.cpp +++ b/src/mongo/scripting/mozjs/PosixNSPR.cpp @@ -50,6 +50,9 @@ class nspr::Thread { public: Thread(void (*start)(void* arg), void* arg, uint32_t stackSize, bool joinable) : start(start), arg(arg), joinable(joinable) { + if (!start) + return; + thread_ = CreateThread(nullptr, stackSize, ThreadRoutine, this, 0, nullptr); if (thread_ == nullptr) { @@ -89,6 +92,8 @@ class nspr::Thread { public: Thread(void (*start)(void* arg), void* arg, uint32_t stackSize, bool joinable) : start(start), arg(arg), joinable(joinable) { + if (!start) + return; pthread_attr_t attrs; if (pthread_attr_init(&attrs) != 0) { @@ -131,6 +136,24 @@ private: }; #endif +namespace mongo { +namespace mozjs { + +void PR_BindThread(PRThread* thread) { + kCurrentThread = thread; +} + +PRThread* PR_CreateFakeThread() { + return new PRThread(nullptr, nullptr, 0, true); +} + +void PR_DestroyFakeThread(PRThread* thread) { + delete thread; +} +} // namespace mozjs +} // namespace mongo + + PRThread* PR_CreateThread(PRThreadType type, void (*start)(void* arg), void* arg, diff --git a/src/mongo/scripting/mozjs/engine.cpp b/src/mongo/scripting/mozjs/engine.cpp index 15875da16e1..d762e772ca7 100644 --- a/src/mongo/scripting/mozjs/engine.cpp +++ b/src/mongo/scripting/mozjs/engine.cpp @@ -67,6 +67,10 @@ mongo::Scope* MozJSScriptEngine::createScope() { return new MozJSProxyScope(this); } +mongo::Scope* MozJSScriptEngine::createScopeForCurrentThread() { + return new MozJSImplScope(this); +} + void MozJSScriptEngine::interrupt(unsigned opId) { stdx::lock_guard<stdx::mutex> intLock(_globalInterruptLock); OpIdToScopeMap::iterator iScope = _opToScopeMap.find(opId); diff --git a/src/mongo/scripting/mozjs/engine.h b/src/mongo/scripting/mozjs/engine.h index a337ef0bcdc..c43dbfa9367 100644 --- a/src/mongo/scripting/mozjs/engine.h +++ b/src/mongo/scripting/mozjs/engine.h @@ -51,6 +51,7 @@ public: ~MozJSScriptEngine() override; mongo::Scope* createScope() override; + mongo::Scope* createScopeForCurrentThread() override; void runTest() override {} diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp index 9c2412ef62f..aa2cd004d8f 100644 --- a/src/mongo/scripting/mozjs/implscope.cpp +++ b/src/mongo/scripting/mozjs/implscope.cpp @@ -204,6 +204,15 @@ void MozJSImplScope::_gcCallback(JSRuntime* rt, JSGCStatus status, void* data) { MozJSImplScope::MozRuntime::MozRuntime() { mongo::sm::reset(kMallocMemoryLimit); + // If this runtime isn't running on an NSPR thread, then it is + // running on a mongo thread. In that case, we need to insert a + // fake NSPR thread so that the SM runtime can call PR functions + // without falling over. + auto thread = PR_GetCurrentThread(); + if (!thread) { + PR_BindThread(_thread = PR_CreateFakeThread()); + } + { stdx::unique_lock<stdx::mutex> lk(gRuntimeCreationMutex); @@ -232,6 +241,12 @@ MozJSImplScope::MozRuntime::MozRuntime() { MozJSImplScope::MozRuntime::~MozRuntime() { JS_DestroyContext(_context); JS_DestroyRuntime(_runtime); + + if (_thread) { + invariant(PR_GetCurrentThread() == _thread); + PR_DestroyFakeThread(_thread); + PR_BindThread(nullptr); + } } MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine) diff --git a/src/mongo/scripting/mozjs/implscope.h b/src/mongo/scripting/mozjs/implscope.h index 56eda215fff..affcdce1470 100644 --- a/src/mongo/scripting/mozjs/implscope.h +++ b/src/mongo/scripting/mozjs/implscope.h @@ -29,6 +29,7 @@ #pragma once #include <jsapi.h> +#include <vm/PosixNSPR.h> #include "mongo/client/dbclientcursor.h" #include "mongo/scripting/mozjs/bindata.h" @@ -317,8 +318,9 @@ private: MozRuntime(); ~MozRuntime(); - JSRuntime* _runtime; - JSContext* _context; + PRThread* _thread = nullptr; + JSRuntime* _runtime = nullptr; + JSContext* _context = nullptr; }; /** diff --git a/src/mongo/scripting/mozjs/proxyscope.cpp b/src/mongo/scripting/mozjs/proxyscope.cpp index bf49709e495..0c171c63635 100644 --- a/src/mongo/scripting/mozjs/proxyscope.cpp +++ b/src/mongo/scripting/mozjs/proxyscope.cpp @@ -73,11 +73,11 @@ MozJSProxyScope::~MozJSProxyScope() { } void MozJSProxyScope::init(const BSONObj* data) { - runOnImplThread([&] { _implScope->init(data); }); + run([&] { _implScope->init(data); }); } void MozJSProxyScope::reset() { - runOnImplThread([&] { _implScope->reset(); }); + run([&] { _implScope->reset(); }); } bool MozJSProxyScope::isKillPending() const { @@ -85,24 +85,24 @@ bool MozJSProxyScope::isKillPending() const { } void MozJSProxyScope::registerOperation(OperationContext* txn) { - runOnImplThread([&] { _implScope->registerOperation(txn); }); + run([&] { _implScope->registerOperation(txn); }); } void MozJSProxyScope::unregisterOperation() { - runOnImplThread([&] { _implScope->unregisterOperation(); }); + run([&] { _implScope->unregisterOperation(); }); } void MozJSProxyScope::localConnectForDbEval(OperationContext* txn, const char* dbName) { - runOnImplThread([&] { _implScope->localConnectForDbEval(txn, dbName); }); + run([&] { _implScope->localConnectForDbEval(txn, dbName); }); } void MozJSProxyScope::externalSetup() { - runOnImplThread([&] { _implScope->externalSetup(); }); + run([&] { _implScope->externalSetup(); }); } std::string MozJSProxyScope::getError() { std::string out; - runOnImplThread([&] { out = _implScope->getError(); }); + run([&] { out = _implScope->getError(); }); return out; } @@ -120,83 +120,83 @@ void MozJSProxyScope::gc() { } void MozJSProxyScope::advanceGeneration() { - runOnImplThread([&] { _implScope->advanceGeneration(); }); + run([&] { _implScope->advanceGeneration(); }); } double MozJSProxyScope::getNumber(const char* field) { double out; - runOnImplThread([&] { out = _implScope->getNumber(field); }); + run([&] { out = _implScope->getNumber(field); }); return out; } int MozJSProxyScope::getNumberInt(const char* field) { int out; - runOnImplThread([&] { out = _implScope->getNumberInt(field); }); + run([&] { out = _implScope->getNumberInt(field); }); return out; } long long MozJSProxyScope::getNumberLongLong(const char* field) { long long out; - runOnImplThread([&] { out = _implScope->getNumberLongLong(field); }); + run([&] { out = _implScope->getNumberLongLong(field); }); return out; } Decimal128 MozJSProxyScope::getNumberDecimal(const char* field) { Decimal128 out; - runOnImplThread([&] { out = _implScope->getNumberDecimal(field); }); + run([&] { out = _implScope->getNumberDecimal(field); }); return out; } std::string MozJSProxyScope::getString(const char* field) { std::string out; - runOnImplThread([&] { out = _implScope->getString(field); }); + run([&] { out = _implScope->getString(field); }); return out; } bool MozJSProxyScope::getBoolean(const char* field) { bool out; - runOnImplThread([&] { out = _implScope->getBoolean(field); }); + run([&] { out = _implScope->getBoolean(field); }); return out; } BSONObj MozJSProxyScope::getObject(const char* field) { BSONObj out; - runOnImplThread([&] { out = _implScope->getObject(field); }); + run([&] { out = _implScope->getObject(field); }); return out; } void MozJSProxyScope::setNumber(const char* field, double val) { - runOnImplThread([&] { _implScope->setNumber(field, val); }); + run([&] { _implScope->setNumber(field, val); }); } void MozJSProxyScope::setString(const char* field, StringData val) { - runOnImplThread([&] { _implScope->setString(field, val); }); + run([&] { _implScope->setString(field, val); }); } void MozJSProxyScope::setBoolean(const char* field, bool val) { - runOnImplThread([&] { _implScope->setBoolean(field, val); }); + run([&] { _implScope->setBoolean(field, val); }); } void MozJSProxyScope::setElement(const char* field, const BSONElement& e, const BSONObj& parent) { - runOnImplThread([&] { _implScope->setElement(field, e, parent); }); + run([&] { _implScope->setElement(field, e, parent); }); } void MozJSProxyScope::setObject(const char* field, const BSONObj& obj, bool readOnly) { - runOnImplThread([&] { _implScope->setObject(field, obj, readOnly); }); + run([&] { _implScope->setObject(field, obj, readOnly); }); } void MozJSProxyScope::setFunction(const char* field, const char* code) { - runOnImplThread([&] { _implScope->setFunction(field, code); }); + run([&] { _implScope->setFunction(field, code); }); } int MozJSProxyScope::type(const char* field) { int out; - runOnImplThread([&] { out = _implScope->type(field); }); + run([&] { out = _implScope->type(field); }); return out; } void MozJSProxyScope::rename(const char* from, const char* to) { - runOnImplThread([&] { _implScope->rename(from, to); }); + run([&] { _implScope->rename(from, to); }); } int MozJSProxyScope::invoke(ScriptingFunction func, @@ -207,7 +207,7 @@ int MozJSProxyScope::invoke(ScriptingFunction func, bool readOnlyArgs, bool readOnlyRecv) { int out; - runOnImplThread([&] { + run([&] { out = _implScope->invoke( func, argsObject, recv, timeoutMs, ignoreReturn, readOnlyArgs, readOnlyRecv); }); @@ -222,20 +222,20 @@ bool MozJSProxyScope::exec(StringData code, bool assertOnError, int timeoutMs) { bool out; - runOnImplThread([&] { + run([&] { out = _implScope->exec(code, name, printResult, reportError, assertOnError, timeoutMs); }); return out; } void MozJSProxyScope::injectNative(const char* field, NativeFunction func, void* data) { - runOnImplThread([&] { _implScope->injectNative(field, func, data); }); + run([&] { _implScope->injectNative(field, func, data); }); } ScriptingFunction MozJSProxyScope::_createFunction(const char* raw, ScriptingFunction functionNumber) { ScriptingFunction out; - runOnImplThread([&] { out = _implScope->_createFunction(raw, functionNumber); }); + run([&] { out = _implScope->_createFunction(raw, functionNumber); }); return out; } @@ -257,16 +257,21 @@ void MozJSProxyScope::kill() { * * Idle -> ProxyRequest -> ImplResponse -> Idle */ -void MozJSProxyScope::runOnImplThread(std::function<void()> f) { +template <typename Closure> +void MozJSProxyScope::run(Closure&& closure) { // We can end up calling functions on the proxy scope from the impl thread // when callbacks from javascript have a handle to the proxy scope and call // methods on it from there. If we're on the same thread, it's safe to // simply call back in, so let's do that. if (_thread == PR_GetCurrentThread()) { - return f(); + return closure(); } + runOnImplThread(std::move(closure)); +} + +void MozJSProxyScope::runOnImplThread(stdx::function<void()> f) { stdx::unique_lock<stdx::mutex> lk(_mutex); _function = std::move(f); @@ -281,6 +286,10 @@ void MozJSProxyScope::runOnImplThread(std::function<void()> f) { // Clear the _status state and throw it if necessary auto status = std::move(_status); + + // Can validate the status outside the lock + lk.unlock(); + uassertStatusOK(status); } diff --git a/src/mongo/scripting/mozjs/proxyscope.h b/src/mongo/scripting/mozjs/proxyscope.h index bb9ad41e3e6..09a84101dfd 100644 --- a/src/mongo/scripting/mozjs/proxyscope.h +++ b/src/mongo/scripting/mozjs/proxyscope.h @@ -176,7 +176,11 @@ public: void kill(); private: - void runOnImplThread(std::function<void()> f); + template <typename Closure> + void run(Closure&& closure); + + void runOnImplThread(stdx::function<void()> f); + void shutdownThread(); static void implThread(void* proxy); |