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();
}