// bypass standard alloc/insert routines to use the extent we want. static DiskLoc insert( const DiskLoc& ext, int i ) { BSONObjBuilder b; b.append( "a", i ); BSONObj o = b.done(); int len = o.objsize(); Extent *e = ext.ext(); e = getDur().writing(e); int ofs; if ( e->lastRecord.isNull() ) ofs = ext.getOfs() + ( e->_extentData - (char *)e ); else ofs = e->lastRecord.getOfs() + e->lastRecord.rec()->lengthWithHeaders(); DiskLoc dl( ext.a(), ofs ); Record *r = dl.rec(); r = (Record*) getDur().writingPtr(r, Record::HeaderSize + len); r->lengthWithHeaders() = Record::HeaderSize + len; r->extentOfs() = e->myLoc.getOfs(); r->nextOfs() = DiskLoc::NullOfs; r->prevOfs() = e->lastRecord.isNull() ? DiskLoc::NullOfs : e->lastRecord.getOfs(); memcpy( r->data(), o.objdata(), len ); if ( e->firstRecord.isNull() ) e->firstRecord = dl; else getDur().writingInt(e->lastRecord.rec()->nextOfs()) = ofs; e->lastRecord = dl; return dl; }
void initializeV1RS(OperationContext* txn, const LocAndSize* records, const LocAndSize* drecs, 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().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); 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); } // This signals "done allocating new extents". if (md->isCapped()) md->setDeletedListEntry(txn, 1, DiskLoc()); } if (records && !records[0].loc.isNull()) { int recIdx = 0; DiskLoc extLoc = md->firstExtent(); 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 >= Record::HeaderSize); md->incrementStats(txn, size - Record::HeaderSize, 1); if (ext->firstRecord.isNull()) ext->firstRecord = loc; Record* rec = em->recordForV1(loc); rec->lengthWithHeaders() = size; rec->extentOfs() = 0; rec->prevOfs() = prevOfs; prevOfs = loc.getOfs(); 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; } recIdx++; } extLoc = ext->xnext; } 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 >= Record::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 { *prevNextPtr = loc; } DeletedRecord* drec = &em->recordForV1(loc)->asDeleted(); drec->lengthWithHeaders() = size; drec->extentOfs() = 0; drec->nextDeleted() = DiskLoc(); prevNextPtr = &drec->nextDeleted(); drecIdx++; } } // Make sure we set everything up as requested. assertStateV1RS(records, drecs, em, md); }
Extent* ExtentManager::extentFor( const DiskLoc& loc ) const { Record* record = recordFor( loc ); DiskLoc extentLoc( loc.a(), record->extentOfs() ); return getExtent( extentLoc ); }
DiskLoc MmapV1ExtentManager::extentLocForV1( const DiskLoc& loc ) const { Record* record = recordForV1( loc ); return DiskLoc( loc.a(), record->extentOfs() ); }