summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/rename_collection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/commands/rename_collection.cpp')
-rw-r--r--src/mongo/db/commands/rename_collection.cpp220
1 files changed, 13 insertions, 207 deletions
diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp
index 162208b73cf..2cc098bf621 100644
--- a/src/mongo/db/commands/rename_collection.cpp
+++ b/src/mongo/db/commands/rename_collection.cpp
@@ -31,6 +31,7 @@
#include "mongo/client/dbclientcursor.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/collection_catalog_entry.h"
+#include "mongo/db/catalog/rename_collection.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/catalog/index_catalog.h"
#include "mongo/db/catalog/index_create.h"
@@ -74,11 +75,10 @@ namespace mongo {
help << " example: { renameCollection: foo.a, to: bar.b }";
}
- virtual std::vector<BSONObj> stopIndexBuilds(OperationContext* opCtx,
- Database* db,
- const BSONObj& cmdObj) {
- string source = cmdObj.getStringField( name.c_str() );
- string target = cmdObj.getStringField( "to" );
+ std::vector<BSONObj> stopIndexBuilds(OperationContext* opCtx,
+ Database* db,
+ const NamespaceString& source,
+ const NamespaceString& target) {
IndexCatalog::IndexKillCriteria criteria;
criteria.ns = source;
@@ -114,20 +114,10 @@ namespace mongo {
string& errmsg,
BSONObjBuilder& result,
bool fromRepl) {
- ScopedTransaction transaction(txn, MODE_X);
- Lock::GlobalWrite globalWriteLock(txn->lockState());
+ invariant(!fromRepl == txn->writesAreReplicated());
string source = cmdObj.getStringField( name.c_str() );
string target = cmdObj.getStringField( "to" );
- if (!fromRepl &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbname)) {
- return appendCommandStatus(result, Status(ErrorCodes::NotMaster, str::stream()
- << "Not primary while renaming collection " << source << " to " << target));
- }
-
- // We stay in source context the whole time. This is mostly to set the CurOp namespace.
- OldClientContext ctx(txn, source);
-
if ( !NamespaceString::validCollectionComponent(target.c_str()) ) {
errmsg = "invalid collection name: " + target;
return false;
@@ -175,197 +165,13 @@ namespace mongo {
return false;
}
- Database* const sourceDB = dbHolder().get(txn, nsToDatabase(source));
- Collection* const sourceColl = sourceDB ? sourceDB->getCollection(source)
- : NULL;
- if (!sourceColl) {
- errmsg = "source namespace does not exist";
- return false;
- }
-
- {
- // Ensure that collection name does not exceed maximum length.
- // Ensure that index names do not push the length over the max.
- // Iterator includes unfinished indexes.
- IndexCatalog::IndexIterator sourceIndIt =
- sourceColl->getIndexCatalog()->getIndexIterator( txn, true );
- int longestIndexNameLength = 0;
- while ( sourceIndIt.more() ) {
- int thisLength = sourceIndIt.next()->indexName().length();
- if ( thisLength > longestIndexNameLength )
- longestIndexNameLength = thisLength;
- }
-
- unsigned int longestAllowed =
- min(int(NamespaceString::MaxNsCollectionLen),
- int(NamespaceString::MaxNsLen) - 2/*strlen(".$")*/ - longestIndexNameLength);
- if (target.size() > longestAllowed) {
- StringBuilder sb;
- sb << "collection name length of " << target.size()
- << " exceeds maximum length of " << longestAllowed
- << ", allowing for index names";
- errmsg = sb.str();
- return false;
- }
- }
-
- const std::vector<BSONObj> indexesInProg = stopIndexBuilds(txn, sourceDB, cmdObj);
- // Dismissed on success
- ScopeGuard indexBuildRestorer = MakeGuard(IndexBuilder::restoreIndexes,
- txn,
- indexesInProg);
-
- Database* const targetDB = dbHolder().openDb(txn, nsToDatabase(target));
-
- {
- WriteUnitOfWork wunit(txn);
-
- // Check if the target namespace exists and if dropTarget is true.
- // If target exists and dropTarget is not true, return false.
- if (targetDB->getCollection(target)) {
- if (!cmdObj["dropTarget"].trueValue()) {
- errmsg = "target namespace exists";
- return false;
- }
-
- Status s = targetDB->dropCollection(txn, target);
- if ( !s.isOK() ) {
- errmsg = s.toString();
- return false;
- }
- }
-
- // If we are renaming in the same database, just
- // rename the namespace and we're done.
- if (sourceDB == targetDB) {
- Status s = targetDB->renameCollection(txn,
- source,
- target,
- cmdObj["stayTemp"].trueValue() );
- if (!s.isOK()) {
- return appendCommandStatus(result, s);
- }
-
- if (!fromRepl) {
- getGlobalServiceContext()->getOpObserver()->onRenameCollection(
- txn,
- NamespaceString(source),
- NamespaceString(target),
- cmdObj["dropTarget"].trueValue(),
- cmdObj["stayTemp"].trueValue());
- }
-
- wunit.commit();
- indexBuildRestorer.Dismiss();
- return true;
- }
-
- wunit.commit();
- }
-
- // If we get here, we are renaming across databases, so we must copy all the data and
- // indexes, then remove the source collection.
-
- // Create the target collection. It will be removed if we fail to copy the collection.
- // TODO use a temp collection and unset the temp flag on success.
- Collection* targetColl = NULL;
- {
- CollectionOptions options;
- options.setNoIdIndex();
-
- if (sourceColl->isCapped()) {
- const CollectionOptions sourceOpts =
- sourceColl->getCatalogEntry()->getCollectionOptions(txn);
-
- options.capped = true;
- options.cappedSize = sourceOpts.cappedSize;
- options.cappedMaxDocs = sourceOpts.cappedMaxDocs;
- }
-
- WriteUnitOfWork wunit(txn);
-
- // No logOp necessary because the entire renameCollection command is one logOp.
- targetColl = targetDB->createCollection(txn, target, options);
- if (!targetColl) {
- errmsg = "Failed to create target collection.";
- return false;
- }
-
- wunit.commit();
- }
-
- // Dismissed on success
- ScopeGuard targetCollectionDropper = MakeGuard(dropCollection, txn, targetDB, target);
-
- MultiIndexBlock indexer(txn, targetColl);
- indexer.allowInterruption();
-
- // Copy the index descriptions from the source collection, adjusting the ns field.
- {
- std::vector<BSONObj> indexesToCopy;
- IndexCatalog::IndexIterator sourceIndIt =
- sourceColl->getIndexCatalog()->getIndexIterator( txn, true );
- while (sourceIndIt.more()) {
- const BSONObj currIndex = sourceIndIt.next()->infoObj();
-
- // Process the source index.
- BSONObjBuilder newIndex;
- newIndex.append("ns", target);
- newIndex.appendElementsUnique(currIndex);
- indexesToCopy.push_back(newIndex.obj());
- }
- indexer.init(indexesToCopy);
- }
-
- {
- // Copy over all the data from source collection to target collection.
- boost::scoped_ptr<RecordIterator> sourceIt(sourceColl->getIterator(txn));
- while (!sourceIt->isEOF()) {
- txn->checkForInterrupt();
-
- const Snapshotted<BSONObj> obj = sourceColl->docFor(txn, sourceIt->getNext());
-
- WriteUnitOfWork wunit(txn);
- // No logOp necessary because the entire renameCollection command is one logOp.
- Status status =
- targetColl->insertDocument(txn, obj.value(), &indexer, true).getStatus();
- if (!status.isOK())
- return appendCommandStatus(result, status);
- wunit.commit();
- }
- }
-
- Status status = indexer.doneInserting();
- if (!status.isOK())
- return appendCommandStatus(result, status);
-
- {
- // Getting here means we successfully built the target copy. We now remove the
- // source collection and finalize the rename.
- WriteUnitOfWork wunit(txn);
-
- Status status = sourceDB->dropCollection(txn, source);
- if (!status.isOK())
- return appendCommandStatus(result, status);
-
- indexer.commit();
-
- if (!fromRepl) {
- getGlobalServiceContext()->getOpObserver()->onRenameCollection(
- txn,
- NamespaceString(source),
- NamespaceString(target),
- cmdObj["dropTarget"].trueValue(),
- cmdObj["stayTemp"].trueValue());
- }
-
- wunit.commit();
- }
-
- indexBuildRestorer.Dismiss();
- targetCollectionDropper.Dismiss();
- return true;
+ return appendCommandStatus(result,
+ renameCollection(txn,
+ NamespaceString(source),
+ NamespaceString(target),
+ cmdObj["dropTarget"].trueValue(),
+ cmdObj["stayTemp"].trueValue()));
}
} cmdrenamecollection;
-}
+} // namespace mongo