summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2013-09-03 23:34:32 -0400
committerEliot Horowitz <eliot@10gen.com>2013-09-04 14:31:23 -0400
commit5f40281d1463a4925086b29567499924dec04889 (patch)
tree7ad98ad0527172c5400c73496c9e6e97850a7530
parentf38124f816483a2e87c3056d161035d3d1013a15 (diff)
downloadmongo-5f40281d1463a4925086b29567499924dec04889.tar.gz
SERVER-6405: move rename into database
-rw-r--r--jstests/rename.js1
-rw-r--r--src/mongo/db/commands/rename_collection.cpp8
-rw-r--r--src/mongo/db/database.cpp141
-rw-r--r--src/mongo/db/database.h11
-rw-r--r--src/mongo/db/namespace_details.cpp83
-rw-r--r--src/mongo/db/namespace_details.h5
6 files changed, 152 insertions, 97 deletions
diff --git a/jstests/rename.js b/jstests/rename.js
index d475cc6247a..51b74047288 100644
--- a/jstests/rename.js
+++ b/jstests/rename.js
@@ -23,6 +23,7 @@ assert.eq( 2, b.find().count() );
assert( db.system.namespaces.findOne( {name:"test.jstests_rename_b" } ) );
assert( !db.system.namespaces.findOne( {name:"test.jstests_rename_a" } ) );
assert.eq( 3, db.system.indexes.find( {ns:"test.jstests_rename_b"} ).count() );
+assert.eq( 0, db.system.indexes.find( {ns:"test.jstests_rename_a"} ).count() );
assert( b.find( {a:1} ).explain().cursor.match( /^BtreeCursor/ ) );
// now try renaming a capped collection
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