mongodb原始碼分析(二)
阿新 • • 發佈:2019-01-23
在之前的2篇文章中分別分析了mongod和mongo的啟動流程,下面開始將分析mongodb的查詢,由於查詢部分流程比較長,將分成mongo端的請求,mongod端的資料庫的載入,mongod query的選取,mongod文件的匹配與資料的響應幾部分來分析。
首先進入mongo的查詢請求部分.mongo的查詢請求部分歸納起來很簡單就是將請求分裝成一個Message結構,然後將其傳送到服務端,等待服務端的相應資料,取得資料最後顯示結果.下面來看具體流程分析吧.
當我們點選db.coll.find({x:1})時按照上一篇文章的講解,我們首先來到了mongo/shell/dbshell.cpp
- if ( ! wascmd ) {
- try {
- if ( scope->exec( code.c_str() , "(shell)" , false , true , false ) )//執行相應的javascript程式碼
- scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false );
- }
- catch ( std::exception& e ) {
-
cout << "error:"
- }
- }
-
//這裡因為我們只設置了query,所以其它選項都是空的,this.getQueryOptions()目前只有一個SlaveOK的option,在replset模式下是不能查詢secondary伺服器的,需要呼叫rs.SlaveOK()之後才能對secondary進行查詢,其執行SlaveOK後每次查詢時都會新增一個QueryOption.
- DBCollection.prototype.find = function (query, fields, limit, skip, batchSize, options) {
- returnnew DBQuery( this._mongo , this._db , this ,
- this._fullName , this._massageObject( query ) , fields , limit , skip , batchSize , options || this.getQueryOptions() );
- }
- JSBool dbquery_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- try {
- smuassert( cx , "DDQuery needs at least 4 args" , argc >= 4 );
- n style="white-space:pre"> </span> //整個程式碼都是建立一個DBQuery物件,並未進行任何的查詢請求動作
- Convertor c(cx);
- c.setProperty( obj , "_mongo" , argv[0] );
- c.setProperty( obj , "_db" , argv[1] );
- c.setProperty( obj , "_collection" , argv[2] );
- c.setProperty( obj , "_ns" , argv[3] );
- if ( argc > 4 && JSVAL_IS_OBJECT( argv[4] ) )
- c.setProperty( obj , "_query" , argv[4] );
- else {
- JSObject * temp = JS_NewObject( cx , 0 , 0 , 0 );
- CHECKNEWOBJECT( temp, cx, "dbquery_constructor" );
- c.setProperty( obj , "_query" , OBJECT_TO_JSVAL( temp ) );
- }
- if ( argc > 5 && JSVAL_IS_OBJECT( argv[5] ) )
- c.setProperty( obj , "_fields" , argv[5] );
- else
- c.setProperty( obj , "_fields" , JSVAL_NULL );
- if ( argc > 6 && JSVAL_IS_NUMBER( argv[6] ) )
- c.setProperty( obj , "_limit" , argv[6] );
- else
- c.setProperty( obj , "_limit" , JSVAL_ZERO );
- if ( argc > 7 && JSVAL_IS_NUMBER( argv[7] ) )
- c.setProperty( obj , "_skip" , argv[7] );
- else
- c.setProperty( obj , "_skip" , JSVAL_ZERO );
- if ( argc > 8 && JSVAL_IS_NUMBER( argv[8] ) )
- c.setProperty( obj , "_batchSize" , argv[8] );
- else
- c.setProperty( obj , "_batchSize" , JSVAL_ZERO );
- if ( argc > 9 && JSVAL_IS_NUMBER( argv[9] ) )
- c.setProperty( obj , "_options" , argv[9] );
- else
- c.setProperty( obj , "_options" , JSVAL_ZERO );
- c.setProperty( obj , "_cursor" , JSVAL_NULL );
- c.setProperty( obj , "_numReturned" , JSVAL_ZERO );
- c.setProperty( obj , "_special" , JSVAL_FALSE );
- }
- catch ( const AssertionException& e ) {
- if ( ! JS_IsExceptionPending( cx ) ) {
- JS_ReportError( cx, e.what() );
- }
- return JS_FALSE;
- }
- catch ( const std::exception& e ) {
- log() << "unhandled exception: " << e.what() << ", throwing Fatal Assertion" << endl;
- fassertFailed( 16323 );
- }
- return JS_TRUE;
- }
- try {
- if ( scope->exec( code.c_str() , "(shell)" , false , true , false ) )//執行相應的javascript程式碼
- scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false );
- }
- bool exec( const StringData& code,const string& name = "(anon)",bool printResult = false,bool reportError = true, bool assertOnError = true,int timeoutMs = 0 ) {
- JSBool worked = JS_EvaluateScript( _context,
- _global,
- code.data(),
- code.size(),
- name.c_str(),
- 1,
- &ret );
- if ( worked )
- _convertor->setProperty( _global , "__lastres__" , ret );
- }
- shellPrintHelper = function (x) {
- if (typeof (x) == "undefined") {
- // Make sure that we have a db var before we use it
- // TODO: This implicit calling of GLE can cause subtle, hard to track issues - remove?
- if (__callLastError && typeof( db ) != "undefined" && db.getMongo ) {
- __callLastError = false;