diff options
Diffstat (limited to 'src/mongo/db/commands/rename_collection.cpp')
-rw-r--r-- | src/mongo/db/commands/rename_collection.cpp | 220 |
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 |