mongodb源碼分析之mongo shell

Mongo version:0.8
Github:https://github.com/mongodb/mongo

目標:瞭解mongodb的shell是如何實現的

1.進入目錄

可以看到一個shell的目錄,直接進去

在這裏插入圖片描述

在shell目錄下可以看到這樣幾個文件
在這裏插入圖片描述
文件也不多,cpp文件,都瀏覽一下,我們就看到在dbshell.cpp中有main函數了,主要看這個函數就好了
2.代碼分析

int main(int argc, char* argv[]) {
    setupSignals();		//做一些信號的接收工作
    
    RecordMyLocation( argv[ 0 ] );  

    //v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
    
    v8::HandleScope handle_scope;

    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

    installShellUtils( global );		//定義一些shell命令
    installMongoGlobals( global );		//定義一些mongo使用的類

    
    v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
    v8::Context::Scope context_scope(context);
    
    { // init mongo code
        v8::HandleScope handle_scope;
        if ( ! ExecuteString( v8::String::New( jsconcatcode ) , v8::String::New( "(mongo init)" ) , false , true ) )
            return -1;
    }
    
    string url = "test";
    string dbhost;
    string port;
    
    string username;
    string password;

    bool runShell = false;
    bool nodb = false;
    
    int argNumber = 1;
    for ( ; argNumber < argc; argNumber++) {
        const char* str = argv[argNumber];
        
        if (strcmp(str, "--shell") == 0) {
            runShell = true;
            continue;
        } 
        
        if (strcmp(str, "--nodb") == 0) {
            nodb = true;
            continue;
        } 

        if ( strcmp( str , "--port" ) == 0 ){     //這裏是我熟悉的操作,從這裏入手
            port = argv[argNumber+1];
            argNumber++;
            continue;
        }

        if ( strcmp( str , "--host" ) == 0 ){
            dbhost = argv[argNumber+1];
            argNumber++;
            continue;
        }


        if ( strcmp( str , "-u" ) == 0 ){
            username = argv[argNumber+1];
            argNumber++;
            continue;
        }

        if ( strcmp( str , "-p" ) == 0 ){
            password = argv[argNumber+1];
            argNumber++;
            continue;
        }

        if ( strstr( str , "-p" ) == str ){
            password = str;
            password = password.substr( 2 );
            continue;
        }

        if ( strcmp(str, "--help") == 0 || 
             strcmp(str, "-h" ) == 0 ) {

            cout 
                << "usage: " << argv[0] << " [options] [db address] [file names]\n" 
                << "db address can be:\n"
                << "   foo   =   foo database on local machine\n" 
                << "   192.169.0.5/foo   =   foo database on 192.168.0.5 machine\n" 
                << "   192.169.0.5:9999/foo   =   foo database on 192.168.0.5 machine on port 9999\n"
                << "options\n"
                << " --shell run the shell after executing files\n"
                << " -u <username>\n"
                << " -p<password> - notice no space\n"
                << " --host <host> - server to connect to\n"
                << " --port <port> - port to connect to\n"
                << " --nodb don't connect to mongod on startup.  No 'db address' arg expected.\n"
                << "file names: a list of files to run.  will exit after unless --shell is specified\n"
                ;
            
            return 0;
        } 

        if (strcmp(str, "-f") == 0) {
            continue;
        } 
        
        if (strncmp(str, "--", 2) == 0) {
            printf("Warning: unknown flag %s.\nTry --help for options\n", str);
            continue;
        } 
        
        if ( nodb )
            break;

        const char * last = strstr( str , "/" );
        if ( last )
            last++;
        else
            last = str;
        
        if ( ! strstr( last , "." ) ){
            url = str;
            continue;
        }
        
        if ( strstr( last , ".js" ) )
            break;

        path p( str );
        if ( ! boost::filesystem::exists( p ) ){
            url = str;
            continue;
        }
            

        break;
    }

    if ( !nodb ) { // init mongo code
        v8::HandleScope handle_scope;
        cout << "url: " << url << endl;
        string setup = (string)"db = connect( \"" + fixHost( url , dbhost , port ) + "\")";
        if ( ! ExecuteString( v8::String::New( setup.c_str() ) , v8::String::New( "(connect)" ) , false , true ) ){
            return -1;
        }

        if ( username.size() && password.size() ){
            stringstream ss;
            ss << "if ( ! db.auth( \"" << username << "\" , \"" << password << "\" ) ){ throw 'login failed'; }";

            if ( ! ExecuteString( v8::String::New( ss.str().c_str() ) , v8::String::New( "(auth)" ) , true , true ) ){
                cout << "login failed" << endl;
                return -1;
            }
                

        }

    }    
    
    int numFiles = 0;
    
    for ( ; argNumber < argc; argNumber++) {		//從port到這裏啦,開始解析命令行參數
        const char* str = argv[argNumber];

        v8::HandleScope handle_scope;
        v8::Handle<v8::String> file_name = v8::String::New(str);
        v8::Handle<v8::String> source = ReadFile(str);
        if (source.IsEmpty()) {
            printf("Error reading '%s'\n", str);
            return 1;
        }
        
        MongodScope s;
        if (!ExecuteString(source, file_name, false, true)){
            cout << "error processing: " << file_name << endl;
            return 1;
        }
        
        numFiles++;
    }
    
    if ( numFiles == 0 )
        runShell = true;

    if ( runShell ){
        
        MongodScope s;

	shellHistoryInit();
        
        cout << "type \"help\" for help" << endl;
        
        v8::Handle<v8::Object> shellHelper = context->Global()->Get( v8::String::New( "shellHelper" ) )->ToObject();

        while ( 1 ){
            
            char * line = shellReadline( "> " );		//這裏熟悉不???Mongo的shell就是這個開始的
            
            if ( ! line || ( strlen(line) == 4 && strstr( line , "exit" ) ) ){
                cout << "bye" << endl;
                break;
            }
            
            string code = line;
            if ( code == "exit" ){
	        break;
	    }

            {
                string cmd = line;
                if ( cmd.find( " " ) > 0 )
                    cmd = cmd.substr( 0 , cmd.find( " " ) );
                
                if ( shellHelper->HasRealNamedProperty( v8::String::New( cmd.c_str() ) ) ){
                    stringstream ss;
                    ss << "shellHelper( \"" << cmd << "\" , \"" << code.substr( cmd.size() ) << "\" )";
                    code = ss.str();
                }
                
            }

            v8::HandleScope handle_scope;
            ExecuteString(v8::String::New( code.c_str() ),
                          v8::String::New("(shell)"),
                          true,
                          true);

            
	    shellHistoryAdd( line );
        }
        
	shellHistoryDone();
    }
    
    return 0;
}


添加了幾處註釋以後,就發現這個邏輯很簡單啊,所以不虛,繼續看

char * shellReadline( const char * prompt ){
#ifdef USE_READLINE
  return readline( "> " );
#else
  printf( "> " );
  char * buf = new char[1024];
  char *l = fgets( buf , 1024 , stdin );
  int len = strlen( buf );
  buf[len-1] = 0;
  return buf;
#endif
}

這個函數中的USE_READLINE是個什麼鬼?


#ifdef _WIN32
#else
#define USE_READLINE
#endif

這樣一看,就很明瞭了,linux的機器,定義了USE_READLINE,走下面的流程,所以,mongo的shell就是使用printf將信息直接打到tty上,然後我們輸入相應的指令,解析指令,就完成了。

  • 正所謂源碼之下無祕密,所以,有什麼不懂的,看看源碼就知道了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章