1. 程式人生 > >Mongodb原始碼分析--刪除記錄

Mongodb原始碼分析--刪除記錄

//query.cpp檔案 128行/* ns:      要刪除的表集合(namespace, e.g. <database>.<collection>)
       pattern: 刪除條件,相當於 "where" 字語(clause / criteria)
       justOne: 是否僅刪除第一個匹配物件資訊
       god:     是否允許訪問系統名空間(system namespaces)
    
*/longlong deleteObjects(constchar*ns, BSONObj pattern, bool justOneOrig, 
bool logop, bool god, RemoveSaver * rs ) {
        
if!god ) {//如果不能訪問system空間,但卻刪除該空間資訊時if ( strstr(ns, ".system.") ) {
                
/* note a delete from system.indexes would corrupt the db. if done here, as there are pointers into those objects in NamespaceDetails.
                
*/
                uassert(
12050"cannot delete from system namespace", legalClientSystemNS( ns , true ) );
            }
            
if ( strchr( ns , '$' ) ) {
                log() 
<<"cannot delete from collection with reserved $ in name: "<< ns << endl;
                uassert( 
10100 ,  "cannot delete from collection with reserved $ in name
", strchr(ns, '$'==0 );
            }
        }

        NamespaceDetails 
*= nsdetails( ns );//獲取名空間詳細資訊if ( ! d )
            
return0;
        uassert( 
10101 ,  "can't remove from a capped collection" , ! d->capped );//確保當前collection不是capped型別(該型別集合會自動刪除舊資料)longlong nDeleted =0;

        
int best =0;
        shared_ptr
< MultiCursor::CursorOp > opPtr( new DeleteOp( justOneOrig, best ) );//構造“刪除操作”例項物件並用其構造遊標操作(符)例項        shared_ptr< MultiCursor > creal( new MultiCursor( ns, pattern, BSONObj(), opPtr, !god ) );//構造MultiCursor查詢遊標(參見構造方法中的 nextClause()語句)if!creal->ok() )//如果查詢遊標指向地址是否正常(主要判斷是否null),因為系統會根據上面遊標初始資訊決定使用什麼樣的方式進行資訊查詢(比如是否使用B樹索引等)return nDeleted;

        shared_ptr
< Cursor > cPtr = creal;
        auto_ptr
<ClientCursor> cc( new ClientCursor( QueryOption_NoCursorTimeout, cPtr, ns) );//將遊標封裝以便下面遍歷使用        cc->setDoingDeletes( true );//設定_doingDeletes(刪除中)標誌
        CursorId id 
= cc->cursorid();

        
bool justOne = justOneOrig;
        
bool canYield =!god &&!creal->matcher()->docMatcher().atomic();

        
do {
            
if ( canYield &&! cc->yieldSometimes() ) {//檢視是否已到期(每個cc都會有一個讀寫操作時間,該值取決子獲取讀寫鎖時系統分配的時間,詳見client.cpp 檔案中的方法 int Client::recommendedYieldMicros( int * writers , int * readers ) {)                cc.release(); // 時間已到則釋放該物件(意味著已在別的地方被刪除?)
                
// TODO should we assert or something?break;
            }
            
if ( !cc->ok() ) {
                
break// if we yielded, could have hit the end            }

            
// this way we can avoid calling updateLocation() every time (expensive)
            
// as well as some other nuances handled            cc->setDoingDeletes( true );

            DiskLoc rloc 
= cc->currLoc();//遊標當前所指向的記錄所在地址            BSONObj key = cc->currKey();//遊標當前所指向的記錄的key

            
// NOTE Calling advance() may change the matcher, so it's important
            
// to try to match first.bool match = creal->matcher()->matches( key , rloc );//將當前遊標指向的記錄與遊標中的where條件進行比較if ( ! cc->advance() )//遊標移到下一個記錄位置                justOne =true;

            
if ( ! match )
                
continue;

            assert( 
!cc->c()->getsetdup(rloc) ); //不允許複本, 因為在多鍵值索引中可能會返回複本if ( !justOne ) {
                
/* NOTE: this is SLOW.  this is not good, noteLocation() was designed to be called across getMore
                    blocks.  here we might call millions of times which would be bad.
                    
*/
                cc
->c()->noteLocation();//記錄當前遊標移動到的位置            }

            
if ( logop ) {//是否儲存操作日誌                BSONElement e;
                
if( BSONObj( rloc.rec() ).getObjectID( e ) ) {
                    BSONObjBuilder b;
                    b.append( e );
                    
bool replJustOne =true;
                    logOp( 
"d", ns, b.done(), 0&replJustOne );//d表示delete                }
                
else {
                    problem() 
<<"deleted object without id, not logging"<< endl;
                }
            }

            
if ( rs )//將刪除記錄的bson objects 資訊儲存到磁碟檔案上                rs->goingToDelete( rloc.obj() /*cc->c->current()*/ );

            theDataFileMgr.deleteRecord(ns, rloc.rec(), rloc);
//刪除查詢匹配到的記錄            nDeleted++;//累計刪除資訊數if ( justOne ) {
                
break;
            }
            cc
->c()->checkLocation();//因為刪除完記錄好,會造成快取中相關索引資訊過期,用該方法能確保索引有效if!god )
                getDur().commitIfNeeded();

            
if( debug && god && nDeleted ==100 ) //刪除100條資訊之後,顯示記憶體使用預警資訊                log() <<"warning high number of deletes with god=true which could use significant memory"<< endl;
        }
        
while ( cc->ok() );

        
if ( cc.get() && ClientCursor::find( id , false ) ==0 ) {//再次在btree bucket中查詢,如沒有找到,表示記錄已全部被刪除            cc.release();
        }

        
return nDeleted;//返回已刪除的記錄數    }