diff options
Diffstat (limited to 'src/mongo/scripting/engine.h')
-rw-r--r-- | src/mongo/scripting/engine.h | 458 |
1 files changed, 243 insertions, 215 deletions
diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h index 9b99d438fc4..b3426d544ab 100644 --- a/src/mongo/scripting/engine.h +++ b/src/mongo/scripting/engine.h @@ -34,225 +34,253 @@ #include "mongo/platform/atomic_word.h" namespace mongo { - typedef unsigned long long ScriptingFunction; - typedef BSONObj (*NativeFunction)(const BSONObj& args, void* data); - typedef std::map<std::string, ScriptingFunction> FunctionCacheMap; +typedef unsigned long long ScriptingFunction; +typedef BSONObj (*NativeFunction)(const BSONObj& args, void* data); +typedef std::map<std::string, ScriptingFunction> FunctionCacheMap; + +class DBClientWithCommands; +class DBClientBase; +class OperationContext; + +struct JSFile { + const char* name; + const StringData& source; +}; + +class Scope { + MONGO_DISALLOW_COPYING(Scope); + +public: + Scope(); + virtual ~Scope(); + + virtual void reset() = 0; + virtual void init(const BSONObj* data) = 0; + virtual void registerOperation(OperationContext* txn) = 0; + virtual void unregisterOperation() = 0; + + void init(const char* data) { + BSONObj o(data); + init(&o); + } + + 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; + virtual double getNumber(const char* field) = 0; + virtual int getNumberInt(const char* field) { + return (int)getNumber(field); + } + virtual long long getNumberLongLong(const char* field) { + return static_cast<long long>(getNumber(field)); + } + + virtual void setElement(const char* field, const BSONElement& e) = 0; + virtual void setNumber(const char* field, double val) = 0; + virtual void setString(const char* field, StringData val) = 0; + virtual void setObject(const char* field, const BSONObj& obj, bool readOnly = true) = 0; + virtual void setBoolean(const char* field, bool val) = 0; + virtual void setFunction(const char* field, const char* code) = 0; + + virtual int type(const char* field) = 0; + + virtual void append(BSONObjBuilder& builder, const char* fieldName, const char* scopeName); + + virtual void rename(const char* from, const char* to) = 0; + + virtual std::string getError() = 0; + + virtual bool hasOutOfMemoryException() = 0; + + virtual bool isKillPending() const = 0; + + virtual void gc() = 0; + + virtual ScriptingFunction createFunction(const char* code); + + /** + * @return 0 on success + */ + int invoke(const char* code, const BSONObj* args, const BSONObj* recv, int timeoutMs = 0); + + virtual int invoke(ScriptingFunction func, + const BSONObj* args, + const BSONObj* recv, + int timeoutMs = 0, + bool ignoreReturn = false, + bool readOnlyArgs = false, + bool readOnlyRecv = false) = 0; + + void invokeSafe(ScriptingFunction func, + const BSONObj* args, + const BSONObj* recv, + int timeoutMs = 0, + bool ignoreReturn = false, + bool readOnlyArgs = false, + bool readOnlyRecv = false) { + int res = invoke(func, args, recv, timeoutMs, ignoreReturn, readOnlyArgs, readOnlyRecv); + if (res == 0) + return; + uasserted(9004, std::string("invoke failed: ") + getError()); + } + + void invokeSafe(const char* code, const BSONObj* args, const BSONObj* recv, int timeoutMs = 0) { + if (invoke(code, args, recv, timeoutMs) == 0) + return; + uasserted(9005, std::string("invoke failed: ") + getError()); + } + + virtual void injectNative(const char* field, NativeFunction func, void* data = 0) = 0; + + virtual bool exec(StringData code, + const std::string& name, + bool printResult, + bool reportError, + bool assertOnError, + int timeoutMs = 0) = 0; + + virtual void execSetup(StringData code, const std::string& name = "setup") { + exec(code, name, false, true, true, 0); + } + + void execSetup(const JSFile& file) { + execSetup(file.source, file.name); + } + + virtual bool execFile(const std::string& filename, + bool printResult, + bool reportError, + int timeoutMs = 0); + + void execCoreFiles(); + + virtual void loadStored(OperationContext* txn, bool ignoreNotConnected = false); + + /** + * if any changes are made to .system.js, call this + * right now its just global - slightly inefficient, but a lot simpler + */ + static void storedFuncMod(OperationContext* txn); + + static void validateObjectIdString(const std::string& str); + + /** increments the number of times a scope was used */ + void incTimesUsed() { + ++_numTimesUsed; + } + + /** gets the number of times a scope was used */ + int getTimesUsed() const { + return _numTimesUsed; + } - class DBClientWithCommands; - class DBClientBase; - class OperationContext; + /** return true if last invoke() return'd native code */ + virtual bool isLastRetNativeCode() { + return _lastRetIsNativeCode; + } - struct JSFile { - const char* name; - const StringData& source; - }; - - class Scope { - MONGO_DISALLOW_COPYING(Scope); - public: - Scope(); - virtual ~Scope(); - - virtual void reset() = 0; - virtual void init(const BSONObj* data) = 0; - virtual void registerOperation(OperationContext* txn) = 0; - virtual void unregisterOperation() = 0; - - void init(const char* data) { - BSONObj o(data); - init(&o); - } - - 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; - virtual double getNumber(const char* field) = 0; - virtual int getNumberInt(const char* field) { return (int)getNumber(field); } - virtual long long getNumberLongLong(const char* field) { - return static_cast<long long>(getNumber(field)); - } - - virtual void setElement(const char* field, const BSONElement& e) = 0; - virtual void setNumber(const char* field, double val) = 0; - virtual void setString(const char* field, StringData val) = 0; - virtual void setObject(const char* field, const BSONObj& obj, bool readOnly=true) = 0; - virtual void setBoolean(const char* field, bool val) = 0; - virtual void setFunction(const char* field, const char* code) = 0; - - virtual int type(const char* field) = 0; - - virtual void append(BSONObjBuilder& builder, const char* fieldName, const char* scopeName); - - virtual void rename(const char* from, const char* to) = 0; - - virtual std::string getError() = 0; - - virtual bool hasOutOfMemoryException() = 0; - - virtual bool isKillPending() const = 0; - - virtual void gc() = 0; - - virtual ScriptingFunction createFunction(const char* code); - - /** - * @return 0 on success - */ - int invoke(const char* code, const BSONObj* args, const BSONObj* recv, int timeoutMs = 0); - - virtual int invoke(ScriptingFunction func, const BSONObj* args, const BSONObj* recv, - int timeoutMs = 0, bool ignoreReturn = false, bool readOnlyArgs = false, - bool readOnlyRecv = false) = 0; - - void invokeSafe(ScriptingFunction func, const BSONObj* args, const BSONObj* recv, - int timeoutMs = 0, bool ignoreReturn = false, bool readOnlyArgs = false, - bool readOnlyRecv = false) { - int res = invoke(func, args, recv, timeoutMs, ignoreReturn, - readOnlyArgs, readOnlyRecv); - if (res == 0) - return; - uasserted(9004, std::string("invoke failed: ") + getError()); - } - - void invokeSafe(const char* code, const BSONObj* args, const BSONObj* recv, - int timeoutMs = 0) { - if (invoke(code, args, recv, timeoutMs) == 0) - return; - uasserted(9005, std::string("invoke failed: ") + getError()); - } - - virtual void injectNative(const char* field, NativeFunction func, void* data = 0) = 0; - - virtual bool exec(StringData code, const std::string& name, bool printResult, - bool reportError, bool assertOnError, int timeoutMs = 0) = 0; - - virtual void execSetup(StringData code, const std::string& name = "setup") { - exec(code, name, false, true, true, 0); - } - - void execSetup(const JSFile& file) { - execSetup(file.source, file.name); - } - - virtual bool execFile(const std::string& filename, bool printResult, bool reportError, - int timeoutMs = 0); - - void execCoreFiles(); - - virtual void loadStored(OperationContext* txn, bool ignoreNotConnected = false); - - /** - * if any changes are made to .system.js, call this - * right now its just global - slightly inefficient, but a lot simpler - */ - static void storedFuncMod(OperationContext *txn); - - static void validateObjectIdString(const std::string& str); - - /** increments the number of times a scope was used */ - void incTimesUsed() { ++_numTimesUsed; } + class NoDBAccess { + Scope* _s; - /** gets the number of times a scope was used */ - int getTimesUsed() const { return _numTimesUsed; } - - /** return true if last invoke() return'd native code */ - virtual bool isLastRetNativeCode() { return _lastRetIsNativeCode; } - - class NoDBAccess { - Scope* _s; - public: - NoDBAccess(Scope* s) : _s(s) { - } - ~NoDBAccess() { - _s->rename("____db____", "db"); - } - }; - NoDBAccess disableDBAccess(const char* why) { - rename("db", "____db____"); - return NoDBAccess(this); - } - - protected: - friend class PooledScope; - - /** - * RecoveryUnit::Change subclass used to commit work for - * Scope::storedFuncMod logOp listener. - */ - class StoredFuncModLogOpHandler; - - virtual FunctionCacheMap& getFunctionCache() { return _cachedFunctions; } - virtual ScriptingFunction _createFunction(const char* code, - ScriptingFunction functionNumber = 0) = 0; - - std::string _localDBName; - int64_t _loadedVersion; - std::set<std::string> _storedNames; - static AtomicInt64 _lastVersion; - FunctionCacheMap _cachedFunctions; - int _numTimesUsed; - bool _lastRetIsNativeCode; // v8 only: set to true if eval'd script returns a native func - }; - - class ScriptEngine : public KillOpListenerInterface { - MONGO_DISALLOW_COPYING(ScriptEngine); public: - ScriptEngine(); - virtual ~ScriptEngine(); - - virtual Scope* newScope() { - return createScope(); + NoDBAccess(Scope* s) : _s(s) {} + ~NoDBAccess() { + _s->rename("____db____", "db"); } - - virtual void runTest() = 0; - - virtual bool utf8Ok() const = 0; - - static void setup(); - - /** gets a scope from the pool or a new one if pool is empty - * @param db The db name - * @param scopeType A unique id to limit scope sharing. - * This must include authenticated users. - * @return the scope - */ - std::unique_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&)) { - _connectCallback = func; - } - static void runConnectCallback(DBClientWithCommands& c) { - if (_connectCallback) - _connectCallback(c); - } - - // engine implementation may either respond to interrupt events or - // poll for interrupts. the interrupt functions must not wait indefinitely on a lock. - virtual void interrupt(unsigned opId) {} - virtual void interruptAll() {} - - static std::string getInterpreterVersionString(); - - protected: - virtual Scope* createScope() = 0; - void (*_scopeInitCallback)(Scope&); - - private: - static void (*_connectCallback)(DBClientWithCommands&); }; - - void installGlobalUtils(Scope& scope); - bool hasJSReturn(const std::string& s); - const char* jsSkipWhiteSpace(const char* raw); - - DBClientBase* createDirectClient(OperationContext* txn); - - extern ScriptEngine* globalScriptEngine; + NoDBAccess disableDBAccess(const char* why) { + rename("db", "____db____"); + return NoDBAccess(this); + } + +protected: + friend class PooledScope; + + /** + * RecoveryUnit::Change subclass used to commit work for + * Scope::storedFuncMod logOp listener. + */ + class StoredFuncModLogOpHandler; + + virtual FunctionCacheMap& getFunctionCache() { + return _cachedFunctions; + } + virtual ScriptingFunction _createFunction(const char* code, + ScriptingFunction functionNumber = 0) = 0; + + std::string _localDBName; + int64_t _loadedVersion; + std::set<std::string> _storedNames; + static AtomicInt64 _lastVersion; + FunctionCacheMap _cachedFunctions; + int _numTimesUsed; + bool _lastRetIsNativeCode; // v8 only: set to true if eval'd script returns a native func +}; + +class ScriptEngine : public KillOpListenerInterface { + MONGO_DISALLOW_COPYING(ScriptEngine); + +public: + ScriptEngine(); + virtual ~ScriptEngine(); + + virtual Scope* newScope() { + return createScope(); + } + + virtual void runTest() = 0; + + virtual bool utf8Ok() const = 0; + + static void setup(); + + /** gets a scope from the pool or a new one if pool is empty + * @param db The db name + * @param scopeType A unique id to limit scope sharing. + * This must include authenticated users. + * @return the scope + */ + std::unique_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&)) { + _connectCallback = func; + } + static void runConnectCallback(DBClientWithCommands& c) { + if (_connectCallback) + _connectCallback(c); + } + + // engine implementation may either respond to interrupt events or + // poll for interrupts. the interrupt functions must not wait indefinitely on a lock. + virtual void interrupt(unsigned opId) {} + virtual void interruptAll() {} + + static std::string getInterpreterVersionString(); + +protected: + virtual Scope* createScope() = 0; + void (*_scopeInitCallback)(Scope&); + +private: + static void (*_connectCallback)(DBClientWithCommands&); +}; + +void installGlobalUtils(Scope& scope); +bool hasJSReturn(const std::string& s); +const char* jsSkipWhiteSpace(const char* raw); + +DBClientBase* createDirectClient(OperationContext* txn); + +extern ScriptEngine* globalScriptEngine; } |