void MMAPV1DatabaseCatalogEntry::appendExtraStats(OperationContext* opCtx,
                                                  BSONObjBuilder* output,
                                                  double scale) const {
    if (isEmpty()) {
        output->appendNumber("fileSize", 0);
    } else {
        output->appendNumber("fileSize", _extentManager.fileSize() / scale);
        output->appendNumber("nsSizeMB",
                             static_cast<int>(_namespaceIndex.fileLength() / (1024 * 1024)));

        int freeListSize = 0;
        int64_t freeListSpace = 0;
        _extentManager.freeListStats(opCtx, &freeListSize, &freeListSpace);

        BSONObjBuilder extentFreeList(output->subobjStart("extentFreeList"));
        extentFreeList.append("num", freeListSize);
        extentFreeList.appendNumber("totalSize", static_cast<long long>(freeListSpace / scale));
        extentFreeList.done();

        {
            const DataFileVersion version = _extentManager.getFileFormat(opCtx);

            BSONObjBuilder dataFileVersion(output->subobjStart("dataFileVersion"));
            dataFileVersion.append("major", version.majorRaw());
            dataFileVersion.append("minor", version.minorRaw());
            dataFileVersion.done();
        }
    }
}
bool MMAPV1DatabaseCatalogEntry::isOlderThan24(OperationContext* opCtx) const {
    if (_extentManager->numFiles() == 0)
        return false;

    const DataFileVersion version = _extentManager->getFileFormat(opCtx);
    fassert(40109, version.isCompatibleWithCurrentCode());

    return !version.is24IndexClean();
}
void MMAPV1DatabaseCatalogEntry::markCollationFeatureAsInUse(OperationContext* opCtx) {
    if (_extentManager->numFiles() == 0)
        return;

    DataFileVersion version = _extentManager->getFileFormat(opCtx);
    fassert(40150, version.isCompatibleWithCurrentCode());

    if (version.getMayHaveCollationMetadata())
        return;

    version.setMayHaveCollationMetadata();
    _extentManager->setFileFormat(opCtx, version);
}
void MMAPV1DatabaseCatalogEntry::markIndexSafe24AndUp(OperationContext* opCtx) {
    if (_extentManager->numFiles() == 0)
        return;

    DataFileVersion version = _extentManager->getFileFormat(opCtx);
    fassert(40110, version.isCompatibleWithCurrentCode());

    if (version.is24IndexClean())
        return;  // nothing to do

    version.setIs24IndexClean();
    _extentManager->setFileFormat(opCtx, version);
}
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);
    }
}