summaryrefslogtreecommitdiff
path: root/src/mongo/scripting
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-07-24 14:44:23 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-07-28 17:14:17 -0400
commit78d2f38aa445ef1658300e66e1db14b9f1eceba8 (patch)
treed8503e6badb65230017c5c6a4042983283b11933 /src/mongo/scripting
parent5e515de16fe1eac1f7079a2a95aa9e4f716ee3ec (diff)
downloadmongo-78d2f38aa445ef1658300e66e1db14b9f1eceba8.tar.gz
SERVER-13961 Pass through OperationContext in the JS framework
The JS framework uses DBDirectClient, which requires OperationContext in order to not conflict with locks, which have already been acquired. This change also makes dbEval not use pooled scopes and create a new scope instead.
Diffstat (limited to 'src/mongo/scripting')
-rw-r--r--src/mongo/scripting/engine.cpp21
-rw-r--r--src/mongo/scripting/engine.h21
-rw-r--r--src/mongo/scripting/engine_v8-3.25.cpp17
-rw-r--r--src/mongo/scripting/engine_v8-3.25.h9
-rw-r--r--src/mongo/scripting/engine_v8.cpp17
-rw-r--r--src/mongo/scripting/engine_v8.h9
-rw-r--r--src/mongo/scripting/v8-3.25_db.cpp2
-rw-r--r--src/mongo/scripting/v8-3.25_db.h8
-rw-r--r--src/mongo/scripting/v8_db.cpp2
-rw-r--r--src/mongo/scripting/v8_db.h7
10 files changed, 73 insertions, 40 deletions
diff --git a/src/mongo/scripting/engine.cpp b/src/mongo/scripting/engine.cpp
index 820acd24eda..449fe15ee08 100644
--- a/src/mongo/scripting/engine.cpp
+++ b/src/mongo/scripting/engine.cpp
@@ -57,6 +57,7 @@ namespace mongo {
}
Scope::~Scope() {
+
}
void Scope::append(BSONObjBuilder& builder, const char* fieldName, const char* scopeName) {
@@ -177,7 +178,7 @@ namespace mongo {
uassert(10430, "invalid object id: not hex", std::isxdigit(str.at(i)));
}
- void Scope::loadStored(bool ignoreNotConnected) {
+ void Scope::loadStored(OperationContext* txn, bool ignoreNotConnected) {
if (_localDBName.size() == 0) {
if (ignoreNotConnected)
return;
@@ -190,7 +191,7 @@ namespace mongo {
_loadedVersion = _lastVersion;
string coll = _localDBName + ".system.js";
- DBClientBase* directDBClient = createDirectClient();
+ scoped_ptr<DBClientBase> directDBClient(createDirectClient(txn));
auto_ptr<DBClientCursor> c = directDBClient->query(coll, Query(), 0, 0, NULL,
QueryOption_SlaveOk, 0);
massert(16669, "unable to get db client cursor from query", c.get());
@@ -347,7 +348,7 @@ namespace {
PooledScope(const std::string& pool, const boost::shared_ptr<Scope>& real)
: _pool(pool)
, _real(real) {
- _real->loadStored(true);
+
}
virtual ~PooledScope() {
@@ -357,9 +358,13 @@ namespace {
// wrappers for the derived (_real) scope
void reset() { _real->reset(); }
void init(const BSONObj* data) { _real->init(data); }
- void localConnect(const char* dbName) { _real->localConnect(dbName); }
+ void localConnectForDbEval(OperationContext* txn, const char* dbName) {
+ invariant(!"localConnectForDbEval should only be called from dbEval");
+ }
void setLocalDB(const string& dbName) { _real->setLocalDB(dbName); }
- void loadStored(bool ignoreNotConnected = false) { _real->loadStored(ignoreNotConnected); }
+ void loadStored(OperationContext* txn, bool ignoreNotConnected = false) {
+ _real->loadStored(txn, ignoreNotConnected);
+ }
void externalSetup() { _real->externalSetup(); }
void gc() { _real->gc(); }
bool isKillPending() const { return _real->isKillPending(); }
@@ -417,7 +422,9 @@ namespace {
};
/** Get a scope from the pool of scopes matching the supplied pool name */
- auto_ptr<Scope> ScriptEngine::getPooledScope(const string& db, const string& scopeType) {
+ auto_ptr<Scope> ScriptEngine::getPooledScope(OperationContext* txn,
+ const string& db,
+ const string& scopeType) {
const string fullPoolName = db + scopeType;
boost::shared_ptr<Scope> s = scopeCache.tryAcquire(fullPoolName);
if (!s) {
@@ -427,7 +434,7 @@ namespace {
auto_ptr<Scope> p;
p.reset(new PooledScope(fullPoolName, s));
p->setLocalDB(db);
- p->loadStored(true);
+ p->loadStored(txn, true);
return p;
}
diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h
index ec4c1667481..7a3d4b67a8b 100644
--- a/src/mongo/scripting/engine.h
+++ b/src/mongo/scripting/engine.h
@@ -38,27 +38,31 @@ namespace mongo {
class DBClientWithCommands;
class DBClientBase;
+ class OperationContext;
struct JSFile {
const char* name;
const StringData& source;
};
- class Scope : boost::noncopyable {
+ class Scope {
+ MONGO_DISALLOW_COPYING(Scope);
public:
Scope();
virtual ~Scope();
virtual void reset() = 0;
virtual void init(const BSONObj* data) = 0;
+
void init(const char* data) {
BSONObj o(data);
init(&o);
}
- virtual void localConnect(const char* dbName) = 0;
+ virtual void localConnectForDbEval(OperationContext* txn, const char* dbName) = 0;
virtual void externalSetup() = 0;
virtual void setLocalDB(const std::string& localDBName) { _localDBName = localDBName; }
+
virtual BSONObj getObject(const char* field) = 0;
virtual std::string getString(const char* field) = 0;
virtual bool getBoolean(const char* field) = 0;
@@ -135,7 +139,7 @@ namespace mongo {
void execCoreFiles();
- virtual void loadStored(bool ignoreNotConnected = false);
+ virtual void loadStored(OperationContext* txn, bool ignoreNotConnected = false);
/**
* if any changes are made to .system.js, call this
@@ -149,7 +153,7 @@ namespace mongo {
void incTimesUsed() { ++_numTimesUsed; }
/** gets the number of times a scope was used */
- int getTimesUsed() { return _numTimesUsed; }
+ int getTimesUsed() const { return _numTimesUsed; }
/** return true if last invoke() return'd native code */
virtual bool isLastRetNativeCode() { return _lastRetIsNativeCode; }
@@ -183,7 +187,8 @@ namespace mongo {
bool _lastRetIsNativeCode; // v8 only: set to true if eval'd script returns a native func
};
- class ScriptEngine : boost::noncopyable {
+ class ScriptEngine {
+ MONGO_DISALLOW_COPYING(ScriptEngine);
public:
ScriptEngine();
virtual ~ScriptEngine();
@@ -204,7 +209,9 @@ namespace mongo {
* This must include authenticated users.
* @return the scope
*/
- std::auto_ptr<Scope> getPooledScope(const std::string& db, const std::string& scopeType);
+ std::auto_ptr<Scope> getPooledScope(OperationContext* txn,
+ const std::string& db,
+ const std::string& scopeType);
void setScopeInitCallback(void (*func)(Scope&)) { _scopeInitCallback = func; }
static void setConnectCallback(void (*func)(DBClientWithCommands&)) {
@@ -255,5 +262,7 @@ namespace mongo {
bool hasJSReturn(const std::string& s);
const char* jsSkipWhiteSpace(const char* raw);
+ DBClientBase* createDirectClient(OperationContext* txn);
+
extern ScriptEngine* globalScriptEngine;
}
diff --git a/src/mongo/scripting/engine_v8-3.25.cpp b/src/mongo/scripting/engine_v8-3.25.cpp
index 4bf7e34ad54..a2c57034e26 100644
--- a/src/mongo/scripting/engine_v8-3.25.cpp
+++ b/src/mongo/scripting/engine_v8-3.25.cpp
@@ -482,6 +482,10 @@ namespace mongo {
bool V8Scope::isKillPending() const {
return _pendingKill || _engine->interrupted();
}
+
+ OperationContext* V8Scope::getOpContext() const {
+ return _opCtx;
+ }
/**
* Display a list of all known ops (for verbose output)
@@ -505,7 +509,8 @@ namespace mongo {
_cpuProfiler(),
_interruptLock("ScopeInterruptLock"),
_inNativeExecution(true),
- _pendingKill(false) {
+ _pendingKill(false),
+ _opCtx(NULL) {
// create new isolate and enter it via a scope
_isolate.set(v8::Isolate::New());
@@ -1265,9 +1270,13 @@ namespace mongo {
v8::V8::LowMemoryNotification();
}
- void V8Scope::localConnect(const char * dbName) {
+ void V8Scope::localConnectForDbEval(OperationContext* txn, const char * dbName) {
{
- V8_SIMPLE_HEADER
+ V8_SIMPLE_HEADER;
+
+ invariant(_opCtx == NULL);
+ _opCtx = txn;
+
if (_connectState == EXTERNAL)
uasserted(12510, "externalSetup already called, can't call localConnect");
if (_connectState == LOCAL) {
@@ -1295,7 +1304,7 @@ namespace mongo {
_connectState = LOCAL;
_localDBName = dbName;
}
- loadStored();
+ loadStored(txn);
}
void V8Scope::externalSetup() {
diff --git a/src/mongo/scripting/engine_v8-3.25.h b/src/mongo/scripting/engine_v8-3.25.h
index 87d1f78ddbf..c75c626019d 100644
--- a/src/mongo/scripting/engine_v8-3.25.h
+++ b/src/mongo/scripting/engine_v8-3.25.h
@@ -172,12 +172,18 @@ namespace mongo {
/** check if there is a pending killOp request */
bool isKillPending() const;
+
+ /**
+ * Obtains the operation context associated with this Scope, so it can be given to the
+ * DBDirectClient used by the V8 engine's connection. Only needed for dbEval.
+ */
+ OperationContext* getOpContext() const;
/**
* Connect to a local database, create a Mongo object instance, and load any
* server-side js into the global object
*/
- virtual void localConnect(const char* dbName);
+ virtual void localConnectForDbEval(OperationContext* txn, const char* dbName);
virtual void externalSetup();
@@ -516,6 +522,7 @@ namespace mongo {
bool _inNativeExecution; // protected by _interruptLock
bool _pendingKill; // protected by _interruptLock
int _opId; // op id for this scope
+ OperationContext* _opCtx; // Op context for DbEval
};
/// Helper to extract V8Scope for an Isolate
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp
index 3502c95bc6d..05e6aa54017 100644
--- a/src/mongo/scripting/engine_v8.cpp
+++ b/src/mongo/scripting/engine_v8.cpp
@@ -454,6 +454,10 @@ namespace mongo {
return _pendingKill || _engine->interrupted();
}
+ OperationContext* V8Scope::getOpContext() const {
+ return _opCtx;
+ }
+
/**
* Display a list of all known ops (for verbose output)
*/
@@ -476,7 +480,8 @@ namespace mongo {
_cpuProfiler(),
_interruptLock("ScopeInterruptLock"),
_inNativeExecution(true),
- _pendingKill(false) {
+ _pendingKill(false),
+ _opCtx(NULL) {
// create new isolate and enter it via a scope
_isolate.set(v8::Isolate::New());
@@ -1191,10 +1196,14 @@ namespace mongo {
v8::V8::LowMemoryNotification();
}
- void V8Scope::localConnect(const char * dbName) {
+ void V8Scope::localConnectForDbEval(OperationContext* txn, const char * dbName) {
typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
{
- V8_SIMPLE_HEADER
+ V8_SIMPLE_HEADER;
+
+ invariant(_opCtx == NULL);
+ _opCtx = txn;
+
if (_connectState == EXTERNAL)
uasserted(12510, "externalSetup already called, can't call localConnect");
if (_connectState == LOCAL) {
@@ -1221,7 +1230,7 @@ namespace mongo {
_connectState = LOCAL;
_localDBName = dbName;
}
- loadStored();
+ loadStored(txn);
}
void V8Scope::externalSetup() {
diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h
index 463ab734b8e..9c3de0f732a 100644
--- a/src/mongo/scripting/engine_v8.h
+++ b/src/mongo/scripting/engine_v8.h
@@ -168,10 +168,16 @@ namespace mongo {
bool isKillPending() const;
/**
+ * Obtains the operation context associated with this Scope, so it can be given to the
+ * DBDirectClient used by the V8 engine's connection. Only needed for dbEval.
+ */
+ OperationContext* getOpContext() const;
+
+ /**
* Connect to a local database, create a Mongo object instance, and load any
* server-side js into the global object
*/
- virtual void localConnect(const char* dbName);
+ virtual void localConnectForDbEval(OperationContext* txn, const char* dbName);
virtual void externalSetup();
@@ -498,6 +504,7 @@ namespace mongo {
bool _inNativeExecution; // protected by _interruptLock
bool _pendingKill; // protected by _interruptLock
int _opId; // op id for this scope
+ OperationContext* _opCtx; // Op context for DbEval
};
/// Helper to extract V8Scope for an Isolate
diff --git a/src/mongo/scripting/v8-3.25_db.cpp b/src/mongo/scripting/v8-3.25_db.cpp
index d8f4dc01796..ba53950633a 100644
--- a/src/mongo/scripting/v8-3.25_db.cpp
+++ b/src/mongo/scripting/v8-3.25_db.cpp
@@ -173,7 +173,7 @@ namespace mongo {
args.IsConstructCall());
verify(scope->MongoFT()->HasInstance(args.This()));
- DBClientBase* conn = createDirectClient();
+ DBClientBase* conn = createDirectClient(scope->getOpContext());
v8::Local<v8::External> connHandle =
scope->dbClientBaseTracker.track(scope->getIsolate(), args.This(), conn);
diff --git a/src/mongo/scripting/v8-3.25_db.h b/src/mongo/scripting/v8-3.25_db.h
index fe93e1b6fbe..c4c14674f1a 100644
--- a/src/mongo/scripting/v8-3.25_db.h
+++ b/src/mongo/scripting/v8-3.25_db.h
@@ -36,14 +36,6 @@
namespace mongo {
- class DBClientBase;
-
- /**
- * get the DBClientBase connection from JS args
- */
- boost::shared_ptr<mongo::DBClientBase> getConnection(V8Scope* scope,
- const v8::FunctionCallbackInfo<v8::Value>& args);
-
// Internal Cursor
v8::Local<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope);
diff --git a/src/mongo/scripting/v8_db.cpp b/src/mongo/scripting/v8_db.cpp
index 3a380edca6c..a81275b6c60 100644
--- a/src/mongo/scripting/v8_db.cpp
+++ b/src/mongo/scripting/v8_db.cpp
@@ -169,7 +169,7 @@ namespace mongo {
args.IsConstructCall());
verify(scope->MongoFT()->HasInstance(args.This()));
- DBClientBase* conn = createDirectClient();
+ DBClientBase* conn = createDirectClient(scope->getOpContext());
v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This());
v8::Local<v8::External> connHandle = scope->dbClientBaseTracker.track(self, conn);
diff --git a/src/mongo/scripting/v8_db.h b/src/mongo/scripting/v8_db.h
index 5e9d02fed1a..76064c3922b 100644
--- a/src/mongo/scripting/v8_db.h
+++ b/src/mongo/scripting/v8_db.h
@@ -36,13 +36,6 @@
namespace mongo {
- class DBClientBase;
-
- /**
- * get the DBClientBase connection from JS args
- */
- boost::shared_ptr<mongo::DBClientBase> getConnection(V8Scope* scope, const v8::Arguments& args);
-
// Internal Cursor
v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope);