diff options
author | Eliot Horowitz <eliot@10gen.com> | 2013-09-03 23:34:32 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2013-09-04 14:31:23 -0400 |
commit | 5f40281d1463a4925086b29567499924dec04889 (patch) | |
tree | 7ad98ad0527172c5400c73496c9e6e97850a7530 /src | |
parent | f38124f816483a2e87c3056d161035d3d1013a15 (diff) | |
download | mongo-5f40281d1463a4925086b29567499924dec04889.tar.gz |
SERVER-6405: move rename into database
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/commands/rename_collection.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/database.cpp | 141 | ||||
-rw-r--r-- | src/mongo/db/database.h | 11 | ||||
-rw-r--r-- | src/mongo/db/namespace_details.cpp | 83 | ||||
-rw-r--r-- | src/mongo/db/namespace_details.h | 5 |
5 files changed, 151 insertions, 97 deletions
diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index c30cc7b9bb8..596872f6099 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -136,9 +136,11 @@ namespace mongo { // rename the namespace and we're done. { if ( sourceDB == targetDB ) { - renameNamespace( source.c_str(), target.c_str(), cmdObj["stayTemp"].trueValue() ); - // make sure we drop counters etc - Top::global.collectionDropped( source ); + Status s = ctx.db()->renameCollection( source, target, cmdObj["stayTemp"].trueValue() ); + if ( !s.isOK() ) { + errmsg = s.toString(); + return false; + } return true; } } diff --git a/src/mongo/db/database.cpp b/src/mongo/db/database.cpp index 72fa8f70e48..3572656dd70 100644 --- a/src/mongo/db/database.cpp +++ b/src/mongo/db/database.cpp @@ -30,6 +30,7 @@ #include "mongo/db/introspect.h" #include "mongo/db/pdfile.h" #include "mongo/db/query/internal_plans.h" +#include "mongo/db/ops/delete.h" namespace mongo { @@ -89,6 +90,7 @@ namespace mongo { _namespaceIndex( _path, _name ), _extentManager( _name, _path, directoryperdb /* this is a global right now */ ), _profileName(_name + ".system.profile"), + _namespacesName(_name + ".system.namespaces"), _collectionLock( "Database::_collectionLock" ) { Status status = validateDBName( _name ); @@ -298,4 +300,143 @@ namespace mongo { return c; } + + + void addNewNamespaceToCatalog(const char *ns, const BSONObj *options = 0); // XXX + + Status Database::renameCollection( const StringData& fromNS, const StringData& toNS, + bool stayTemp ) { + + // move data namespace + Status s = _renameSingleNamespace( fromNS, toNS, stayTemp ); + if ( !s.isOK() ) + return s; + + NamespaceDetails* details = _namespaceIndex.details( toNS ); + verify( details ); + + // move index namespaces + string indexName = _name + ".system.indexes"; + BSONObj oldIndexSpec; + while( Helpers::findOne( indexName, BSON( "ns" << fromNS ), oldIndexSpec ) ) { + oldIndexSpec = oldIndexSpec.getOwned(); + + 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(); + } + + DiskLoc newIndexSpecLoc = theDataFileMgr.insert( indexName.c_str(), + newIndexSpec.objdata(), + newIndexSpec.objsize(), + false, + true, + false ); + int indexI = details->findIndexByName( oldIndexSpec.getStringField( "name" ) ); + IndexDetails &indexDetails = details->idx(indexI); + string oldIndexNs = indexDetails.indexNamespace(); + indexDetails.info = newIndexSpecLoc; + string newIndexNs = indexDetails.indexNamespace(); + + Status s = _renameSingleNamespace( oldIndexNs, newIndexNs, false ); + if ( !s.isOK() ) + return s; + + deleteObjects( indexName.c_str(), oldIndexSpec, true, false, true ); + } + + Top::global.collectionDropped( fromNS.toString() ); + + 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(); + } + } // namespace mongo diff --git a/src/mongo/db/database.h b/src/mongo/db/database.h index caa26848d2c..e09274f5bb6 100644 --- a/src/mongo/db/database.h +++ b/src/mongo/db/database.h @@ -123,6 +123,8 @@ namespace mongo { */ CollectionTemp* getCollectionTemp( const StringData& ns ); + Status renameCollection( const StringData& fromNS, const StringData& toNS, bool stayTemp ); + /** * @return name of an existing database with same text name but different * casing, if one exists. Otherwise the empty string is returned. If @@ -144,12 +146,8 @@ namespace mongo { void openAllFiles(); - /** - * throws exception if error encounted - * @return true if the file was opened - * false if no errors, but file doesn't exist - */ - bool openExistingFile( int n ); + Status _renameSingleNamespace( const StringData& fromNS, const StringData& toNS, + bool stayTemp ); const string _name; // "alleyinsider" const string _path; // "/data/db" @@ -158,6 +156,7 @@ namespace mongo { ExtentManager _extentManager; const string _profileName; // "alleyinsider.system.profile" + const string _namespacesName; // "alleyinsider.system.namespaces" CCByLoc _ccByLoc; // use by ClientCursor diff --git a/src/mongo/db/namespace_details.cpp b/src/mongo/db/namespace_details.cpp index 2787aabc940..678cf0d421c 100644 --- a/src/mongo/db/namespace_details.cpp +++ b/src/mongo/db/namespace_details.cpp @@ -925,89 +925,6 @@ namespace mongo { theDataFileMgr.insert(s.c_str(), j.objdata(), j.objsize(), false, true); } - void renameNamespace( const char *from, const char *to, bool stayTemp) { - NamespaceIndex *ni = nsindex( from ); - verify( ni ); - verify( ni->details( from ) ); - verify( ! ni->details( to ) ); - - // Our namespace and index details will move to a different - // memory location. The only references to namespace and - // index details across commands are in cursors and nsd - // transient (including query cache) so clear these. - ClientCursor::invalidate( from ); - NamespaceDetailsTransient::eraseCollection( from ); - cc().database()->dropCollection( from ); // XXX-ERH - - NamespaceDetails *details = ni->details( from ); - ni->add_ns( to, details ); - NamespaceDetails *todetails = ni->details( to ); - try { - todetails->copyingFrom(to, details); // fixes extraOffset - } - catch( DBException& ) { - // could end up here if .ns is full - if so try to clean up / roll back a little - ni->kill_ns(to); - throw; - } - ni->kill_ns( from ); - details = todetails; - - BSONObj oldSpec; - char database[MaxDatabaseNameLen]; - nsToDatabase(from, database); - string s = database; - s += ".system.namespaces"; - verify( Helpers::findOne( s.c_str(), BSON( "name" << from ), oldSpec ) ); - - BSONObjBuilder newSpecB; - 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)) - newSpecB.append( e ); - } - else { - newSpecB << "create" << to; - } - } - BSONObj newSpec = newSpecB.done(); - addNewNamespaceToCatalog( to, newSpec.isEmpty() ? 0 : &newSpec ); - - deleteObjects( s.c_str(), BSON( "name" << from ), false, false, true ); - // oldSpec variable no longer valid memory - - BSONObj oldIndexSpec; - s = database; - s += ".system.indexes"; - while( Helpers::findOne( s.c_str(), BSON( "ns" << from ), oldIndexSpec ) ) { - BSONObjBuilder newIndexSpecB; - BSONObjIterator i( oldIndexSpec ); - while( i.more() ) { - BSONElement e = i.next(); - if ( strcmp( e.fieldName(), "ns" ) != 0 ) - newIndexSpecB.append( e ); - else - newIndexSpecB << "ns" << to; - } - BSONObj newIndexSpec = newIndexSpecB.done(); - DiskLoc newIndexSpecLoc = theDataFileMgr.insert( s.c_str(), - newIndexSpec.objdata(), - newIndexSpec.objsize(), - false, - true, - false ); - int indexI = details->findIndexByName( oldIndexSpec.getStringField( "name" ) ); - IndexDetails &indexDetails = details->idx(indexI); - string oldIndexNs = indexDetails.indexNamespace(); - indexDetails.info = newIndexSpecLoc; - string newIndexNs = indexDetails.indexNamespace(); - - renameNamespace( oldIndexNs.c_str(), newIndexNs.c_str(), false ); - deleteObjects( s.c_str(), oldIndexSpec.getOwned(), true, false, true ); - } - } bool legalClientSystemNS( const string& ns , bool write ) { if( ns == "local.system.replset" ) return true; diff --git a/src/mongo/db/namespace_details.h b/src/mongo/db/namespace_details.h index 965a0e13c2c..9d4c8c3f357 100644 --- a/src/mongo/db/namespace_details.h +++ b/src/mongo/db/namespace_details.h @@ -637,9 +637,4 @@ namespace mongo { extern string dbpath; // --dbpath parm extern bool directoryperdb; - // Rename a namespace within current 'client' db. - // (Arguments should include db name) - void renameNamespace( const char *from, const char *to, bool stayTemp); - - } // namespace mongo |