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 Database::_renameSingleNamespace( const StringData& fromNS, const StringData& toNS, bool stayTemp ) { // TODO: make it so we dont't need to do this string fromNSString = fromNS.toString(); string toNSString = toNS.toString(); // 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" ); // remove anything cached { scoped_lock lk( _collectionLock ); _collections.erase( fromNSString ); _collections.erase( toNSString ); } ClientCursor::invalidate( fromNSString.c_str() ); ClientCursor::invalidate( toNSString.c_str() ); NamespaceDetailsTransient::eraseCollection( fromNSString ); // XXX NamespaceDetailsTransient::eraseCollection( toNSString ); // XXX // 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( toNS, fromDetails ); NamespaceDetails* toDetails = _namespaceIndex.details( toNS ); try { toDetails->copyingFrom(toNSString.c_str(), 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(toNSString.c_str()); throw; } // at this point, code .ns stuff moved _namespaceIndex.kill_ns( fromNSString.c_str() ); fromDetails = NULL; // fix system.namespaces BSONObj newSpec; { BSONObj oldSpec; if ( !Helpers::findOne( _namespacesName, BSON( "name" << fromNS ), oldSpec ) ) return Status( ErrorCodes::InternalError, "can't find system.namespaces entry" ); 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(); } addNewNamespaceToCatalog( toNSString.c_str(), newSpec.isEmpty() ? 0 : &newSpec ); deleteObjects( _namespacesName.c_str(), BSON( "name" << fromNS ), false, false, true ); return Status::OK(); }
Status MMAPV1DatabaseCatalogEntry::_renameSingleNamespace(OperationContext* txn, StringData fromNS, 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; RecordId oldSpecLocation = getCollectionCatalogEntry(fromNS)->getNamespacesRecordId(); invariant(!oldSpecLocation.isNull()); { BSONObj oldSpec = _getNamespaceRecordStore()->dataFor(txn, oldSpecLocation).releaseToBson(); invariant(!oldSpec.isEmpty()); 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(); } RecordId rid = _addNamespaceToNamespaceCollection(txn, toNS, newSpec.isEmpty() ? 0 : &newSpec); _getNamespaceRecordStore()->deleteRecord(txn, oldSpecLocation); Entry*& entry = _collections[toNS.toString()]; invariant(entry == NULL); txn->recoveryUnit()->registerChange(new EntryInsertion(toNS, this)); entry = new Entry(); _removeFromCache(txn->recoveryUnit(), fromNS); _insertInCache(txn, toNS, rid, entry); return Status::OK(); }