diff options
Diffstat (limited to 'src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp | 1016 |
1 files changed, 497 insertions, 519 deletions
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp index 7bfaee1867e..12801124b95 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp @@ -47,631 +47,609 @@ namespace mongo { - using std::numeric_limits; - - DummyRecordStoreV1MetaData::DummyRecordStoreV1MetaData( bool capped, int userFlags ) { - _dataSize = 0; - _numRecords = 0; - _capped = capped; - _userFlags = userFlags; - _lastExtentSize = 0; - _paddingFactor = 1; - _maxCappedDocs = numeric_limits<long long>::max(); - _capFirstNewRecord.setInvalid(); - if ( _capped ) { - // copied from NamespaceDetails::NamespaceDetails() - setDeletedListEntry( NULL, 1, DiskLoc().setInvalid() ); - } - } - - const DiskLoc& DummyRecordStoreV1MetaData::capExtent() const { - return _capExtent; - } - - void DummyRecordStoreV1MetaData::setCapExtent( OperationContext* txn, - const DiskLoc& loc ) { - _capExtent = loc; - } - - const DiskLoc& DummyRecordStoreV1MetaData::capFirstNewRecord() const { - return _capFirstNewRecord; - } - - void DummyRecordStoreV1MetaData::setCapFirstNewRecord( OperationContext* txn, - const DiskLoc& loc ) { - _capFirstNewRecord = loc; - } - - long long DummyRecordStoreV1MetaData::dataSize() const { - return _dataSize; +using std::numeric_limits; + +DummyRecordStoreV1MetaData::DummyRecordStoreV1MetaData(bool capped, int userFlags) { + _dataSize = 0; + _numRecords = 0; + _capped = capped; + _userFlags = userFlags; + _lastExtentSize = 0; + _paddingFactor = 1; + _maxCappedDocs = numeric_limits<long long>::max(); + _capFirstNewRecord.setInvalid(); + if (_capped) { + // copied from NamespaceDetails::NamespaceDetails() + setDeletedListEntry(NULL, 1, DiskLoc().setInvalid()); } +} - long long DummyRecordStoreV1MetaData::numRecords() const { - return _numRecords; - } +const DiskLoc& DummyRecordStoreV1MetaData::capExtent() const { + return _capExtent; +} - void DummyRecordStoreV1MetaData::incrementStats( OperationContext* txn, - long long dataSizeIncrement, - long long numRecordsIncrement ) { - _dataSize += dataSizeIncrement; - _numRecords += numRecordsIncrement; - } +void DummyRecordStoreV1MetaData::setCapExtent(OperationContext* txn, const DiskLoc& loc) { + _capExtent = loc; +} - void DummyRecordStoreV1MetaData::setStats( OperationContext* txn, - long long dataSize, - long long numRecords ) { - _dataSize = dataSize; - _numRecords = numRecords; - } +const DiskLoc& DummyRecordStoreV1MetaData::capFirstNewRecord() const { + return _capFirstNewRecord; +} - namespace { - DiskLoc myNull; - } +void DummyRecordStoreV1MetaData::setCapFirstNewRecord(OperationContext* txn, const DiskLoc& loc) { + _capFirstNewRecord = loc; +} - DiskLoc DummyRecordStoreV1MetaData::deletedListEntry( int bucket ) const { - invariant( bucket >= 0 ); - if ( static_cast<size_t>( bucket ) >= _deletedLists.size() ) - return myNull; - return _deletedLists[bucket]; - } +long long DummyRecordStoreV1MetaData::dataSize() const { + return _dataSize; +} - void DummyRecordStoreV1MetaData::setDeletedListEntry( OperationContext* txn, - int bucket, - const DiskLoc& loc ) { - invariant( bucket >= 0 ); - invariant( bucket < 1000 ); - while ( static_cast<size_t>( bucket ) >= _deletedLists.size() ) - _deletedLists.push_back( DiskLoc() ); - _deletedLists[bucket] = loc; - } +long long DummyRecordStoreV1MetaData::numRecords() const { + return _numRecords; +} - DiskLoc DummyRecordStoreV1MetaData::deletedListLegacyGrabBag() const { - return _deletedListLegacyGrabBag; - } +void DummyRecordStoreV1MetaData::incrementStats(OperationContext* txn, + long long dataSizeIncrement, + long long numRecordsIncrement) { + _dataSize += dataSizeIncrement; + _numRecords += numRecordsIncrement; +} - void DummyRecordStoreV1MetaData::setDeletedListLegacyGrabBag(OperationContext* txn, - const DiskLoc& loc) { - _deletedListLegacyGrabBag = loc; - } +void DummyRecordStoreV1MetaData::setStats(OperationContext* txn, + long long dataSize, + long long numRecords) { + _dataSize = dataSize; + _numRecords = numRecords; +} - void DummyRecordStoreV1MetaData::orphanDeletedList(OperationContext* txn) { - // They will be recreated on demand. - _deletedLists.clear(); - } +namespace { +DiskLoc myNull; +} - const DiskLoc& DummyRecordStoreV1MetaData::firstExtent(OperationContext* txn) const { - return _firstExtent; - } +DiskLoc DummyRecordStoreV1MetaData::deletedListEntry(int bucket) const { + invariant(bucket >= 0); + if (static_cast<size_t>(bucket) >= _deletedLists.size()) + return myNull; + return _deletedLists[bucket]; +} - void DummyRecordStoreV1MetaData::setFirstExtent( OperationContext* txn, - const DiskLoc& loc ) { - _firstExtent = loc; - } +void DummyRecordStoreV1MetaData::setDeletedListEntry(OperationContext* txn, + int bucket, + const DiskLoc& loc) { + invariant(bucket >= 0); + invariant(bucket < 1000); + while (static_cast<size_t>(bucket) >= _deletedLists.size()) + _deletedLists.push_back(DiskLoc()); + _deletedLists[bucket] = loc; +} - const DiskLoc& DummyRecordStoreV1MetaData::lastExtent(OperationContext* txn) const { - return _lastExtent; - } +DiskLoc DummyRecordStoreV1MetaData::deletedListLegacyGrabBag() const { + return _deletedListLegacyGrabBag; +} - void DummyRecordStoreV1MetaData::setLastExtent( OperationContext* txn, - const DiskLoc& loc ) { - _lastExtent = loc; - } +void DummyRecordStoreV1MetaData::setDeletedListLegacyGrabBag(OperationContext* txn, + const DiskLoc& loc) { + _deletedListLegacyGrabBag = loc; +} - bool DummyRecordStoreV1MetaData::isCapped() const { - return _capped; - } +void DummyRecordStoreV1MetaData::orphanDeletedList(OperationContext* txn) { + // They will be recreated on demand. + _deletedLists.clear(); +} - bool DummyRecordStoreV1MetaData::isUserFlagSet( int flag ) const { - return _userFlags & flag; - } +const DiskLoc& DummyRecordStoreV1MetaData::firstExtent(OperationContext* txn) const { + return _firstExtent; +} - bool DummyRecordStoreV1MetaData::setUserFlag( OperationContext* txn, int flag ) { - if ( ( _userFlags & flag ) == flag ) - return false; +void DummyRecordStoreV1MetaData::setFirstExtent(OperationContext* txn, const DiskLoc& loc) { + _firstExtent = loc; +} - _userFlags |= flag; - return true; +const DiskLoc& DummyRecordStoreV1MetaData::lastExtent(OperationContext* txn) const { + return _lastExtent; +} - } - bool DummyRecordStoreV1MetaData::clearUserFlag( OperationContext* txn, int flag ) { - if ( ( _userFlags & flag ) == 0 ) - return false; +void DummyRecordStoreV1MetaData::setLastExtent(OperationContext* txn, const DiskLoc& loc) { + _lastExtent = loc; +} - _userFlags &= ~flag; - return true; +bool DummyRecordStoreV1MetaData::isCapped() const { + return _capped; +} - } - bool DummyRecordStoreV1MetaData::replaceUserFlags( OperationContext* txn, int flags ) { - if ( _userFlags == flags ) - return false; - _userFlags = flags; - return true; - } +bool DummyRecordStoreV1MetaData::isUserFlagSet(int flag) const { + return _userFlags & flag; +} +bool DummyRecordStoreV1MetaData::setUserFlag(OperationContext* txn, int flag) { + if ((_userFlags & flag) == flag) + return false; - int DummyRecordStoreV1MetaData::lastExtentSize(OperationContext* txn) const { - return _lastExtentSize; - } + _userFlags |= flag; + return true; +} +bool DummyRecordStoreV1MetaData::clearUserFlag(OperationContext* txn, int flag) { + if ((_userFlags & flag) == 0) + return false; - void DummyRecordStoreV1MetaData::setLastExtentSize( OperationContext* txn, int newMax ) { - _lastExtentSize = newMax; - } + _userFlags &= ~flag; + return true; +} +bool DummyRecordStoreV1MetaData::replaceUserFlags(OperationContext* txn, int flags) { + if (_userFlags == flags) + return false; + _userFlags = flags; + return true; +} - long long DummyRecordStoreV1MetaData::maxCappedDocs() const { - return _maxCappedDocs; - } - // ----------------------------------------- +int DummyRecordStoreV1MetaData::lastExtentSize(OperationContext* txn) const { + return _lastExtentSize; +} - DummyExtentManager::~DummyExtentManager() { - for ( size_t i = 0; i < _extents.size(); i++ ) { - if ( _extents[i].data ) - free( _extents[i].data ); - } - } +void DummyRecordStoreV1MetaData::setLastExtentSize(OperationContext* txn, int newMax) { + _lastExtentSize = newMax; +} - Status DummyExtentManager::init(OperationContext* txn) { - return Status::OK(); - } +long long DummyRecordStoreV1MetaData::maxCappedDocs() const { + return _maxCappedDocs; +} - int DummyExtentManager::numFiles() const { - return static_cast<int>( _extents.size() ); - } +// ----------------------------------------- - long long DummyExtentManager::fileSize() const { - invariant( false ); - return -1; +DummyExtentManager::~DummyExtentManager() { + for (size_t i = 0; i < _extents.size(); i++) { + if (_extents[i].data) + free(_extents[i].data); } +} - DiskLoc DummyExtentManager::allocateExtent( OperationContext* txn, - bool capped, - int size, - bool enforceQuota ) { - size = quantizeExtentSize( size ); +Status DummyExtentManager::init(OperationContext* txn) { + return Status::OK(); +} - ExtentInfo info; - info.data = static_cast<char*>( mongoMalloc( size ) ); - info.length = size; +int DummyExtentManager::numFiles() const { + return static_cast<int>(_extents.size()); +} - DiskLoc loc( _extents.size(), 0 ); - _extents.push_back( info ); +long long DummyExtentManager::fileSize() const { + invariant(false); + return -1; +} - Extent* e = getExtent( loc, false ); - e->magic = Extent::extentSignature; - e->myLoc = loc; - e->xnext.Null(); - e->xprev.Null(); - e->length = size; - e->firstRecord.Null(); - e->lastRecord.Null(); +DiskLoc DummyExtentManager::allocateExtent(OperationContext* txn, + bool capped, + int size, + bool enforceQuota) { + size = quantizeExtentSize(size); + + ExtentInfo info; + info.data = static_cast<char*>(mongoMalloc(size)); + info.length = size; + + DiskLoc loc(_extents.size(), 0); + _extents.push_back(info); + + Extent* e = getExtent(loc, false); + e->magic = Extent::extentSignature; + e->myLoc = loc; + e->xnext.Null(); + e->xprev.Null(); + e->length = size; + e->firstRecord.Null(); + e->lastRecord.Null(); + + return loc; +} - return loc; +void DummyExtentManager::freeExtents(OperationContext* txn, DiskLoc firstExt, DiskLoc lastExt) { + // XXX +} - } +void DummyExtentManager::freeExtent(OperationContext* txn, DiskLoc extent) { + // XXX +} +void DummyExtentManager::freeListStats(OperationContext* txn, + int* numExtents, + int64_t* totalFreeSizeBytes) const { + invariant(false); +} - void DummyExtentManager::freeExtents( OperationContext* txn, - DiskLoc firstExt, DiskLoc lastExt ) { - // XXX - } +std::unique_ptr<RecordFetcher> DummyExtentManager::recordNeedsFetch(const DiskLoc& loc) const { + return {}; +} - void DummyExtentManager::freeExtent( OperationContext* txn, DiskLoc extent ) { - // XXX - } - void DummyExtentManager::freeListStats(OperationContext* txn, - int* numExtents, - int64_t* totalFreeSizeBytes) const { - invariant(false); - } +MmapV1RecordHeader* DummyExtentManager::recordForV1(const DiskLoc& loc) const { + if (static_cast<size_t>(loc.a()) >= _extents.size()) + return NULL; + if (static_cast<size_t>(loc.getOfs()) >= _extents[loc.a()].length) + return NULL; + char* root = _extents[loc.a()].data; + return reinterpret_cast<MmapV1RecordHeader*>(root + loc.getOfs()); +} - std::unique_ptr<RecordFetcher> DummyExtentManager::recordNeedsFetch(const DiskLoc& loc) const { - return {}; - } +Extent* DummyExtentManager::extentForV1(const DiskLoc& loc) const { + invariant(false); +} - MmapV1RecordHeader* DummyExtentManager::recordForV1( const DiskLoc& loc ) const { - if ( static_cast<size_t>( loc.a() ) >= _extents.size() ) - return NULL; - if ( static_cast<size_t>( loc.getOfs() ) >= _extents[loc.a()].length ) - return NULL; - char* root = _extents[loc.a()].data; - return reinterpret_cast<MmapV1RecordHeader*>( root + loc.getOfs() ); - } +DiskLoc DummyExtentManager::extentLocForV1(const DiskLoc& loc) const { + return DiskLoc(loc.a(), 0); +} - Extent* DummyExtentManager::extentForV1( const DiskLoc& loc ) const { - invariant( false ); - } +Extent* DummyExtentManager::getExtent(const DiskLoc& loc, bool doSanityCheck) const { + invariant(!loc.isNull()); + invariant(static_cast<size_t>(loc.a()) < _extents.size()); + invariant(loc.getOfs() == 0); + Extent* ext = reinterpret_cast<Extent*>(_extents[loc.a()].data); + if (doSanityCheck) + ext->assertOk(); + return ext; +} - DiskLoc DummyExtentManager::extentLocForV1( const DiskLoc& loc ) const { - return DiskLoc( loc.a(), 0 ); - } +int DummyExtentManager::maxSize() const { + return 1024 * 1024 * 64; +} - Extent* DummyExtentManager::getExtent( const DiskLoc& loc, bool doSanityCheck ) const { - invariant( !loc.isNull() ); - invariant( static_cast<size_t>( loc.a() ) < _extents.size() ); - invariant( loc.getOfs() == 0 ); - Extent* ext = reinterpret_cast<Extent*>( _extents[loc.a()].data ); - if (doSanityCheck) - ext->assertOk(); - return ext; - } +DummyExtentManager::CacheHint* DummyExtentManager::cacheHint(const DiskLoc& extentLoc, + const HintType& hint) { + return new CacheHint(); +} - int DummyExtentManager::maxSize() const { - return 1024 * 1024 * 64; - } +namespace { +void accumulateExtentSizeRequirements(const LocAndSize* las, std::map<int, size_t>* sizes) { + if (!las) + return; - DummyExtentManager::CacheHint* DummyExtentManager::cacheHint( const DiskLoc& extentLoc, const HintType& hint ) { - return new CacheHint(); - } + while (!las->loc.isNull()) { + // We require passed in offsets to be > 1000 to leave room for Extent headers. + invariant(Extent::HeaderSize() < 1000); + invariant(las->loc.getOfs() >= 1000); -namespace { - void accumulateExtentSizeRequirements(const LocAndSize* las, std::map<int, size_t>* sizes) { - if (!las) - return; - - while (!las->loc.isNull()) { - // We require passed in offsets to be > 1000 to leave room for Extent headers. - invariant(Extent::HeaderSize() < 1000); - invariant(las->loc.getOfs() >= 1000); - - const size_t end = las->loc.getOfs() + las->size; - size_t& sizeNeeded = (*sizes)[las->loc.a()]; - sizeNeeded = std::max(sizeNeeded, end); - las++; - } + const size_t end = las->loc.getOfs() + las->size; + size_t& sizeNeeded = (*sizes)[las->loc.a()]; + sizeNeeded = std::max(sizeNeeded, end); + las++; } +} - void printRecList(OperationContext* txn, - const ExtentManager* em, - const RecordStoreV1MetaData* md) { - log() << " *** BEGIN ACTUAL RECORD LIST *** "; - DiskLoc extLoc = md->firstExtent(txn); - std::set<DiskLoc> seenLocs; - while (!extLoc.isNull()) { - Extent* ext = em->getExtent(extLoc, true); - DiskLoc actualLoc = ext->firstRecord; - while (!actualLoc.isNull()) { - const MmapV1RecordHeader* actualRec = em->recordForV1(actualLoc); - const int actualSize = actualRec->lengthWithHeaders(); - - log() << "loc: " << actualLoc // <--hex - << " (" << actualLoc.getOfs() << ")" - << " size: " << actualSize - << " prev: " << actualRec->prevOfs() - << " next: " << actualRec->nextOfs() - << (actualLoc == md->capFirstNewRecord() ? " (CAP_FIRST_NEW)" : "") - ; - - const bool foundCycle = !seenLocs.insert(actualLoc).second; - invariant(!foundCycle); - - const int nextOfs = actualRec->nextOfs(); - actualLoc = (nextOfs == DiskLoc::NullOfs ? DiskLoc() - : DiskLoc(actualLoc.a(), nextOfs)); - } - extLoc = ext->xnext; +void printRecList(OperationContext* txn, const ExtentManager* em, const RecordStoreV1MetaData* md) { + log() << " *** BEGIN ACTUAL RECORD LIST *** "; + DiskLoc extLoc = md->firstExtent(txn); + std::set<DiskLoc> seenLocs; + while (!extLoc.isNull()) { + Extent* ext = em->getExtent(extLoc, true); + DiskLoc actualLoc = ext->firstRecord; + while (!actualLoc.isNull()) { + const MmapV1RecordHeader* actualRec = em->recordForV1(actualLoc); + const int actualSize = actualRec->lengthWithHeaders(); + + log() << "loc: " << actualLoc // <--hex + << " (" << actualLoc.getOfs() << ")" + << " size: " << actualSize << " prev: " << actualRec->prevOfs() + << " next: " << actualRec->nextOfs() + << (actualLoc == md->capFirstNewRecord() ? " (CAP_FIRST_NEW)" : ""); + + const bool foundCycle = !seenLocs.insert(actualLoc).second; + invariant(!foundCycle); + + const int nextOfs = actualRec->nextOfs(); + actualLoc = (nextOfs == DiskLoc::NullOfs ? DiskLoc() : DiskLoc(actualLoc.a(), nextOfs)); } - log() << " *** END ACTUAL RECORD LIST *** "; + extLoc = ext->xnext; } + log() << " *** END ACTUAL RECORD LIST *** "; +} - void printDRecList(const ExtentManager* em, const RecordStoreV1MetaData* md) { - log() << " *** BEGIN ACTUAL DELETED RECORD LIST *** "; - std::set<DiskLoc> seenLocs; - for (int bucketIdx = 0; bucketIdx < RecordStoreV1Base::Buckets; bucketIdx++) { - DiskLoc actualLoc = md->deletedListEntry(bucketIdx); - while (!actualLoc.isNull()) { - const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); - const int actualSize = actualDrec->lengthWithHeaders(); +void printDRecList(const ExtentManager* em, const RecordStoreV1MetaData* md) { + log() << " *** BEGIN ACTUAL DELETED RECORD LIST *** "; + std::set<DiskLoc> seenLocs; + for (int bucketIdx = 0; bucketIdx < RecordStoreV1Base::Buckets; bucketIdx++) { + DiskLoc actualLoc = md->deletedListEntry(bucketIdx); + while (!actualLoc.isNull()) { + const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); + const int actualSize = actualDrec->lengthWithHeaders(); - log() << "loc: " << actualLoc // <--hex - << " (" << actualLoc.getOfs() << ")" - << " size: " << actualSize - << " bucket: " << bucketIdx - << " next: " << actualDrec->nextDeleted(); + log() << "loc: " << actualLoc // <--hex + << " (" << actualLoc.getOfs() << ")" + << " size: " << actualSize << " bucket: " << bucketIdx + << " next: " << actualDrec->nextDeleted(); - const bool foundCycle = !seenLocs.insert(actualLoc).second; - invariant(!foundCycle); + const bool foundCycle = !seenLocs.insert(actualLoc).second; + invariant(!foundCycle); - actualLoc = actualDrec->nextDeleted(); - } - - // Only print bucket 0 in capped collections since it contains all deleted records - if (md->isCapped()) - break; + actualLoc = actualDrec->nextDeleted(); } - log() << " *** END ACTUAL DELETED RECORD LIST *** "; + + // Only print bucket 0 in capped collections since it contains all deleted records + if (md->isCapped()) + break; } + log() << " *** END ACTUAL DELETED RECORD LIST *** "; +} } - void initializeV1RS(OperationContext* txn, - const LocAndSize* records, - const LocAndSize* drecs, - const LocAndSize* legacyGrabBag, - DummyExtentManager* em, - DummyRecordStoreV1MetaData* md) { - invariant(records || drecs); // if both are NULL nothing is being created... - - // Need to start with a blank slate - invariant(em->numFiles() == 0); - invariant(md->firstExtent(txn).isNull()); - - // pre-allocate extents (even extents that aren't part of this RS) - { - typedef std::map<int, size_t> ExtentSizes; - ExtentSizes extentSizes; - accumulateExtentSizeRequirements(records, &extentSizes); - accumulateExtentSizeRequirements(drecs, &extentSizes); - accumulateExtentSizeRequirements(legacyGrabBag, &extentSizes); - invariant(!extentSizes.empty()); - - const int maxExtent = extentSizes.rbegin()->first; - for (int i = 0; i <= maxExtent; i++) { - const size_t size = extentSizes.count(i) ? extentSizes[i] : 0; - const DiskLoc loc = em->allocateExtent(txn, md->isCapped(), size, 0); - - // This function and assertState depend on these details of DummyExtentManager - invariant(loc.a() == i); - invariant(loc.getOfs() == 0); - } - - // link together extents that should be part of this RS - md->setFirstExtent(txn, DiskLoc(extentSizes.begin()->first, 0)); - md->setLastExtent(txn, DiskLoc(extentSizes.rbegin()->first, 0)); - for (ExtentSizes::iterator it = extentSizes.begin(); - boost::next(it) != extentSizes.end(); /* ++it */ ) { - const int a = it->first; - ++it; - const int b = it->first; - em->getExtent(DiskLoc(a, 0))->xnext = DiskLoc(b, 0); - em->getExtent(DiskLoc(b, 0))->xprev = DiskLoc(a, 0); - } +void initializeV1RS(OperationContext* txn, + const LocAndSize* records, + const LocAndSize* drecs, + const LocAndSize* legacyGrabBag, + DummyExtentManager* em, + DummyRecordStoreV1MetaData* md) { + invariant(records || drecs); // if both are NULL nothing is being created... + + // Need to start with a blank slate + invariant(em->numFiles() == 0); + invariant(md->firstExtent(txn).isNull()); + + // pre-allocate extents (even extents that aren't part of this RS) + { + typedef std::map<int, size_t> ExtentSizes; + ExtentSizes extentSizes; + accumulateExtentSizeRequirements(records, &extentSizes); + accumulateExtentSizeRequirements(drecs, &extentSizes); + accumulateExtentSizeRequirements(legacyGrabBag, &extentSizes); + invariant(!extentSizes.empty()); + + const int maxExtent = extentSizes.rbegin()->first; + for (int i = 0; i <= maxExtent; i++) { + const size_t size = extentSizes.count(i) ? extentSizes[i] : 0; + const DiskLoc loc = em->allocateExtent(txn, md->isCapped(), size, 0); + + // This function and assertState depend on these details of DummyExtentManager + invariant(loc.a() == i); + invariant(loc.getOfs() == 0); + } - // This signals "done allocating new extents". - if (md->isCapped()) - md->setDeletedListEntry(txn, 1, DiskLoc()); + // link together extents that should be part of this RS + md->setFirstExtent(txn, DiskLoc(extentSizes.begin()->first, 0)); + md->setLastExtent(txn, DiskLoc(extentSizes.rbegin()->first, 0)); + for (ExtentSizes::iterator it = extentSizes.begin(); boost::next(it) != extentSizes.end(); + /* ++it */) { + const int a = it->first; + ++it; + const int b = it->first; + em->getExtent(DiskLoc(a, 0))->xnext = DiskLoc(b, 0); + em->getExtent(DiskLoc(b, 0))->xprev = DiskLoc(a, 0); } - if (records && !records[0].loc.isNull()) { - int recIdx = 0; - DiskLoc extLoc = md->firstExtent(txn); - while (!extLoc.isNull()) { - Extent* ext = em->getExtent(extLoc); - int prevOfs = DiskLoc::NullOfs; - while (extLoc.a() == records[recIdx].loc.a()) { // for all records in this extent - const DiskLoc loc = records[recIdx].loc; - const int size = records[recIdx].size;; - invariant(size >= MmapV1RecordHeader::HeaderSize); + // This signals "done allocating new extents". + if (md->isCapped()) + md->setDeletedListEntry(txn, 1, DiskLoc()); + } - md->incrementStats(txn, size - MmapV1RecordHeader::HeaderSize, 1); + if (records && !records[0].loc.isNull()) { + int recIdx = 0; + DiskLoc extLoc = md->firstExtent(txn); + while (!extLoc.isNull()) { + Extent* ext = em->getExtent(extLoc); + int prevOfs = DiskLoc::NullOfs; + while (extLoc.a() == records[recIdx].loc.a()) { // for all records in this extent + const DiskLoc loc = records[recIdx].loc; + const int size = records[recIdx].size; + ; + invariant(size >= MmapV1RecordHeader::HeaderSize); - if (ext->firstRecord.isNull()) - ext->firstRecord = loc; + md->incrementStats(txn, size - MmapV1RecordHeader::HeaderSize, 1); - MmapV1RecordHeader* rec = em->recordForV1(loc); - rec->lengthWithHeaders() = size; - rec->extentOfs() = 0; + if (ext->firstRecord.isNull()) + ext->firstRecord = loc; - rec->prevOfs() = prevOfs; - prevOfs = loc.getOfs(); + MmapV1RecordHeader* rec = em->recordForV1(loc); + rec->lengthWithHeaders() = size; + rec->extentOfs() = 0; - const DiskLoc nextLoc = records[recIdx + 1].loc; - if (nextLoc.a() == loc.a()) { // if next is in same extent - rec->nextOfs() = nextLoc.getOfs(); - } - else { - rec->nextOfs() = DiskLoc::NullOfs; - ext->lastRecord = loc; - } + rec->prevOfs() = prevOfs; + prevOfs = loc.getOfs(); - recIdx++; + const DiskLoc nextLoc = records[recIdx + 1].loc; + if (nextLoc.a() == loc.a()) { // if next is in same extent + rec->nextOfs() = nextLoc.getOfs(); + } else { + rec->nextOfs() = DiskLoc::NullOfs; + ext->lastRecord = loc; } - extLoc = ext->xnext; + + recIdx++; } - invariant(records[recIdx].loc.isNull()); + extLoc = ext->xnext; } - - if (drecs && !drecs[0].loc.isNull()) { - int drecIdx = 0; - DiskLoc* prevNextPtr = NULL; - int lastBucket = -1; - while (!drecs[drecIdx].loc.isNull()) { - const DiskLoc loc = drecs[drecIdx].loc; - const int size = drecs[drecIdx].size; - invariant(size >= MmapV1RecordHeader::HeaderSize); - const int bucket = RecordStoreV1Base::bucket(size); - - if (md->isCapped()) { - // All drecs form a single list in bucket 0 - if (prevNextPtr == NULL) { - md->setDeletedListEntry(txn, 0, loc); - } - else { - *prevNextPtr = loc; - } - - if (loc.a() < md->capExtent().a() - && drecs[drecIdx + 1].loc.a() == md->capExtent().a()) { - // Bucket 1 is known as cappedLastDelRecLastExtent - md->setDeletedListEntry(txn, 1, loc); - } - } - else if (bucket != lastBucket) { - invariant(bucket > lastBucket); // if this fails, drecs weren't sorted by bucket - md->setDeletedListEntry(txn, bucket, loc); - lastBucket = bucket; - } - else { + invariant(records[recIdx].loc.isNull()); + } + + if (drecs && !drecs[0].loc.isNull()) { + int drecIdx = 0; + DiskLoc* prevNextPtr = NULL; + int lastBucket = -1; + while (!drecs[drecIdx].loc.isNull()) { + const DiskLoc loc = drecs[drecIdx].loc; + const int size = drecs[drecIdx].size; + invariant(size >= MmapV1RecordHeader::HeaderSize); + const int bucket = RecordStoreV1Base::bucket(size); + + if (md->isCapped()) { + // All drecs form a single list in bucket 0 + if (prevNextPtr == NULL) { + md->setDeletedListEntry(txn, 0, loc); + } else { *prevNextPtr = loc; } - DeletedRecord* drec = &em->recordForV1(loc)->asDeleted(); - drec->lengthWithHeaders() = size; - drec->extentOfs() = 0; - drec->nextDeleted() = DiskLoc(); - prevNextPtr = &drec->nextDeleted(); - - drecIdx++; + if (loc.a() < md->capExtent().a() && + drecs[drecIdx + 1].loc.a() == md->capExtent().a()) { + // Bucket 1 is known as cappedLastDelRecLastExtent + md->setDeletedListEntry(txn, 1, loc); + } + } else if (bucket != lastBucket) { + invariant(bucket > lastBucket); // if this fails, drecs weren't sorted by bucket + md->setDeletedListEntry(txn, bucket, loc); + lastBucket = bucket; + } else { + *prevNextPtr = loc; } - } - if (legacyGrabBag && !legacyGrabBag[0].loc.isNull()) { - invariant(!md->isCapped()); // capped should have an empty legacy grab bag. + DeletedRecord* drec = &em->recordForV1(loc)->asDeleted(); + drec->lengthWithHeaders() = size; + drec->extentOfs() = 0; + drec->nextDeleted() = DiskLoc(); + prevNextPtr = &drec->nextDeleted(); - int grabBagIdx = 0; - DiskLoc* prevNextPtr = NULL; - while (!legacyGrabBag[grabBagIdx].loc.isNull()) { - const DiskLoc loc = legacyGrabBag[grabBagIdx].loc; - const int size = legacyGrabBag[grabBagIdx].size; - invariant(size >= MmapV1RecordHeader::HeaderSize); + drecIdx++; + } + } - if (grabBagIdx == 0) { - md->setDeletedListLegacyGrabBag(txn, loc); - } - else { - *prevNextPtr = loc; - } + if (legacyGrabBag && !legacyGrabBag[0].loc.isNull()) { + invariant(!md->isCapped()); // capped should have an empty legacy grab bag. - DeletedRecord* drec = &em->recordForV1(loc)->asDeleted(); - drec->lengthWithHeaders() = size; - drec->extentOfs() = 0; - drec->nextDeleted() = DiskLoc(); - prevNextPtr = &drec->nextDeleted(); + int grabBagIdx = 0; + DiskLoc* prevNextPtr = NULL; + while (!legacyGrabBag[grabBagIdx].loc.isNull()) { + const DiskLoc loc = legacyGrabBag[grabBagIdx].loc; + const int size = legacyGrabBag[grabBagIdx].size; + invariant(size >= MmapV1RecordHeader::HeaderSize); - grabBagIdx++; + if (grabBagIdx == 0) { + md->setDeletedListLegacyGrabBag(txn, loc); + } else { + *prevNextPtr = loc; } - } - // Make sure we set everything up as requested. - assertStateV1RS(txn, records, drecs, legacyGrabBag, em, md); + DeletedRecord* drec = &em->recordForV1(loc)->asDeleted(); + drec->lengthWithHeaders() = size; + drec->extentOfs() = 0; + drec->nextDeleted() = DiskLoc(); + prevNextPtr = &drec->nextDeleted(); + + grabBagIdx++; + } } - void assertStateV1RS(OperationContext* txn, - const LocAndSize* records, - const LocAndSize* drecs, - const LocAndSize* legacyGrabBag, - const ExtentManager* em, - const DummyRecordStoreV1MetaData* md) { - invariant(records || drecs); // if both are NULL nothing is being asserted... - - try { - if (records) { - long long dataSize = 0; - long long numRecs = 0; - - int recIdx = 0; - - DiskLoc extLoc = md->firstExtent(txn); - while (!extLoc.isNull()) { // for each Extent - Extent* ext = em->getExtent(extLoc, true); - int expectedPrevOfs = DiskLoc::NullOfs; - DiskLoc actualLoc = ext->firstRecord; - while (!actualLoc.isNull()) { // for each MmapV1RecordHeader in this Extent - const MmapV1RecordHeader* actualRec = em->recordForV1(actualLoc); - const int actualSize = actualRec->lengthWithHeaders(); - - dataSize += actualSize - MmapV1RecordHeader::HeaderSize; - numRecs += 1; - - ASSERT_EQUALS(actualLoc, records[recIdx].loc); - ASSERT_EQUALS(actualSize, records[recIdx].size); - - ASSERT_EQUALS(actualRec->extentOfs(), extLoc.getOfs()); - ASSERT_EQUALS(actualRec->prevOfs(), expectedPrevOfs); - expectedPrevOfs = actualLoc.getOfs(); - - recIdx++; - const int nextOfs = actualRec->nextOfs(); - actualLoc = (nextOfs == DiskLoc::NullOfs ? DiskLoc() - : DiskLoc(actualLoc.a(), nextOfs)); - } + // Make sure we set everything up as requested. + assertStateV1RS(txn, records, drecs, legacyGrabBag, em, md); +} - if (ext->xnext.isNull()) { - ASSERT_EQUALS(md->lastExtent(txn), extLoc); - } +void assertStateV1RS(OperationContext* txn, + const LocAndSize* records, + const LocAndSize* drecs, + const LocAndSize* legacyGrabBag, + const ExtentManager* em, + const DummyRecordStoreV1MetaData* md) { + invariant(records || drecs); // if both are NULL nothing is being asserted... - extLoc = ext->xnext; - } + try { + if (records) { + long long dataSize = 0; + long long numRecs = 0; - // both the expected and actual record lists must be done at this point - ASSERT_EQUALS(records[recIdx].loc, DiskLoc()); + int recIdx = 0; - ASSERT_EQUALS(dataSize, md->dataSize()); - ASSERT_EQUALS(numRecs, md->numRecords()); - } + DiskLoc extLoc = md->firstExtent(txn); + while (!extLoc.isNull()) { // for each Extent + Extent* ext = em->getExtent(extLoc, true); + int expectedPrevOfs = DiskLoc::NullOfs; + DiskLoc actualLoc = ext->firstRecord; + while (!actualLoc.isNull()) { // for each MmapV1RecordHeader in this Extent + const MmapV1RecordHeader* actualRec = em->recordForV1(actualLoc); + const int actualSize = actualRec->lengthWithHeaders(); - if (drecs) { - int drecIdx = 0; - for (int bucketIdx = 0; bucketIdx < RecordStoreV1Base::Buckets; bucketIdx++) { - DiskLoc actualLoc = md->deletedListEntry(bucketIdx); - - if (md->isCapped() && bucketIdx == 1) { - // In capped collections, the 2nd bucket (index 1) points to the drec before - // the first drec in the capExtent. If the capExtent is the first Extent, - // it should be Null. - - if (md->capExtent() == md->firstExtent(txn)) { - ASSERT_EQUALS(actualLoc, DiskLoc()); - } - else { - ASSERT_NOT_EQUALS(actualLoc.a(), md->capExtent().a()); - const DeletedRecord* actualDrec = - &em->recordForV1(actualLoc)->asDeleted(); - ASSERT_EQUALS(actualDrec->nextDeleted().a(), md->capExtent().a()); - } - - // Don't do normal checking of bucket 1 in capped collections. Checking - // other buckets to verify that they are Null. - continue; - } + dataSize += actualSize - MmapV1RecordHeader::HeaderSize; + numRecs += 1; - while (!actualLoc.isNull()) { - const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); - const int actualSize = actualDrec->lengthWithHeaders(); + ASSERT_EQUALS(actualLoc, records[recIdx].loc); + ASSERT_EQUALS(actualSize, records[recIdx].size); + + ASSERT_EQUALS(actualRec->extentOfs(), extLoc.getOfs()); + ASSERT_EQUALS(actualRec->prevOfs(), expectedPrevOfs); + expectedPrevOfs = actualLoc.getOfs(); + + recIdx++; + const int nextOfs = actualRec->nextOfs(); + actualLoc = + (nextOfs == DiskLoc::NullOfs ? DiskLoc() : DiskLoc(actualLoc.a(), nextOfs)); + } + + if (ext->xnext.isNull()) { + ASSERT_EQUALS(md->lastExtent(txn), extLoc); + } - ASSERT_EQUALS(actualLoc, drecs[drecIdx].loc); - ASSERT_EQUALS(actualSize, drecs[drecIdx].size); + extLoc = ext->xnext; + } - // Make sure the drec is correct - ASSERT_EQUALS(actualDrec->extentOfs(), 0); + // both the expected and actual record lists must be done at this point + ASSERT_EQUALS(records[recIdx].loc, DiskLoc()); - // in capped collections all drecs are linked into a single list in bucket 0 - ASSERT_EQUALS(bucketIdx, md->isCapped() - ? 0 - : RecordStoreV1Base::bucket(actualSize)); + ASSERT_EQUALS(dataSize, md->dataSize()); + ASSERT_EQUALS(numRecs, md->numRecords()); + } - drecIdx++; - actualLoc = actualDrec->nextDeleted(); + if (drecs) { + int drecIdx = 0; + for (int bucketIdx = 0; bucketIdx < RecordStoreV1Base::Buckets; bucketIdx++) { + DiskLoc actualLoc = md->deletedListEntry(bucketIdx); + + if (md->isCapped() && bucketIdx == 1) { + // In capped collections, the 2nd bucket (index 1) points to the drec before + // the first drec in the capExtent. If the capExtent is the first Extent, + // it should be Null. + + if (md->capExtent() == md->firstExtent(txn)) { + ASSERT_EQUALS(actualLoc, DiskLoc()); + } else { + ASSERT_NOT_EQUALS(actualLoc.a(), md->capExtent().a()); + const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); + ASSERT_EQUALS(actualDrec->nextDeleted().a(), md->capExtent().a()); } + + // Don't do normal checking of bucket 1 in capped collections. Checking + // other buckets to verify that they are Null. + continue; } - // both the expected and actual deleted lists must be done at this point - ASSERT_EQUALS(drecs[drecIdx].loc, DiskLoc()); - } - if (legacyGrabBag) { - int grabBagIdx = 0; - DiskLoc actualLoc = md->deletedListLegacyGrabBag(); while (!actualLoc.isNull()) { const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); const int actualSize = actualDrec->lengthWithHeaders(); - ASSERT_EQUALS(actualLoc, legacyGrabBag[grabBagIdx].loc); - ASSERT_EQUALS(actualSize, legacyGrabBag[grabBagIdx].size); + ASSERT_EQUALS(actualLoc, drecs[drecIdx].loc); + ASSERT_EQUALS(actualSize, drecs[drecIdx].size); + + // Make sure the drec is correct + ASSERT_EQUALS(actualDrec->extentOfs(), 0); + + // in capped collections all drecs are linked into a single list in bucket 0 + ASSERT_EQUALS(bucketIdx, + md->isCapped() ? 0 : RecordStoreV1Base::bucket(actualSize)); - grabBagIdx++; + drecIdx++; actualLoc = actualDrec->nextDeleted(); } - - // both the expected and actual deleted lists must be done at this point - ASSERT_EQUALS(legacyGrabBag[grabBagIdx].loc, DiskLoc()); - } - else { - // Unless a test is actually using the grabBag it should be empty - ASSERT_EQUALS(md->deletedListLegacyGrabBag(), DiskLoc()); } + // both the expected and actual deleted lists must be done at this point + ASSERT_EQUALS(drecs[drecIdx].loc, DiskLoc()); } - catch (...) { - // If a test fails, provide extra info to make debugging easier - printRecList(txn, em, md); - printDRecList(em, md); - throw; + + if (legacyGrabBag) { + int grabBagIdx = 0; + DiskLoc actualLoc = md->deletedListLegacyGrabBag(); + while (!actualLoc.isNull()) { + const DeletedRecord* actualDrec = &em->recordForV1(actualLoc)->asDeleted(); + const int actualSize = actualDrec->lengthWithHeaders(); + + ASSERT_EQUALS(actualLoc, legacyGrabBag[grabBagIdx].loc); + ASSERT_EQUALS(actualSize, legacyGrabBag[grabBagIdx].size); + + grabBagIdx++; + actualLoc = actualDrec->nextDeleted(); + } + + // both the expected and actual deleted lists must be done at this point + ASSERT_EQUALS(legacyGrabBag[grabBagIdx].loc, DiskLoc()); + } else { + // Unless a test is actually using the grabBag it should be empty + ASSERT_EQUALS(md->deletedListLegacyGrabBag(), DiskLoc()); } + } catch (...) { + // If a test fails, provide extra info to make debugging easier + printRecList(txn, em, md); + printDRecList(em, md); + throw; } } +} |