summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morrow <acm@mongodb.com>2015-10-07 13:50:46 -0400
committerAndrew Morrow <acm@mongodb.com>2015-10-12 12:25:23 -0400
commit644e0a886850763603de5c40498c26f78c1f4751 (patch)
tree10183e54ab450ee4175200cbf1cda65229d9fa25
parent86df469d26ef8482ffcf5753929b8a5102086b90 (diff)
downloadmongo-644e0a886850763603de5c40498c26f78c1f4751.tar.gz
SERVER-20678 Create a new JS scope for each mapreduce
-rw-r--r--src/mongo/db/commands/mr.cpp6
-rw-r--r--src/mongo/scripting/engine.h5
-rw-r--r--src/mongo/scripting/mozjs/PosixNSPR.cpp23
-rw-r--r--src/mongo/scripting/mozjs/engine.cpp4
-rw-r--r--src/mongo/scripting/mozjs/engine.h1
-rw-r--r--src/mongo/scripting/mozjs/implscope.cpp15
-rw-r--r--src/mongo/scripting/mozjs/implscope.h6
-rw-r--r--src/mongo/scripting/mozjs/proxyscope.cpp67
-rw-r--r--src/mongo/scripting/mozjs/proxyscope.h6
-rw-r--r--src/third_party/mozjs-38/mongo_sources/vm/PosixNSPR.h8
10 files changed, 107 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);
diff --git a/src/third_party/mozjs-38/mongo_sources/vm/PosixNSPR.h b/src/third_party/mozjs-38/mongo_sources/vm/PosixNSPR.h
index ddd9aa2f6f9..88a9510aab7 100644
--- a/src/third_party/mozjs-38/mongo_sources/vm/PosixNSPR.h
+++ b/src/third_party/mozjs-38/mongo_sources/vm/PosixNSPR.h
@@ -19,6 +19,14 @@ typedef nspr::Thread PRThread;
typedef nspr::Lock PRLock;
typedef nspr::CondVar PRCondVar;
+namespace mongo {
+namespace mozjs {
+void PR_BindThread(PRThread* thread);
+PRThread* PR_CreateFakeThread();
+void PR_DestroyFakeThread(PRThread* thread);
+} // namespace mozjs
+} // namespace mongo
+
enum PRThreadType {
PR_USER_THREAD,
PR_SYSTEM_THREAD