summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/rename_collection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog/rename_collection.cpp')
-rw-r--r--src/mongo/db/catalog/rename_collection.cpp326
1 files changed, 159 insertions, 167 deletions
diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp
index 9c73d968e37..a077a452fb8 100644
--- a/src/mongo/db/catalog/rename_collection.cpp
+++ b/src/mongo/db/catalog/rename_collection.cpp
@@ -51,208 +51,200 @@
namespace mongo {
namespace {
- static void dropCollection(OperationContext* txn, Database* db, StringData collName) {
- WriteUnitOfWork wunit(txn);
- if (db->dropCollection(txn, collName).isOK()) {
- // ignoring failure case
- wunit.commit();
- }
+static void dropCollection(OperationContext* txn, Database* db, StringData collName) {
+ WriteUnitOfWork wunit(txn);
+ if (db->dropCollection(txn, collName).isOK()) {
+ // ignoring failure case
+ wunit.commit();
+ }
+}
+} // namespace
+
+Status renameCollection(OperationContext* txn,
+ const NamespaceString& source,
+ const NamespaceString& target,
+ bool dropTarget,
+ bool stayTemp) {
+ DisableDocumentValidation validationDisabler(txn);
+
+ ScopedTransaction transaction(txn, MODE_X);
+ Lock::GlobalWrite globalWriteLock(txn->lockState());
+ // We stay in source context the whole time. This is mostly to set the CurOp namespace.
+ OldClientContext ctx(txn, source);
+
+ bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(source);
+
+ if (userInitiatedWritesAndNotPrimary) {
+ return Status(ErrorCodes::NotMaster,
+ str::stream() << "Not primary while renaming collection " << source.ns()
+ << " to " << target.ns());
}
-} // namespace
-
- Status renameCollection(OperationContext* txn,
- const NamespaceString& source,
- const NamespaceString& target,
- bool dropTarget,
- bool stayTemp) {
- DisableDocumentValidation validationDisabler(txn);
-
- ScopedTransaction transaction(txn, MODE_X);
- Lock::GlobalWrite globalWriteLock(txn->lockState());
- // We stay in source context the whole time. This is mostly to set the CurOp namespace.
- OldClientContext ctx(txn, source);
-
- bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(source);
-
- if (userInitiatedWritesAndNotPrimary) {
- return Status(ErrorCodes::NotMaster, str::stream()
- << "Not primary while renaming collection " << source.ns()
- << " to " << target.ns());
- }
- Database* const sourceDB = dbHolder().get(txn, source.db());
- Collection* const sourceColl = sourceDB ? sourceDB->getCollection(source.ns()) : nullptr;
- if (!sourceColl) {
- return Status(ErrorCodes::NamespaceNotFound, "source namespace does not exist");
- }
+ Database* const sourceDB = dbHolder().get(txn, source.db());
+ Collection* const sourceColl = sourceDB ? sourceDB->getCollection(source.ns()) : nullptr;
+ if (!sourceColl) {
+ return Status(ErrorCodes::NamespaceNotFound, "source namespace does not exist");
+ }
- {
- // 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;
- }
+ {
+ // 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 =
- std::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";
- return Status(ErrorCodes::InvalidLength, sb.str());
- }
+ unsigned int longestAllowed =
+ std::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";
+ return Status(ErrorCodes::InvalidLength, sb.str());
}
+ }
- BackgroundOperation::assertNoBgOpInProgForNs(source.ns());
+ BackgroundOperation::assertNoBgOpInProgForNs(source.ns());
- Database* const targetDB = dbHolder().openDb(txn, target.db());
+ Database* const targetDB = dbHolder().openDb(txn, target.db());
- {
- WriteUnitOfWork wunit(txn);
+ {
+ 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 (!dropTarget) {
- printStackTrace();
- return Status(ErrorCodes::NamespaceExists, "target namespace exists");
- }
-
- Status s = targetDB->dropCollection(txn, target.ns());
- if (!s.isOK()) {
- return s;
- }
+ // 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 (!dropTarget) {
+ printStackTrace();
+ return Status(ErrorCodes::NamespaceExists, "target namespace exists");
}
- // 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.ns(), target.ns(), stayTemp);
- if (!s.isOK()) {
- return s;
- }
-
- getGlobalServiceContext()->getOpObserver()->onRenameCollection(
- txn,
- NamespaceString(source),
- NamespaceString(target),
- dropTarget,
- stayTemp);
-
- wunit.commit();
- return Status::OK();
+ Status s = targetDB->dropCollection(txn, target.ns());
+ if (!s.isOK()) {
+ return s;
+ }
+ }
+
+ // 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.ns(), target.ns(), stayTemp);
+ if (!s.isOK()) {
+ return s;
}
+ getGlobalServiceContext()->getOpObserver()->onRenameCollection(
+ txn, NamespaceString(source), NamespaceString(target), dropTarget, stayTemp);
+
wunit.commit();
+ return Status::OK();
}
- // If we get here, we are renaming across databases, so we must copy all the data and
- // indexes, then remove the source collection.
+ wunit.commit();
+ }
- // 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 = nullptr;
- {
- CollectionOptions options = sourceColl->getCatalogEntry()->getCollectionOptions(txn);
+ // If we get here, we are renaming across databases, so we must copy all the data and
+ // indexes, then remove the source collection.
- WriteUnitOfWork wunit(txn);
+ // 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 = nullptr;
+ {
+ CollectionOptions options = sourceColl->getCatalogEntry()->getCollectionOptions(txn);
- // No logOp necessary because the entire renameCollection command is one logOp.
- bool shouldReplicateWrites = txn->writesAreReplicated();
- txn->setReplicatedWrites(false);
- targetColl = targetDB->createCollection(txn, target.ns(), options,
- false); // _id index build with others later.
- txn->setReplicatedWrites(shouldReplicateWrites);
- if (!targetColl) {
- return Status(ErrorCodes::OutOfDiskSpace, "Failed to create target collection.");
- }
+ WriteUnitOfWork wunit(txn);
- wunit.commit();
+ // No logOp necessary because the entire renameCollection command is one logOp.
+ bool shouldReplicateWrites = txn->writesAreReplicated();
+ txn->setReplicatedWrites(false);
+ targetColl = targetDB->createCollection(txn,
+ target.ns(),
+ options,
+ false); // _id index build with others later.
+ txn->setReplicatedWrites(shouldReplicateWrites);
+ if (!targetColl) {
+ return Status(ErrorCodes::OutOfDiskSpace, "Failed to create target collection.");
}
- // Dismissed on success
- ScopeGuard targetCollectionDropper = MakeGuard(dropCollection, txn, targetDB, target.ns());
-
- 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);
- }
+ wunit.commit();
+ }
- {
- // Copy over all the data from source collection to target collection.
- auto cursor = sourceColl->getCursor(txn);
- while (auto record = cursor->next()) {
- txn->checkForInterrupt();
-
- const auto obj = record->data.releaseToBson();
-
- WriteUnitOfWork wunit(txn);
- // No logOp necessary because the entire renameCollection command is one logOp.
- bool shouldReplicateWrites = txn->writesAreReplicated();
- txn->setReplicatedWrites(false);
- Status status =
- targetColl->insertDocument(txn, obj, &indexer, true).getStatus();
- txn->setReplicatedWrites(shouldReplicateWrites);
- if (!status.isOK())
- return status;
- wunit.commit();
- }
+ // Dismissed on success
+ ScopeGuard targetCollectionDropper = MakeGuard(dropCollection, txn, targetDB, target.ns());
+
+ 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);
+ }
- Status status = indexer.doneInserting();
- if (!status.isOK())
- return status;
+ {
+ // Copy over all the data from source collection to target collection.
+ auto cursor = sourceColl->getCursor(txn);
+ while (auto record = cursor->next()) {
+ txn->checkForInterrupt();
- {
- // Getting here means we successfully built the target copy. We now remove the
- // source collection and finalize the rename.
- WriteUnitOfWork wunit(txn);
+ const auto obj = record->data.releaseToBson();
+ WriteUnitOfWork wunit(txn);
+ // No logOp necessary because the entire renameCollection command is one logOp.
bool shouldReplicateWrites = txn->writesAreReplicated();
txn->setReplicatedWrites(false);
- Status status = sourceDB->dropCollection(txn, source.ns());
+ Status status = targetColl->insertDocument(txn, obj, &indexer, true).getStatus();
txn->setReplicatedWrites(shouldReplicateWrites);
if (!status.isOK())
return status;
+ wunit.commit();
+ }
+ }
- indexer.commit();
+ Status status = indexer.doneInserting();
+ if (!status.isOK())
+ return status;
- getGlobalServiceContext()->getOpObserver()->onRenameCollection(
- txn,
- NamespaceString(source),
- NamespaceString(target),
- dropTarget,
- stayTemp);
+ {
+ // Getting here means we successfully built the target copy. We now remove the
+ // source collection and finalize the rename.
+ WriteUnitOfWork wunit(txn);
- wunit.commit();
- }
+ bool shouldReplicateWrites = txn->writesAreReplicated();
+ txn->setReplicatedWrites(false);
+ Status status = sourceDB->dropCollection(txn, source.ns());
+ txn->setReplicatedWrites(shouldReplicateWrites);
+ if (!status.isOK())
+ return status;
- targetCollectionDropper.Dismiss();
- return Status::OK();
+ indexer.commit();
+
+ getGlobalServiceContext()->getOpObserver()->onRenameCollection(
+ txn, NamespaceString(source), NamespaceString(target), dropTarget, stayTemp);
+
+ wunit.commit();
}
-} // namespace mongo
+ targetCollectionDropper.Dismiss();
+ return Status::OK();
+}
+
+} // namespace mongo