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