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(); }
RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getRecordStore( OperationContext* txn, const StringData& ns ) { // XXX TODO - CACHE NamespaceString nss( ns ); NamespaceDetails* details = _namespaceIndex.details( ns ); if ( !details ) { return NULL; } auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns, details, _getNamespaceRecordStore( txn, ns ) ) ); if ( details->isCapped ) { return new CappedRecordStoreV1( txn, NULL, //TOD(ERH) this will blow up :) ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ); } return new SimpleRecordStoreV1( txn, ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ); }
IndexAccessMethod* MMAPV1DatabaseCatalogEntry::getIndex( OperationContext* txn, const CollectionCatalogEntry* collection, IndexCatalogEntry* entry ) { const string& type = entry->descriptor()->getAccessMethodName(); string ns = collection->ns().ns(); if ( IndexNames::TEXT == type || entry->descriptor()->getInfoElement("expireAfterSeconds").isNumber() ) { NamespaceDetailsRSV1MetaData md( ns, _namespaceIndex.details( ns ), _getNamespaceRecordStore() ); md.setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); } RecordStore* rs = NULL; { boost::mutex::scoped_lock lk( _collectionsLock ); string ns = entry->descriptor()->indexNamespace(); Entry*& entry = _collections[ns]; if ( !entry ) { entry = new Entry(); _fillInEntry_inlock( txn, ns, entry ); } rs = entry->recordStore.get(); } std::auto_ptr<BtreeInterface> btree( BtreeInterface::getInterface(entry->headManager(), rs, entry->ordering(), entry->descriptor()->indexNamespace(), entry->descriptor()->version(), &BtreeBasedAccessMethod::invalidateCursors)); if (IndexNames::HASHED == type) return new HashAccessMethod( entry, btree.release() ); if (IndexNames::GEO_2DSPHERE == type) return new S2AccessMethod( entry, btree.release() ); if (IndexNames::TEXT == type) return new FTSAccessMethod( entry, btree.release() ); if (IndexNames::GEO_HAYSTACK == type) return new HaystackAccessMethod( entry, btree.release() ); if ("" == type) return new BtreeAccessMethod( entry, btree.release() ); if (IndexNames::GEO_2D == type) return new TwoDAccessMethod( entry, btree.release() ); log() << "Can't find index for keyPattern " << entry->descriptor()->keyPattern(); fassertFailed(17489); }
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() ); }
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; } } }
IndexAccessMethod* MMAPV1DatabaseCatalogEntry::getIndex( OperationContext* txn, const CollectionCatalogEntry* collection, IndexCatalogEntry* entry ) { const string& type = entry->descriptor()->getAccessMethodName(); string ns = collection->ns().ns(); if ( IndexNames::TEXT == type || entry->descriptor()->getInfoElement("expireAfterSeconds").isNumber() ) { NamespaceDetailsRSV1MetaData md( ns, _namespaceIndex.details( ns ), _getNamespaceRecordStore( txn, ns ) ); md.setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); } RecordStore* rs = _getRecordStore( txn, entry->descriptor()->indexNamespace() ); invariant( rs ); if (IndexNames::HASHED == type) return new HashAccessMethod( entry, rs ); if (IndexNames::GEO_2DSPHERE == type) return new S2AccessMethod( entry, rs ); if (IndexNames::TEXT == type) return new FTSAccessMethod( entry, rs ); if (IndexNames::GEO_HAYSTACK == type) return new HaystackAccessMethod( entry, rs ); if ("" == type) return new BtreeAccessMethod( entry, rs ); if (IndexNames::GEO_2D == type) return new TwoDAccessMethod( entry, rs ); log() << "Can't find index for keyPattern " << entry->descriptor()->keyPattern(); fassertFailed(17489); }
Status MMAPV1DatabaseCatalogEntry::createCollection( OperationContext* txn, const StringData& ns, const CollectionOptions& options, bool allocateDefaultSpace ) { _namespaceIndex.init( 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( txn, ns ) ); 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; } if ( allocateDefaultSpace ) { scoped_ptr<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, -1 ); } } 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, -1 ); } } 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() ); sz &= 0xffffff00; rs->increaseStorageSize( txn, sz, -1 ); } while( rs->storageSize() < options.cappedSize ); } else { rs->increaseStorageSize( txn, _extentManager.initialSize( 128 ), -1 ); } } return Status::OK(); }
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(); }