mongo是mongodb的一个C++写的javascript交互式的可执行客户端。为了分析mongod对于服务请求的响应,这里分析下mongo。先来看看mongo的启动,mongo的启动代码在mongo/shell/dbshell.cpp中。其支持两个javascript 引擎,因为用visual stdio2012调试时默认编译的是spidermonkey,那么就分析spidermonkey那边吧。
当我们使用mongodb时最简单的一个保存命令是db.coll.save({a:1}),我们知道db是javascript对象,也是数据库名,coll是数据集collection,这里将{a:1}保存到coll的集合中,但是这里有一个疑问,javascript对象对于未定义的属性的访问不是通过db[coll]访问的吗,coll这里本应该是undefined,但是为什么结果成功的保存了呢。当我在阅读源码时就有这么个疑问,还好终于从源码中找到了答案,好了废话不多说了,直接分析。
po::options_description shell_options( "options" );//同样是一大堆启动命令,具体含义不说了,自己可以看相关的文档
po::options_description hidden_options( "Hidden options" );
po::options_description cmdline_options( "Command line options" );
po::positional_options_description positional_options;
shell_options.add_options()
( "shell", "run the shell after executing files" )
( "nodb", "don't connect to mongod on startup - no 'db address' arg expected" )
( "norc", "will not run the \".mongorc.js\" file on start up" )
( "quiet", "be less chatty" )
( "port", po::value<string>( &port ), "port to connect to" )
( "host", po::value<string>( &dbhost ), "server to connect to" )
( "eval", po::value<string>( &script ), "evaluate javascript" )
( "username,u", po::value<string>(&username), "username for authentication" )
( "password,p", new mongo::PasswordValue( &password ), "password for authentication" )
( "help,h", "show this usage information" )
( "version", "show version information" )
( "verbose", "increase verbosity" )
( "ipv6", "enable IPv6 support (disabled by default)" )
if ( !nodb ) { // connect to db
//if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl;
//如果启动时没有指定nodb,那么这里将生成一串javascript代码,用来连接mongod
stringstream ss;
if ( mongo::cmdLine.quiet )
ss << "__quiet = true;";
ss << "db = connect( \"" << fixHost( url , dbhost , port ) << "\")";
mongo::shell_utils::_dbConnect = ss.str();
if ( params.count( "password" ) && password.empty() )
password = mongo::askPassword();
if ( username.size() && password.size()) {
stringstream ss;
ss << "if ( ! db.auth( \"" << username << "\" , \"" << password << "\" ) ){ throw 'login failed'; }";
mongo::shell_utils::_dbAuth = ss.str();
}
}
mongo::ScriptEngine::setConnectCallback( mongo::shell_utils::onConnect );//这个回调函数用来做连接成功后的记录工作
mongo::ScriptEngine::setup();
mongo::globalScriptEngine->setScopeInitCallback( mongo::shell_utils::initScope );
auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
shellMainScope = scope.get();
现在来看看mongo::globalScriptEngine->newScope(),在mongo::ScriptEngine::setup()函数中globalScriptEngine=new SMEngine()。
virtual Scope * newScope() {
Scope *s = createScope();
if ( s && _scopeInitCallback )//_scopeInitCallback对应上面的mongo::shell_utils::initScope
_scopeInitCallback( *s );
installGlobalUtils( *s );
return s;
}
createScope对应spideMonkey则为new SMScope()
SMScope() ://spideMonkey的初始化
_this( 0 ),
_reportError( true ),
_externalSetup( false ),
_localConnect( false ) {
smlock;
_context = JS_NewContext( globalSMEngine->_runtime , 8192 );
_convertor = new Convertor( _context );
massert( 10431 , "JS_NewContext failed" , _context );
JS_SetOptions( _context , JSOPTION_VAROBJFIX);
//JS_SetVersion( _context , JSVERSION_LATEST); TODO
JS_SetErrorReporter( _context , errorReporter );
_global = JS_NewObject( _context , &global_class, NULL, NULL);
massert( 10432 , "JS_NewObject failed for global" , _global );
JS_SetGlobalObject( _context , _global );
massert( 10433 , "js init failed" , JS_InitStandardClasses( _context , _global ) );
JS_SetOptions( _context , JS_GetOptions( _context ) | JSOPTION_VAROBJFIX );
JS_DefineFunctions( _context , _global , globalHelpers );//预先定义的几个函数
JS_DefineFunctions( _context , _convertor->getGlobalObject( "Object" ), objectHelpers );
//JS_SetGCCallback( _context , no_gc ); // this is useful for se