2009-04-23 14:28:22 -04:00
|
|
|
// engine.h
|
|
|
|
|
|
2009-10-27 15:58:27 -04:00
|
|
|
/* Copyright 2009 10gen Inc.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
2010-04-27 15:27:52 -04:00
|
|
|
#include "../pch.h"
|
2009-04-23 14:28:22 -04:00
|
|
|
#include "../db/jsobj.h"
|
|
|
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
|
2010-08-10 14:35:02 -04:00
|
|
|
struct JSFile {
|
|
|
|
|
const char* name;
|
|
|
|
|
const StringData& source;
|
|
|
|
|
};
|
|
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
typedef unsigned long long ScriptingFunction;
|
2011-05-05 16:30:55 -07:00
|
|
|
typedef BSONObj (*NativeFunction) ( const BSONObj &args, void* data );
|
2010-01-28 12:21:56 -05:00
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
class Scope : boost::noncopyable {
|
|
|
|
|
public:
|
|
|
|
|
Scope();
|
|
|
|
|
virtual ~Scope();
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual void reset() = 0;
|
2010-12-15 09:50:35 -05:00
|
|
|
virtual void init( const BSONObj * data ) = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
void init( const char * data ) {
|
2011-04-01 17:35:11 -04:00
|
|
|
BSONObj o( data );
|
2009-04-23 14:28:22 -04:00
|
|
|
init( &o );
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-04-30 10:51:54 -04:00
|
|
|
virtual void localConnect( const char * dbName ) = 0;
|
2009-05-15 16:32:31 -04:00
|
|
|
virtual void externalSetup() = 0;
|
2010-09-01 01:32:04 -04:00
|
|
|
|
|
|
|
|
class NoDBAccess {
|
|
|
|
|
Scope * _s;
|
|
|
|
|
public:
|
2011-01-04 00:40:41 -05:00
|
|
|
NoDBAccess( Scope * s ) {
|
2010-09-01 01:32:04 -04:00
|
|
|
_s = s;
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
~NoDBAccess() {
|
2010-09-01 01:32:04 -04:00
|
|
|
_s->rename( "____db____" , "db" );
|
|
|
|
|
}
|
|
|
|
|
};
|
2011-01-04 00:40:41 -05:00
|
|
|
NoDBAccess disableDBAccess( const char * why ) {
|
2010-09-01 01:32:04 -04:00
|
|
|
rename( "db" , "____db____" );
|
|
|
|
|
return NoDBAccess( this );
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual double getNumber( const char *field ) = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
virtual int getNumberInt( const char *field ) { return (int)getNumber( field ); }
|
|
|
|
|
virtual long long getNumberLongLong( const char *field ) { return (long long)getNumber( field ); }
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual string getString( const char *field ) = 0;
|
|
|
|
|
virtual bool getBoolean( const char *field ) = 0;
|
|
|
|
|
virtual BSONObj getObject( const char *field ) = 0;
|
|
|
|
|
|
|
|
|
|
virtual int type( const char *field ) = 0;
|
|
|
|
|
|
2011-04-27 16:05:40 -07:00
|
|
|
virtual void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
|
2009-09-21 15:54:41 -04:00
|
|
|
|
2009-09-29 16:54:31 -04:00
|
|
|
virtual void setElement( const char *field , const BSONElement& e ) = 0;
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual void setNumber( const char *field , double val ) = 0;
|
|
|
|
|
virtual void setString( const char *field , const char * val ) = 0;
|
2009-05-09 22:07:36 -04:00
|
|
|
virtual void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) = 0;
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual void setBoolean( const char *field , bool val ) = 0;
|
2011-05-05 16:30:55 -07:00
|
|
|
virtual void setFunction( const char *field , const char * code ) = 0;
|
2011-04-27 11:57:10 -07:00
|
|
|
// virtual void setThis( const BSONObj * obj ) = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-10-09 11:32:41 -04:00
|
|
|
virtual ScriptingFunction createFunction( const char * code );
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-09-01 01:32:04 -04:00
|
|
|
virtual void rename( const char * from , const char * to ) = 0;
|
2009-05-08 11:02:12 -04:00
|
|
|
/**
|
|
|
|
|
* @return 0 on success
|
|
|
|
|
*/
|
2011-04-27 11:57:10 -07:00
|
|
|
virtual int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false ) = 0;
|
|
|
|
|
void invokeSafe( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 ) {
|
|
|
|
|
int res = invoke( func , args , recv, timeoutMs );
|
2009-11-13 11:08:42 -05:00
|
|
|
if ( res == 0 )
|
|
|
|
|
return;
|
2009-12-28 17:06:07 -05:00
|
|
|
throw UserException( 9004 , (string)"invoke failed: " + getError() );
|
2009-05-23 21:10:37 -04:00
|
|
|
}
|
2009-05-01 14:34:44 -04:00
|
|
|
virtual string getError() = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2011-04-27 11:57:10 -07:00
|
|
|
int invoke( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 );
|
|
|
|
|
void invokeSafe( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 ) {
|
|
|
|
|
if ( invoke( code , args , recv, timeoutMs ) == 0 )
|
2009-10-13 11:11:55 -04:00
|
|
|
return;
|
2009-12-28 17:06:07 -05:00
|
|
|
throw UserException( 9005 , (string)"invoke failed: " + getError() );
|
2009-05-23 21:10:37 -04:00
|
|
|
}
|
|
|
|
|
|
2010-08-10 13:29:52 -04:00
|
|
|
virtual bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
virtual void execSetup( const StringData& code , const string& name = "setup" ) {
|
2009-09-21 15:22:15 -04:00
|
|
|
exec( code , name , false , true , true , 0 );
|
|
|
|
|
}
|
2010-08-10 14:35:02 -04:00
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
void execSetup( const JSFile& file) {
|
2010-08-10 14:35:02 -04:00
|
|
|
execSetup(file.source, file.name);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-12 13:46:06 -04:00
|
|
|
void execCoreFiles();
|
2010-08-10 14:35:02 -04:00
|
|
|
|
2009-05-19 16:13:24 -04:00
|
|
|
virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 );
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2011-05-05 16:30:55 -07:00
|
|
|
virtual void injectNative( const char *field, NativeFunction func, void* data = 0 ) = 0;
|
2009-05-26 15:36:41 -04:00
|
|
|
|
|
|
|
|
virtual void gc() = 0;
|
2009-09-29 16:54:31 -04:00
|
|
|
|
|
|
|
|
void loadStored( bool ignoreNotConnected = false );
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-09-29 16:54:31 -04:00
|
|
|
/**
|
|
|
|
|
if any changes are made to .system.js, call this
|
|
|
|
|
right now its just global - slightly inefficient, but a lot simpler
|
|
|
|
|
*/
|
|
|
|
|
static void storedFuncMod();
|
2011-01-04 00:40:41 -05:00
|
|
|
|
|
|
|
|
static int getNumScopes() {
|
2009-10-09 11:32:41 -04:00
|
|
|
return _numScopes;
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-21 17:03:12 -08:00
|
|
|
static void validateObjectIdString( const string &str );
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-09-29 16:54:31 -04:00
|
|
|
protected:
|
2009-10-09 11:32:41 -04:00
|
|
|
|
|
|
|
|
virtual ScriptingFunction _createFunction( const char * code ) = 0;
|
|
|
|
|
|
2009-09-29 16:54:31 -04:00
|
|
|
string _localDBName;
|
|
|
|
|
long long _loadedVersion;
|
2010-02-07 01:10:12 -05:00
|
|
|
set<string> _storedNames;
|
2009-09-29 16:54:31 -04:00
|
|
|
static long long _lastVersion;
|
2009-10-09 11:32:41 -04:00
|
|
|
map<string,ScriptingFunction> _cachedFunctions;
|
|
|
|
|
|
|
|
|
|
static int _numScopes;
|
2009-04-23 14:28:22 -04:00
|
|
|
};
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-01-28 12:21:56 -05:00
|
|
|
void installGlobalUtils( Scope& scope );
|
|
|
|
|
|
2010-02-22 12:08:54 -08:00
|
|
|
class DBClientWithCommands;
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
class ScriptEngine : boost::noncopyable {
|
|
|
|
|
public:
|
|
|
|
|
ScriptEngine();
|
|
|
|
|
virtual ~ScriptEngine();
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-29 18:27:49 -08:00
|
|
|
virtual Scope * newScope() {
|
|
|
|
|
Scope *s = createScope();
|
|
|
|
|
if ( s && _scopeInitCallback )
|
|
|
|
|
_scopeInitCallback( *s );
|
2010-01-28 12:21:56 -05:00
|
|
|
installGlobalUtils( *s );
|
2009-12-29 18:27:49 -08:00
|
|
|
return s;
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
virtual void runTest() = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-05-27 15:20:09 -04:00
|
|
|
virtual bool utf8Ok() const = 0;
|
2009-04-23 14:28:22 -04:00
|
|
|
|
|
|
|
|
static void setup();
|
2009-08-05 13:14:06 -04:00
|
|
|
|
|
|
|
|
auto_ptr<Scope> getPooledScope( const string& pool );
|
2009-08-12 10:51:31 -04:00
|
|
|
void threadDone();
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-22 17:56:57 -08:00
|
|
|
struct Unlocker { virtual ~Unlocker() {} };
|
2009-12-22 15:08:17 -08:00
|
|
|
virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< Unlocker >( new Unlocker ); }
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-29 18:27:49 -08:00
|
|
|
void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInitCallback = func; }
|
2010-02-22 12:08:54 -08:00
|
|
|
static void setConnectCallback( void ( *func )( DBClientWithCommands& ) ) { _connectCallback = func; }
|
|
|
|
|
static void runConnectCallback( DBClientWithCommands &c ) {
|
|
|
|
|
if ( _connectCallback )
|
|
|
|
|
_connectCallback( c );
|
|
|
|
|
}
|
2010-09-23 14:36:04 -07:00
|
|
|
|
|
|
|
|
// engine implementation may either respond to interrupt events or
|
|
|
|
|
// poll for interrupts
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-09-23 14:36:04 -07:00
|
|
|
// the interrupt functions must not wait indefinitely on a lock
|
|
|
|
|
virtual void interrupt( unsigned opSpec ) {}
|
|
|
|
|
virtual void interruptAll() {}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-09-23 14:36:04 -07:00
|
|
|
static void setGetInterruptSpecCallback( unsigned ( *func )() ) { _getInterruptSpecCallback = func; }
|
|
|
|
|
static bool haveGetInterruptSpecCallback() { return _getInterruptSpecCallback; }
|
|
|
|
|
static unsigned getInterruptSpec() {
|
|
|
|
|
massert( 13474, "no _getInterruptSpecCallback", _getInterruptSpecCallback );
|
|
|
|
|
return _getInterruptSpecCallback();
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-09-14 17:00:46 -07:00
|
|
|
static void setCheckInterruptCallback( const char * ( *func )() ) { _checkInterruptCallback = func; }
|
|
|
|
|
static bool haveCheckInterruptCallback() { return _checkInterruptCallback; }
|
|
|
|
|
static const char * checkInterrupt() {
|
|
|
|
|
return _checkInterruptCallback ? _checkInterruptCallback() : "";
|
|
|
|
|
}
|
2010-09-23 14:36:04 -07:00
|
|
|
static bool interrupted() {
|
|
|
|
|
const char *r = checkInterrupt();
|
|
|
|
|
return r && r[ 0 ];
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-29 18:27:49 -08:00
|
|
|
protected:
|
|
|
|
|
virtual Scope * createScope() = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2009-12-29 18:27:49 -08:00
|
|
|
private:
|
|
|
|
|
void ( *_scopeInitCallback )( Scope & );
|
2010-02-22 12:08:54 -08:00
|
|
|
static void ( *_connectCallback )( DBClientWithCommands & );
|
2010-09-14 17:00:46 -07:00
|
|
|
static const char * ( *_checkInterruptCallback )();
|
2010-09-23 14:36:04 -07:00
|
|
|
static unsigned ( *_getInterruptSpecCallback )();
|
2009-04-23 14:28:22 -04:00
|
|
|
};
|
|
|
|
|
|
2010-04-08 15:26:12 -04:00
|
|
|
bool hasJSReturn( const string& s );
|
|
|
|
|
|
2010-11-29 01:50:57 -05:00
|
|
|
const char * jsSkipWhiteSpace( const char * raw );
|
|
|
|
|
|
2009-04-23 14:28:22 -04:00
|
|
|
extern ScriptEngine * globalScriptEngine;
|
|
|
|
|
}
|