CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions( OperationContext* txn,
                                                                        const StringData& ns ) const {
        if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
            return CollectionOptions();
        }

        RecordStoreV1Base* rs = _getNamespaceRecordStore();
        invariant( rs );

        scoped_ptr<RecordIterator> it( rs->getIterator(txn) );
        while ( !it->isEOF() ) {
            DiskLoc loc = it->getNext();
            BSONObj entry = it->dataFor( loc ).toBson();
            BSONElement name = entry["name"];
            if ( name.type() == String && name.String() == ns ) {
                CollectionOptions options;
                if ( entry["options"].isABSONObj() ) {
                    Status status = options.parse( entry["options"].Obj() );
                    fassert( 18523, status );
                }
                return options;
            }
        }

        return CollectionOptions();
    }
void MMAPV1DatabaseCatalogEntry::_removeNamespaceFromNamespaceCollection(OperationContext* txn,
                                                                         StringData ns) {
    if (nsToCollectionSubstring(ns) == "system.namespaces") {
        // system.namespaces holds all the others, so it is not explicitly listed in the catalog.
        return;
    }

    auto entry = _collections.find(ns.toString());
    if (entry == _collections.end()) {
        return;
    }

    RecordStoreV1Base* rs = _getNamespaceRecordStore();
    invariant(rs);

    rs->deleteRecord(txn, entry->second->catalogEntry->getNamespacesRecordId());
}
    void MMAPV1DatabaseCatalogEntry::_addNamespaceToNamespaceCollection( OperationContext* txn,
                                                                        const StringData& ns,
                                                                        const BSONObj* options ) {
        if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
            // system.namespaces holds all the others, so it is not explicitly listed in the catalog.
            return;
        }

        BSONObjBuilder b;
        b.append("name", ns);
        if ( options && !options->isEmpty() )
            b.append("options", *options);
        BSONObj obj = b.done();

        RecordStoreV1Base* rs = _getNamespaceRecordStore( txn, ns );
        invariant( rs );
        StatusWith<DiskLoc> loc = rs->insertRecord( txn, obj.objdata(), obj.objsize(), -1 );
        massertStatusOK( loc.getStatus() );
    }
Status MMAPV1DatabaseCatalogEntry::createCollection(OperationContext* txn,
                                                    StringData ns,
                                                    const CollectionOptions& options,
                                                    bool allocateDefaultSpace) {
    if (_namespaceIndex.details(ns)) {
        return Status(ErrorCodes::NamespaceExists,
                      str::stream() << "namespace already exists: " << ns);
    }

    BSONObj optionsAsBSON = options.toBSON();
    RecordId rid = _addNamespaceToNamespaceCollection(txn, ns, &optionsAsBSON);

    _namespaceIndex.add_ns(txn, ns, DiskLoc(), options.capped);
    NamespaceDetails* details = _namespaceIndex.details(ns);

    // Set the flags.
    NamespaceDetailsRSV1MetaData(ns, details).replaceUserFlags(txn, options.flags);

    if (options.capped && options.cappedMaxDocs > 0) {
        txn->recoveryUnit()->writingInt(details->maxDocsInCapped) = options.cappedMaxDocs;
    }

    Entry*& entry = _collections[ns.toString()];
    invariant(!entry);
    txn->recoveryUnit()->registerChange(new EntryInsertion(ns, this));
    entry = new Entry();
    _insertInCache(txn, ns, rid, entry);

    if (allocateDefaultSpace) {
        RecordStoreV1Base* rs = _getRecordStore(ns);
        if (options.initialNumExtents > 0) {
            int size = _massageExtentSize(&_extentManager, options.cappedSize);
            for (int i = 0; i < options.initialNumExtents; i++) {
                rs->increaseStorageSize(txn, size, false);
            }
        } else if (!options.initialExtentSizes.empty()) {
            for (size_t i = 0; i < options.initialExtentSizes.size(); i++) {
                int size = options.initialExtentSizes[i];
                size = _massageExtentSize(&_extentManager, size);
                rs->increaseStorageSize(txn, size, false);
            }
        } else if (options.capped) {
            // normal
            do {
                // Must do this at least once, otherwise we leave the collection with no
                // extents, which is invalid.
                int sz =
                    _massageExtentSize(&_extentManager, options.cappedSize - rs->storageSize(txn));
                sz &= 0xffffff00;
                rs->increaseStorageSize(txn, sz, false);
            } while (rs->storageSize(txn) < options.cappedSize);
        } else {
            rs->increaseStorageSize(txn, _extentManager.initialSize(128), false);
        }
    }

    return Status::OK();
}
CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions(OperationContext* txn,
                                                                   RecordId rid) const {
    CollectionOptions options;

    if (rid.isNull()) {
        return options;
    }

    RecordStoreV1Base* rs = _getNamespaceRecordStore();
    invariant(rs);

    RecordData data;
    invariant(rs->findRecord(txn, rid, &data));

    if (data.releaseToBson()["options"].isABSONObj()) {
        Status status = options.parse(data.releaseToBson()["options"].Obj());
        fassert(18523, status);
    }
    return options;
}
    void MMAPV1DatabaseCatalogEntry::_removeNamespaceFromNamespaceCollection( OperationContext* txn,
                                                                             const StringData& ns ) {
        if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
            // system.namespaces holds all the others, so it is not explicitly listed in the catalog.
            return;
        }

        RecordStoreV1Base* rs = _getNamespaceRecordStore();
        invariant( rs );

        scoped_ptr<RecordIterator> it( rs->getIterator(txn) );
        while ( !it->isEOF() ) {
            DiskLoc loc = it->getNext();
            BSONObj entry = it->dataFor( loc ).toBson();
            BSONElement name = entry["name"];
            if ( name.type() == String && name.String() == ns ) {
                rs->deleteRecord( txn, loc );
                break;
            }
        }
    }
    Status MMAPV1DatabaseCatalogEntry::_renameSingleNamespace( OperationContext* txn,
                                                              const StringData& fromNS,
                                                              const StringData& toNS,
                                                              bool stayTemp ) {
        // some sanity checking
        NamespaceDetails* fromDetails = _namespaceIndex.details( fromNS );
        if ( !fromDetails )
            return Status( ErrorCodes::BadValue, "from namespace doesn't exist" );

        if ( _namespaceIndex.details( toNS ) )
            return Status( ErrorCodes::BadValue, "to namespace already exists" );

        // at this point, we haven't done anything destructive yet

        // ----
        // actually start moving
        // ----

        // this could throw, but if it does we're ok
        _namespaceIndex.add_ns( txn, toNS, fromDetails );
        NamespaceDetails* toDetails = _namespaceIndex.details( toNS );

        try {
            toDetails->copyingFrom(txn,
                                   toNS,
                                   _namespaceIndex,
                                   fromDetails); // fixes extraOffset
        }
        catch( DBException& ) {
            // could end up here if .ns is full - if so try to clean up / roll back a little
            _namespaceIndex.kill_ns( txn, toNS );
            throw;
        }

        // at this point, code .ns stuff moved

        _namespaceIndex.kill_ns( txn, fromNS );
        fromDetails = NULL;

        // fix system.namespaces
        BSONObj newSpec;
        DiskLoc oldSpecLocation;
        {

            BSONObj oldSpec;
            {
                RecordStoreV1Base* rs = _getNamespaceRecordStore( txn, fromNS );
                scoped_ptr<RecordIterator> it( rs->getIterator() );
                while ( !it->isEOF() ) {
                    DiskLoc loc = it->getNext();
                    const Record* rec = it->recordFor( loc );
                    BSONObj entry( rec->data() );
                    if ( fromNS == entry["name"].String() ) {
                        oldSpecLocation = loc;
                        oldSpec = entry.getOwned();
                        break;
                    }
                }
            }
            invariant( !oldSpec.isEmpty() );
            invariant( !oldSpecLocation.isNull() );

            BSONObjBuilder b;
            BSONObjIterator i( oldSpec.getObjectField( "options" ) );
            while( i.more() ) {
                BSONElement e = i.next();
                if ( strcmp( e.fieldName(), "create" ) != 0 ) {
                    if (stayTemp || (strcmp(e.fieldName(), "temp") != 0))
                        b.append( e );
                }
                else {
                    b << "create" << toNS;
                }
            }
            newSpec = b.obj();
        }

        _addNamespaceToNamespaceCollection( txn, toNS, newSpec.isEmpty() ? 0 : &newSpec );

        _getNamespaceRecordStore( txn, fromNS )->deleteRecord( txn, oldSpecLocation );

        return Status::OK();
    }
    Status MMAPV1DatabaseCatalogEntry::renameCollection( OperationContext* txn,
                                                        const StringData& fromNS,
                                                        const StringData& toNS,
                                                        bool stayTemp ) {
        Status s = _renameSingleNamespace( txn, fromNS, toNS, stayTemp );
        if ( !s.isOK() )
            return s;

        NamespaceDetails* details = _namespaceIndex.details( toNS );
        invariant( details );

        RecordStoreV1Base* systemIndexRecordStore = _getIndexRecordStore( txn );
        scoped_ptr<RecordIterator> it( systemIndexRecordStore->getIterator() );

        while ( !it->isEOF() ) {
            DiskLoc loc = it->getNext();
            const Record* rec = it->recordFor( loc );
            BSONObj oldIndexSpec( rec->data() );
            if ( fromNS != oldIndexSpec["ns"].valuestrsafe() )
                continue;

            BSONObj newIndexSpec;
            {
                BSONObjBuilder b;
                BSONObjIterator i( oldIndexSpec );
                while( i.more() ) {
                    BSONElement e = i.next();
                    if ( strcmp( e.fieldName(), "ns" ) != 0 )
                        b.append( e );
                    else
                        b << "ns" << toNS;
                }
                newIndexSpec = b.obj();
            }

            StatusWith<DiskLoc> newIndexSpecLoc =
                systemIndexRecordStore->insertRecord( txn,
                                                      newIndexSpec.objdata(),
                                                      newIndexSpec.objsize(),
                                                      -1 );
            if ( !newIndexSpecLoc.isOK() )
                return newIndexSpecLoc.getStatus();

            const string& indexName = oldIndexSpec.getStringField( "name" );

            {
                // fix IndexDetails pointer
                NamespaceDetailsCollectionCatalogEntry ce( toNS, details,
                                                           _getIndexRecordStore( txn ), this );
                int indexI = ce._findIndexNumber( indexName );

                IndexDetails& indexDetails = details->idx(indexI);
                *txn->recoveryUnit()->writing(&indexDetails.info) = newIndexSpecLoc.getValue(); // XXX: dur
            }

            {
                // move underlying namespac
                string oldIndexNs = IndexDescriptor::makeIndexNamespace( fromNS, indexName );
                string newIndexNs = IndexDescriptor::makeIndexNamespace( toNS, indexName );

                Status s = _renameSingleNamespace( txn, oldIndexNs, newIndexNs, false );
                if ( !s.isOK() )
                    return s;
            }

            systemIndexRecordStore->deleteRecord( txn, loc );
        }

        return Status::OK();
    }
void MMAPV1DatabaseCatalogEntry::_init(OperationContext* txn) {
    WriteUnitOfWork wunit(txn);

    // Upgrade freelist
    const NamespaceString oldFreeList(name(), "$freelist");
    NamespaceDetails* freeListDetails = _namespaceIndex.details(oldFreeList.ns());
    if (freeListDetails) {
        if (!freeListDetails->firstExtent.isNull()) {
            _extentManager.freeExtents(
                txn, freeListDetails->firstExtent, freeListDetails->lastExtent);
        }

        _namespaceIndex.kill_ns(txn, oldFreeList.ns());
    }

    DataFileVersion version = _extentManager.getFileFormat(txn);
    if (version.isCompatibleWithCurrentCode() && !version.mayHave28Freelist()) {
        // Any DB that can be opened and written to gets this flag set.
        version.setMayHave28Freelist();
        _extentManager.setFileFormat(txn, version);
    }

    const NamespaceString nsi(name(), "system.indexes");
    const NamespaceString nsn(name(), "system.namespaces");

    bool isSystemNamespacesGoingToBeNew = _namespaceIndex.details(nsn.toString()) == NULL;
    bool isSystemIndexesGoingToBeNew = _namespaceIndex.details(nsi.toString()) == NULL;

    _ensureSystemCollection(txn, nsn.toString());
    _ensureSystemCollection(txn, nsi.toString());

    if (isSystemNamespacesGoingToBeNew) {
        txn->recoveryUnit()->registerChange(new EntryInsertion(nsn.toString(), this));
    }
    if (isSystemIndexesGoingToBeNew) {
        txn->recoveryUnit()->registerChange(new EntryInsertion(nsi.toString(), this));
    }

    Entry*& indexEntry = _collections[nsi.toString()];
    Entry*& nsEntry = _collections[nsn.toString()];

    NamespaceDetails* const indexDetails = _namespaceIndex.details(nsi.toString());
    NamespaceDetails* const nsDetails = _namespaceIndex.details(nsn.toString());

    // order has to be:
    // 1) ns rs
    // 2) i rs
    // 3) catalog entries

    if (!nsEntry) {
        nsEntry = new Entry();

        NamespaceDetailsRSV1MetaData* md =
            new NamespaceDetailsRSV1MetaData(nsn.toString(), nsDetails);
        nsEntry->recordStore.reset(
            new SimpleRecordStoreV1(txn, nsn.toString(), md, &_extentManager, false));
    }

    if (!indexEntry) {
        indexEntry = new Entry();

        NamespaceDetailsRSV1MetaData* md =
            new NamespaceDetailsRSV1MetaData(nsi.toString(), indexDetails);

        indexEntry->recordStore.reset(
            new SimpleRecordStoreV1(txn, nsi.toString(), md, &_extentManager, true));
    }

    RecordId indexNamespaceId;
    if (isSystemIndexesGoingToBeNew) {
        indexNamespaceId = _addNamespaceToNamespaceCollection(txn, nsi.toString(), NULL);
    }

    if (!nsEntry->catalogEntry) {
        nsEntry->catalogEntry.reset(
            new NamespaceDetailsCollectionCatalogEntry(nsn.toString(),
                                                       nsDetails,
                                                       nsEntry->recordStore.get(),
                                                       RecordId(),
                                                       indexEntry->recordStore.get(),
                                                       this));
    }

    if (!indexEntry->catalogEntry) {
        indexEntry->catalogEntry.reset(
            new NamespaceDetailsCollectionCatalogEntry(nsi.toString(),
                                                       indexDetails,
                                                       nsEntry->recordStore.get(),
                                                       indexNamespaceId,
                                                       indexEntry->recordStore.get(),
                                                       this));
    }

    wunit.commit();

    // Now put everything in the cache of namespaces. None of the operations below do any
    // transactional operations.
    RecordStoreV1Base* rs = _getNamespaceRecordStore();
    invariant(rs);

    auto cursor = rs->getCursor(txn);
    while (auto record = cursor->next()) {
        auto ns = record->data.releaseToBson()["name"].String();
        Entry*& entry = _collections[ns];

        // The two cases where entry is not null is for system.indexes and system.namespaces,
        // which we manually instantiated above. It is OK to skip these two collections,
        // because they don't have indexes on them anyway.
        if (entry) {
            if (entry->catalogEntry->getNamespacesRecordId().isNull()) {
                entry->catalogEntry->setNamespacesRecordId(record->id);
            } else {
                invariant(entry->catalogEntry->getNamespacesRecordId() == record->id);
            }
            continue;
        }

        entry = new Entry();
        _insertInCache(txn, ns, record->id, entry);
    }
}
Status MMAPV1DatabaseCatalogEntry::renameCollection(OperationContext* txn,
                                                    StringData fromNS,
                                                    StringData toNS,
                                                    bool stayTemp) {
    Status s = _renameSingleNamespace(txn, fromNS, toNS, stayTemp);
    if (!s.isOK())
        return s;

    NamespaceDetails* details = _namespaceIndex.details(toNS);
    invariant(details);

    RecordStoreV1Base* systemIndexRecordStore = _getIndexRecordStore();
    auto cursor = systemIndexRecordStore->getCursor(txn);
    while (auto record = cursor->next()) {
        BSONObj oldIndexSpec = record->data.releaseToBson();
        if (fromNS != oldIndexSpec["ns"].valuestrsafe())
            continue;

        BSONObj newIndexSpec;
        {
            BSONObjBuilder b;
            BSONObjIterator i(oldIndexSpec);
            while (i.more()) {
                BSONElement e = i.next();
                if (strcmp(e.fieldName(), "ns") != 0)
                    b.append(e);
                else
                    b << "ns" << toNS;
            }
            newIndexSpec = b.obj();
        }

        StatusWith<RecordId> newIndexSpecLoc = systemIndexRecordStore->insertRecord(
            txn, newIndexSpec.objdata(), newIndexSpec.objsize(), false);
        if (!newIndexSpecLoc.isOK())
            return newIndexSpecLoc.getStatus();

        const std::string& indexName = oldIndexSpec.getStringField("name");

        {
            // Fix the IndexDetails pointer.
            int indexI = getCollectionCatalogEntry(toNS)->_findIndexNumber(txn, indexName);

            IndexDetails& indexDetails = details->idx(indexI);
            *txn->recoveryUnit()->writing(&indexDetails.info) =
                DiskLoc::fromRecordId(newIndexSpecLoc.getValue());
        }

        {
            // Move the underlying namespace.
            std::string oldIndexNs = IndexDescriptor::makeIndexNamespace(fromNS, indexName);
            std::string newIndexNs = IndexDescriptor::makeIndexNamespace(toNS, indexName);

            Status s = _renameSingleNamespace(txn, oldIndexNs, newIndexNs, false);
            if (!s.isOK())
                return s;
        }

        systemIndexRecordStore->deleteRecord(txn, record->id);
    }

    return Status::OK();
}
    Status MMAPV1DatabaseCatalogEntry::createCollection( OperationContext* txn,
                                                        const StringData& ns,
                                                        const CollectionOptions& options,
                                                        bool allocateDefaultSpace ) {
        _lazyInit( txn );

        if ( _namespaceIndex.details( ns ) ) {
            return Status( ErrorCodes::NamespaceExists,
                           str::stream() << "namespace already exists: " << ns );
        }

        BSONObj optionsAsBSON = options.toBSON();
        _addNamespaceToNamespaceCollection( txn, ns, &optionsAsBSON );

        _namespaceIndex.add_ns( txn, ns, DiskLoc(), options.capped );

        // allocation strategy set explicitly in flags or by server-wide default
        if ( !options.capped ) {
            NamespaceDetailsRSV1MetaData md( ns,
                                             _namespaceIndex.details( ns ),
                                             _getNamespaceRecordStore() );

            if ( options.flagsSet ) {
                md.setUserFlag( txn, options.flags );
            }
            else if ( newCollectionsUsePowerOf2Sizes ) {
                md.setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
            }
        }
        else if ( options.cappedMaxDocs > 0 ) {
            txn->recoveryUnit()->writingInt( _namespaceIndex.details( ns )->maxDocsInCapped ) =
                options.cappedMaxDocs;
        }

        {
            boost::mutex::scoped_lock lk( _collectionsLock );
            Entry*& entry = _collections[ns.toString()];
            invariant( !entry );
            entry = new Entry();
            _fillInEntry_inlock( txn, ns, entry );
        }

        if ( allocateDefaultSpace ) {
            RecordStoreV1Base* rs = _getRecordStore( txn, ns );
            if ( options.initialNumExtents > 0 ) {
                int size = _massageExtentSize( &_extentManager, options.cappedSize );
                for ( int i = 0; i < options.initialNumExtents; i++ ) {
                    rs->increaseStorageSize( txn, size, false );
                }
            }
            else if ( !options.initialExtentSizes.empty() ) {
                for ( size_t i = 0; i < options.initialExtentSizes.size(); i++ ) {
                    int size = options.initialExtentSizes[i];
                    size = _massageExtentSize( &_extentManager, size );
                    rs->increaseStorageSize( txn, size, false );
                }
            }
            else if ( options.capped ) {
                // normal
                do {
                    // Must do this at least once, otherwise we leave the collection with no
                    // extents, which is invalid.
                    int sz = _massageExtentSize( &_extentManager,
                                                 options.cappedSize - rs->storageSize(txn) );
                    sz &= 0xffffff00;
                    rs->increaseStorageSize( txn, sz, false );
                } while( rs->storageSize(txn) < options.cappedSize );
            }
            else {
                rs->increaseStorageSize( txn, _extentManager.initialSize( 128 ), false );
            }
        }

        return Status::OK();
    }