DiskLoc NamespaceDetails::cappedAlloc(const char *ns, int len) { if ( len > theCapExtent()->length ) { // the extent check is a way to try and improve performance uassert( 16328 , str::stream() << "document is larger than capped size " << len << " > " << storageSize() , len <= storageSize() ); } // signal done allocating new extents. if ( !cappedLastDelRecLastExtent().isValid() ) getDur().writingDiskLoc( cappedLastDelRecLastExtent() ) = DiskLoc(); verify( len < 400000000 ); int passes = 0; int maxPasses = ( len / 30 ) + 2; // 30 is about the smallest entry that could go in the oplog if ( maxPasses < 5000 ) { // this is for bacwards safety since 5000 was the old value maxPasses = 5000; } DiskLoc loc; // delete records until we have room and the max # objects limit achieved. /* this fails on a rename -- that is ok but must keep commented out */ //verify( theCapExtent()->ns == ns ); theCapExtent()->assertOk(); DiskLoc firstEmptyExtent; while ( 1 ) { if ( _stats.nrecords < maxCappedDocs() ) { loc = __capAlloc( len ); if ( !loc.isNull() ) break; } // If on first iteration through extents, don't delete anything. if ( !_capFirstNewRecord.isValid() ) { advanceCapExtent( ns ); if ( _capExtent != _firstExtent ) _capFirstNewRecord.writing().setInvalid(); // else signal done with first iteration through extents. continue; } if ( !_capFirstNewRecord.isNull() && theCapExtent()->firstRecord == _capFirstNewRecord ) { // We've deleted all records that were allocated on the previous // iteration through this extent. advanceCapExtent( ns ); continue; } if ( theCapExtent()->firstRecord.isNull() ) { if ( firstEmptyExtent.isNull() ) firstEmptyExtent = _capExtent; advanceCapExtent( ns ); if ( firstEmptyExtent == _capExtent ) { maybeComplain( ns, len ); return DiskLoc(); } continue; } DiskLoc fr = theCapExtent()->firstRecord; theDataFileMgr.deleteRecord(this, ns, fr.rec(), fr, true); // ZZZZZZZZZZZZ compact(); if( ++passes > maxPasses ) { StringBuilder sb; sb << "passes >= maxPasses in NamespaceDetails::cappedAlloc: ns: " << ns << ", len: " << len << ", maxPasses: " << maxPasses << ", _maxDocsInCapped: " << _maxDocsInCapped << ", nrecords: " << _stats.nrecords << ", datasize: " << _stats.datasize; msgasserted(10345, sb.str()); } } // Remember first record allocated on this iteration through capExtent. if ( _capFirstNewRecord.isValid() && _capFirstNewRecord.isNull() ) getDur().writingDiskLoc(_capFirstNewRecord) = loc; return loc; }
DiskLoc NamespaceDetails::cappedAlloc(const char *ns, int len) { // signal done allocating new extents. if ( !cappedLastDelRecLastExtent().isValid() ) getDur().writingDiskLoc( cappedLastDelRecLastExtent() ) = DiskLoc(); verify( len < 400000000 ); int passes = 0; int maxPasses = ( len / 30 ) + 2; // 30 is about the smallest entry that could go in the oplog if ( maxPasses < 5000 ) { // this is for bacwards safety since 5000 was the old value maxPasses = 5000; } DiskLoc loc; // delete records until we have room and the max # objects limit achieved. /* this fails on a rename -- that is ok but must keep commented out */ //verify( theCapExtent()->ns == ns ); theCapExtent()->assertOk(); DiskLoc firstEmptyExtent; while ( 1 ) { if ( stats.nrecords < max ) { loc = __capAlloc( len ); if ( !loc.isNull() ) break; } // If on first iteration through extents, don't delete anything. if ( !capFirstNewRecord.isValid() ) { advanceCapExtent( ns ); if ( capExtent != firstExtent ) capFirstNewRecord.writing().setInvalid(); // else signal done with first iteration through extents. continue; } if ( !capFirstNewRecord.isNull() && theCapExtent()->firstRecord == capFirstNewRecord ) { // We've deleted all records that were allocated on the previous // iteration through this extent. advanceCapExtent( ns ); continue; } if ( theCapExtent()->firstRecord.isNull() ) { if ( firstEmptyExtent.isNull() ) firstEmptyExtent = capExtent; advanceCapExtent( ns ); if ( firstEmptyExtent == capExtent ) { maybeComplain( ns, len ); return DiskLoc(); } continue; } DiskLoc fr = theCapExtent()->firstRecord; theDataFileMgr.deleteRecord(ns, fr.rec(), fr, true); // ZZZZZZZZZZZZ compact(); if( ++passes > maxPasses ) { log() << "passes ns:" << ns << " len:" << len << " maxPasses: " << maxPasses << '\n'; log() << "passes max:" << max << " nrecords:" << stats.nrecords << " datasize: " << stats.datasize << endl; massert( 10345 , "passes >= maxPasses in capped collection alloc", false ); } } // Remember first record allocated on this iteration through capExtent. if ( capFirstNewRecord.isValid() && capFirstNewRecord.isNull() ) getDur().writingDiskLoc(capFirstNewRecord) = loc; return loc; }