00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #pragma once
00019
00020 #include "../pch.h"
00021 #include "../db/jsobj.h"
00022
00023 namespace mongo {
00024
00025 struct JSFile {
00026 const char* name;
00027 const StringData& source;
00028 };
00029
00030 namespace JSFiles {
00031 extern const JSFile collection;
00032 extern const JSFile db;
00033 extern const JSFile mongo;
00034 extern const JSFile mr;
00035 extern const JSFile query;
00036 extern const JSFile servers;
00037 extern const JSFile utils;
00038 }
00039
00040 typedef unsigned long long ScriptingFunction;
00041 typedef BSONObj (*NativeFunction) ( const BSONObj &args );
00042
00043 class Scope : boost::noncopyable {
00044 public:
00045 Scope();
00046 virtual ~Scope();
00047
00048 virtual void reset() = 0;
00049 virtual void init( const BSONObj * data ) = 0;
00050 void init( const char * data ) {
00051 BSONObj o( data , 0 );
00052 init( &o );
00053 }
00054
00055 virtual void localConnect( const char * dbName ) = 0;
00056 virtual void externalSetup() = 0;
00057
00058 class NoDBAccess {
00059 Scope * _s;
00060 public:
00061 NoDBAccess( Scope * s ) {
00062 _s = s;
00063 }
00064 ~NoDBAccess() {
00065 _s->rename( "____db____" , "db" );
00066 }
00067 };
00068 NoDBAccess disableDBAccess( const char * why ) {
00069 rename( "db" , "____db____" );
00070 return NoDBAccess( this );
00071 }
00072
00073 virtual double getNumber( const char *field ) = 0;
00074 virtual int getNumberInt( const char *field ) { return (int)getNumber( field ); }
00075 virtual long long getNumberLongLong( const char *field ) { return (long long)getNumber( field ); }
00076 virtual string getString( const char *field ) = 0;
00077 virtual bool getBoolean( const char *field ) = 0;
00078 virtual BSONObj getObject( const char *field ) = 0;
00079
00080 virtual int type( const char *field ) = 0;
00081
00082 void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
00083
00084 virtual void setElement( const char *field , const BSONElement& e ) = 0;
00085 virtual void setNumber( const char *field , double val ) = 0;
00086 virtual void setString( const char *field , const char * val ) = 0;
00087 virtual void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) = 0;
00088 virtual void setBoolean( const char *field , bool val ) = 0;
00089 virtual void setThis( const BSONObj * obj ) = 0;
00090
00091 virtual ScriptingFunction createFunction( const char * code );
00092
00093 virtual void rename( const char * from , const char * to ) = 0;
00097 virtual int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 , bool ignoreReturn = false ) = 0;
00098 void invokeSafe( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 ) {
00099 int res = invoke( func , args , timeoutMs );
00100 if ( res == 0 )
00101 return;
00102 throw UserException( 9004 , (string)"invoke failed: " + getError() );
00103 }
00104 virtual string getError() = 0;
00105
00106 int invoke( const char* code , const BSONObj& args, int timeoutMs = 0 );
00107 void invokeSafe( const char* code , const BSONObj& args, int timeoutMs = 0 ) {
00108 if ( invoke( code , args , timeoutMs ) == 0 )
00109 return;
00110 throw UserException( 9005 , (string)"invoke failed: " + getError() );
00111 }
00112
00113 virtual bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0;
00114 virtual void execSetup( const StringData& code , const string& name = "setup" ) {
00115 exec( code , name , false , true , true , 0 );
00116 }
00117
00118 void execSetup( const JSFile& file) {
00119 execSetup(file.source, file.name);
00120 }
00121
00122 void execCoreFiles() {
00123
00124 execSetup(JSFiles::utils);
00125 execSetup(JSFiles::db);
00126 execSetup(JSFiles::mongo);
00127 execSetup(JSFiles::mr);
00128 execSetup(JSFiles::query);
00129 execSetup(JSFiles::collection);
00130 }
00131
00132 virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 );
00133
00134 virtual void injectNative( const char *field, NativeFunction func ) = 0;
00135
00136 virtual void gc() = 0;
00137
00138 void loadStored( bool ignoreNotConnected = false );
00139
00144 static void storedFuncMod();
00145
00146 static int getNumScopes() {
00147 return _numScopes;
00148 }
00149
00150 static void validateObjectIdString( const string &str );
00151
00152 protected:
00153
00154 virtual ScriptingFunction _createFunction( const char * code ) = 0;
00155
00156 string _localDBName;
00157 long long _loadedVersion;
00158 set<string> _storedNames;
00159 static long long _lastVersion;
00160 map<string,ScriptingFunction> _cachedFunctions;
00161
00162 static int _numScopes;
00163 };
00164
00165 void installGlobalUtils( Scope& scope );
00166
00167 class DBClientWithCommands;
00168
00169 class ScriptEngine : boost::noncopyable {
00170 public:
00171 ScriptEngine();
00172 virtual ~ScriptEngine();
00173
00174 virtual Scope * newScope() {
00175 Scope *s = createScope();
00176 if ( s && _scopeInitCallback )
00177 _scopeInitCallback( *s );
00178 installGlobalUtils( *s );
00179 return s;
00180 }
00181
00182 virtual void runTest() = 0;
00183
00184 virtual bool utf8Ok() const = 0;
00185
00186 static void setup();
00187
00188 auto_ptr<Scope> getPooledScope( const string& pool );
00189 void threadDone();
00190
00191 struct Unlocker { virtual ~Unlocker() {} };
00192 virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< Unlocker >( new Unlocker ); }
00193
00194 void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInitCallback = func; }
00195 static void setConnectCallback( void ( *func )( DBClientWithCommands& ) ) { _connectCallback = func; }
00196 static void runConnectCallback( DBClientWithCommands &c ) {
00197 if ( _connectCallback )
00198 _connectCallback( c );
00199 }
00200
00201
00202
00203
00204
00205 virtual void interrupt( unsigned opSpec ) {}
00206 virtual void interruptAll() {}
00207
00208 static void setGetInterruptSpecCallback( unsigned ( *func )() ) { _getInterruptSpecCallback = func; }
00209 static bool haveGetInterruptSpecCallback() { return _getInterruptSpecCallback; }
00210 static unsigned getInterruptSpec() {
00211 massert( 13474, "no _getInterruptSpecCallback", _getInterruptSpecCallback );
00212 return _getInterruptSpecCallback();
00213 }
00214
00215 static void setCheckInterruptCallback( const char * ( *func )() ) { _checkInterruptCallback = func; }
00216 static bool haveCheckInterruptCallback() { return _checkInterruptCallback; }
00217 static const char * checkInterrupt() {
00218 return _checkInterruptCallback ? _checkInterruptCallback() : "";
00219 }
00220 static bool interrupted() {
00221 const char *r = checkInterrupt();
00222 return r && r[ 0 ];
00223 }
00224
00225 protected:
00226 virtual Scope * createScope() = 0;
00227
00228 private:
00229 void ( *_scopeInitCallback )( Scope & );
00230 static void ( *_connectCallback )( DBClientWithCommands & );
00231 static const char * ( *_checkInterruptCallback )();
00232 static unsigned ( *_getInterruptSpecCallback )();
00233 };
00234
00235 bool hasJSReturn( const string& s );
00236
00237 const char * jsSkipWhiteSpace( const char * raw );
00238
00239 extern ScriptEngine * globalScriptEngine;
00240 }