void NamespaceDetails::cappedTruncateLastDelUpdate() { if ( _capExtent == _firstExtent ) { // Only one extent of the collection is in use, so there // is no deleted record in a previous extent, so nullify // cappedLastDelRecLastExtent(). cappedLastDelRecLastExtent().writing() = DiskLoc(); } else { // Scan through all deleted records in the collection // until the last deleted record for the extent prior // to the new capExtent is found. Then set // cappedLastDelRecLastExtent() to that deleted record. DiskLoc i = cappedListOfAllDeletedRecords(); for( ; !i.drec()->nextDeleted().isNull() && !inCapExtent( i.drec()->nextDeleted() ); i = i.drec()->nextDeleted() ); // In our capped storage model, every extent must have at least one // deleted record. Here we check that 'i' is not the last deleted // record. (We expect that there will be deleted records in the new // capExtent as well.) verify( !i.drec()->nextDeleted().isNull() ); cappedLastDelRecLastExtent().writing() = i; } }
DiskLoc NamespaceDetails::__capAlloc( int len ) { DiskLoc prev = cappedLastDelRecLastExtent(); DiskLoc i = cappedFirstDeletedInCurExtent(); DiskLoc ret; for (; !i.isNull() && inCapExtent( i ); prev = i, i = i.drec()->nextDeleted() ) { // We need to keep at least one DR per extent in cappedListOfAllDeletedRecords(), // so make sure there's space to create a DR at the end. if ( i.drec()->lengthWithHeaders() >= len + 24 ) { ret = i; break; } } /* unlink ourself from the deleted list */ if ( !ret.isNull() ) { if ( prev.isNull() ) cappedListOfAllDeletedRecords().writing() = ret.drec()->nextDeleted(); else prev.drec()->nextDeleted().writing() = ret.drec()->nextDeleted(); ret.drec()->nextDeleted().writing().setInvalid(); // defensive. verify( ret.drec()->extentOfs() < ret.getOfs() ); } return ret; }
bool NamespaceDetails::nextIsInCapExtent( const DiskLoc &dl ) const { verify( !dl.isNull() ); DiskLoc next = dl.drec()->nextDeleted(); if ( next.isNull() ) return false; return inCapExtent( next ); }
/* combine adjacent deleted records *for the current extent* of the capped collection this is O(n^2) but we call it for capped tables where typically n==1 or 2! (or 3...there will be a little unused sliver at the end of the extent.) */ void NamespaceDetails::compact() { DDD( "NamespaceDetails::compact enter" ); verify( isCapped() ); vector<DiskLoc> drecs; // Pull out capExtent's DRs from deletedList DiskLoc i = cappedFirstDeletedInCurExtent(); for (; !i.isNull() && inCapExtent( i ); i = i.drec()->nextDeleted() ) { DDD( "\t" << i ); drecs.push_back( i ); } getDur().writingDiskLoc( cappedFirstDeletedInCurExtent() ) = i; std::sort( drecs.begin(), drecs.end() ); DDD( "\t drecs.size(): " << drecs.size() ); vector<DiskLoc>::const_iterator j = drecs.begin(); verify( j != drecs.end() ); DiskLoc a = *j; while ( 1 ) { j++; if ( j == drecs.end() ) { DDD( "\t compact adddelrec" ); addDeletedRec(a.drec(), a); break; } DiskLoc b = *j; while ( a.a() == b.a() && a.getOfs() + a.drec()->lengthWithHeaders() == b.getOfs() ) { // a & b are adjacent. merge. getDur().writingInt( a.drec()->lengthWithHeaders() ) += b.drec()->lengthWithHeaders(); j++; if ( j == drecs.end() ) { DDD( "\t compact adddelrec2" ); addDeletedRec(a.drec(), a); return; } b = *j; } DDD( "\t compact adddelrec3" ); addDeletedRec(a.drec(), a); a = b; } }
/* combine adjacent deleted records *for the current extent* of the capped collection this is O(n^2) but we call it for capped tables where typically n==1 or 2! (or 3...there will be a little unused sliver at the end of the extent.) */ void NamespaceDetails::compact() { assert(capped); list<DiskLoc> drecs; // Pull out capExtent's DRs from deletedList DiskLoc i = cappedFirstDeletedInCurExtent(); for (; !i.isNull() && inCapExtent( i ); i = i.drec()->nextDeleted ) drecs.push_back( i ); getDur().writingDiskLoc( cappedFirstDeletedInCurExtent() ) = i; // This is the O(n^2) part. drecs.sort(); list<DiskLoc>::iterator j = drecs.begin(); assert( j != drecs.end() ); DiskLoc a = *j; while ( 1 ) { j++; if ( j == drecs.end() ) { DEBUGGING out() << "TEMP: compact adddelrec\n"; addDeletedRec(a.drec(), a); break; } DiskLoc b = *j; while ( a.a() == b.a() && a.getOfs() + a.drec()->lengthWithHeaders == b.getOfs() ) { // a & b are adjacent. merge. getDur().writingInt( a.drec()->lengthWithHeaders ) += b.drec()->lengthWithHeaders; j++; if ( j == drecs.end() ) { DEBUGGING out() << "temp: compact adddelrec2\n"; addDeletedRec(a.drec(), a); return; } b = *j; } DEBUGGING out() << "temp: compact adddelrec3\n"; addDeletedRec(a.drec(), a); a = b; } }
/* everything from end on, eliminate from the capped collection. @param inclusive if true, deletes end (i.e. closed or open range) */ void NamespaceDetails::cappedTruncateAfter(const char *ns, DiskLoc end, bool inclusive) { DEV assert( this == nsdetails(ns) ); assert( cappedLastDelRecLastExtent().isValid() ); bool foundLast = false; while( 1 ) { if ( foundLast ) { break; } DiskLoc curr = theCapExtent()->lastRecord; assert( !curr.isNull() ); if ( curr == end ) { if ( inclusive ) { foundLast = true; } else { break; } } uassert( 13415, "emptying the collection is not allowed", stats.nrecords > 1 ); if ( !capLooped() ) { theDataFileMgr.deleteRecord(ns, curr.rec(), curr, true); compact(); if ( theCapExtent()->lastRecord.isNull() ) { assert( !theCapExtent()->xprev.isNull() ); capExtent = theCapExtent()->xprev; theCapExtent()->assertOk(); if ( capExtent == firstExtent ) { cappedLastDelRecLastExtent() = DiskLoc(); } else { // slow - there's no prev ptr for deleted rec DiskLoc i = cappedListOfAllDeletedRecords(); for( ; !i.drec()->nextDeleted.isNull() && !inCapExtent( i.drec()->nextDeleted ); i = i.drec()->nextDeleted ); assert( !i.drec()->nextDeleted.isNull() ); // I believe there is always at least one drec per extent cappedLastDelRecLastExtent() = i; } } continue; } theDataFileMgr.deleteRecord(ns, curr.rec(), curr, true); compact(); if ( curr == capFirstNewRecord ) { // invalid, but can compare locations capExtent = ( capExtent == firstExtent ) ? lastExtent : theCapExtent()->xprev; theCapExtent()->assertOk(); assert( !theCapExtent()->firstRecord.isNull() ); capFirstNewRecord = theCapExtent()->firstRecord; if ( capExtent == firstExtent ) { cappedLastDelRecLastExtent() = DiskLoc(); } else { // slow - there's no prev ptr for deleted rec DiskLoc i = cappedListOfAllDeletedRecords(); for( ; !i.drec()->nextDeleted.isNull() && !inCapExtent( i.drec()->nextDeleted ); i = i.drec()->nextDeleted ); assert( !i.drec()->nextDeleted.isNull() ); // I believe there is always at least one drec per extent cappedLastDelRecLastExtent() = i; } } } }