diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2021-02-09 15:06:07 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-09 22:47:45 +0000 |
commit | fcb69334e15e32049a45ebdcc7d2988acf441f5e (patch) | |
tree | 8211c18a65852f1d6b7c4701b9a4264a365f93b7 /src/mongo/db | |
parent | 4a732d685ffa7c29e541c5ef6fe41751c9227d18 (diff) | |
download | mongo-fcb69334e15e32049a45ebdcc7d2988acf441f5e.tar.gz |
SERVER-52542 Convert dropIndexes to IDL
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_indexes.cpp | 242 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_indexes.h | 18 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 26 | ||||
-rw-r--r-- | src/mongo/db/commands/drop_indexes.cpp | 54 | ||||
-rw-r--r-- | src/mongo/db/commands/set_feature_compatibility_version_command.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/drop_indexes.idl | 68 | ||||
-rw-r--r-- | src/mongo/db/repl/oplog.cpp | 12 |
8 files changed, 236 insertions, 201 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index ca823f10c88..1f472114232 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -577,6 +577,7 @@ env.Library( 'commands.cpp', 'drop.idl', 'drop_database.idl', + 'drop_indexes.idl', 'list_collections.idl', 'list_indexes.idl', ], diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp index 93bc44b3a0f..49b08b38b65 100644 --- a/src/mongo/db/catalog/drop_indexes.cpp +++ b/src/mongo/db/catalog/drop_indexes.cpp @@ -33,6 +33,8 @@ #include "mongo/db/catalog/drop_indexes.h" +#include <boost/algorithm/string/join.hpp> + #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -102,19 +104,17 @@ Status checkReplState(OperationContext* opCtx, */ StatusWith<const IndexDescriptor*> getDescriptorByKeyPattern(OperationContext* opCtx, const IndexCatalog* indexCatalog, - const BSONElement& keyPattern) { + const BSONObj& keyPattern) { const bool includeUnfinished = true; std::vector<const IndexDescriptor*> indexes; - indexCatalog->findIndexesByKeyPattern( - opCtx, keyPattern.embeddedObject(), includeUnfinished, &indexes); + indexCatalog->findIndexesByKeyPattern(opCtx, keyPattern, includeUnfinished, &indexes); if (indexes.empty()) { return Status(ErrorCodes::IndexNotFound, - str::stream() - << "can't find index with key: " << keyPattern.embeddedObject()); + str::stream() << "can't find index with key: " << keyPattern); } else if (indexes.size() > 1) { return Status(ErrorCodes::AmbiguousIndexKeyPattern, - str::stream() << indexes.size() << " indexes found for key: " - << keyPattern.embeddedObject() << ", identify by name instead." + str::stream() << indexes.size() << " indexes found for key: " << keyPattern + << ", identify by name instead." << " Conflicting indexes: " << indexes[0]->infoObj() << ", " << indexes[1]->infoObj()); } @@ -143,28 +143,28 @@ StatusWith<const IndexDescriptor*> getDescriptorByKeyPattern(OperationContext* o */ StatusWith<std::vector<std::string>> getIndexNames(OperationContext* opCtx, const CollectionPtr& collection, - const BSONElement& indexElem) { + const IndexArgument& index) { invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_IX)); - std::vector<std::string> indexNames; - if (indexElem.type() == String) { - std::string indexToAbort = indexElem.valuestr(); - indexNames.push_back(indexToAbort); - } else if (indexElem.type() == Object) { - auto swDescriptor = - getDescriptorByKeyPattern(opCtx, collection->getIndexCatalog(), indexElem); - if (!swDescriptor.isOK()) { - return swDescriptor.getStatus(); - } - indexNames.push_back(swDescriptor.getValue()->indexName()); - } else if (indexElem.type() == Array) { - for (auto indexNameElem : indexElem.Array()) { - invariant(indexNameElem.type() == String); - indexNames.push_back(indexNameElem.valuestr()); - } - } - - return indexNames; + return stdx::visit( + [&](auto&& arg) -> StatusWith<std::vector<std::string>> { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, std::string>) { + return {{arg}}; + } else if constexpr (std::is_same_v<T, std::vector<std::string>>) { + return arg; + } else if constexpr (std::is_same_v<T, BSONObj>) { + auto swDescriptor = + getDescriptorByKeyPattern(opCtx, collection->getIndexCatalog(), arg); + if (!swDescriptor.isOK()) { + return swDescriptor.getStatus(); + } + return {{swDescriptor.getValue()->indexName()}}; + } else { + MONGO_UNREACHABLE; + } + }, + index); } /** @@ -245,14 +245,14 @@ std::vector<UUID> abortActiveIndexBuilders(OperationContext* opCtx, return abortIndexBuildByIndexNames(opCtx, collectionUUID, indexNames); } -Status dropReadyIndexes(OperationContext* opCtx, - Collection* collection, - const std::vector<std::string>& indexNames, - BSONObjBuilder* anObjBuilder) { +void dropReadyIndexes(OperationContext* opCtx, + Collection* collection, + const std::vector<std::string>& indexNames, + DropIndexesReply* reply) { invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X)); if (indexNames.empty()) { - return Status::OK(); + return; } IndexCatalog* indexCatalog = collection->getIndexCatalog(); @@ -266,23 +266,19 @@ Status dropReadyIndexes(OperationContext* opCtx, desc->infoObj()); }); - anObjBuilder->append("msg", "non-_id indexes dropped for collection"); - return Status::OK(); + reply->setMsg("non-_id indexes dropped for collection"_sd); + return; } bool includeUnfinished = true; for (const auto& indexName : indexNames) { auto desc = indexCatalog->findIndexByName(opCtx, indexName, includeUnfinished); if (!desc) { - return Status(ErrorCodes::IndexNotFound, - str::stream() << "index not found with name [" << indexName << "]"); - } - Status status = dropIndexByDescriptor(opCtx, collection, indexCatalog, desc); - if (!status.isOK()) { - return status; + uasserted(ErrorCodes::IndexNotFound, + str::stream() << "index not found with name [" << indexName << "]"); } + uassertStatusOK(dropIndexByDescriptor(opCtx, collection, indexCatalog, desc)); } - return Status::OK(); } void assertMovePrimaryInProgress(OperationContext* opCtx, const NamespaceString& ns) { @@ -314,55 +310,45 @@ void assertMovePrimaryInProgress(OperationContext* opCtx, const NamespaceString& } // namespace -Status dropIndexes(OperationContext* opCtx, - const NamespaceString& nss, - const BSONObj& cmdObj, - BSONObjBuilder* result) { +DropIndexesReply dropIndexes(OperationContext* opCtx, + const NamespaceString& nss, + const IndexArgument& index) { // We only need to hold an intent lock to send abort signals to the active index builder(s) we // intend to abort. boost::optional<AutoGetCollection> collection; collection.emplace(opCtx, nss, MODE_IX); Database* db = collection->getDb(); - Status status = checkView(opCtx, nss, db, collection->getCollection()); - if (!status.isOK()) { - return status; - } - + uassertStatusOK(checkView(opCtx, nss, db, collection->getCollection())); const UUID collectionUUID = (*collection)->uuid(); const NamespaceStringOrUUID dbAndUUID = {nss.db().toString(), collectionUUID}; - - status = checkReplState(opCtx, dbAndUUID, collection->getCollection()); - if (!status.isOK()) { - return status; - } - + uassertStatusOK(checkReplState(opCtx, dbAndUUID, collection->getCollection())); if (!serverGlobalParams.quiet.load()) { LOGV2(51806, "CMD: dropIndexes", "namespace"_attr = nss, "uuid"_attr = collectionUUID, - "indexes"_attr = cmdObj[kIndexFieldName].toString(false)); + "indexes"_attr = stdx::visit( + [](auto&& arg) -> std::string { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, std::string>) { + return arg; + } else if constexpr (std::is_same_v<T, std::vector<std::string>>) { + return boost::algorithm::join(arg, ","); + } else if constexpr (std::is_same_v<T, BSONObj>) { + return arg.toString(); + } else { + MONGO_UNREACHABLE; + } + }, + index)); } - result->appendNumber("nIndexesWas", (*collection)->getIndexCatalog()->numIndexesTotal(opCtx)); - - // Validate basic user input. - BSONElement indexElem = cmdObj.getField(kIndexFieldName); - const bool isWildcard = indexElem.type() == String && indexElem.String() == "*"; - - // If an Array was passed in, verify that all the elements are of type String. - if (indexElem.type() == Array) { - for (auto indexNameElem : indexElem.Array()) { - if (indexNameElem.type() != String) { - return Status(ErrorCodes::TypeMismatch, - str::stream() - << "dropIndexes " << (*collection)->ns() << " (" << collectionUUID - << ") failed to drop multiple indexes " - << indexElem.toString(false) << ": index name must be a string"); - } - } - } + DropIndexesReply reply; + reply.setNIndexesWas((*collection)->getIndexCatalog()->numIndexesTotal(opCtx)); + + const bool isWildcard = + stdx::holds_alternative<std::string>(index) && stdx::get<std::string>(index) == "*"; IndexBuildsCoordinator* indexBuildsCoord = IndexBuildsCoordinator::get(opCtx); @@ -372,22 +358,18 @@ Status dropIndexes(OperationContext* opCtx, std::vector<UUID> abortedIndexBuilders; std::vector<std::string> indexNames; while (true) { - auto swIndexNames = getIndexNames(opCtx, collection->getCollection(), indexElem); - if (!swIndexNames.isOK()) { - return swIndexNames.getStatus(); - } - - indexNames = swIndexNames.getValue(); + indexNames = uassertStatusOK(getIndexNames(opCtx, collection->getCollection(), index)); // Copy the namespace and UUID before dropping locks. auto collUUID = (*collection)->uuid(); auto collNs = (*collection)->ns(); - // Release locks before aborting index builds. The helper will acquire locks on our behalf. + // Release locks before aborting index builds. The helper will acquire locks on our + // behalf. collection = boost::none; - // Send the abort signal to any index builders that match the users request. Waits until all - // aborted builders complete. + // Send the abort signal to any index builders that match the users request. Waits until + // all aborted builders complete. auto justAborted = abortActiveIndexBuilders(opCtx, collNs, collUUID, indexNames); abortedIndexBuilders.insert( abortedIndexBuilders.end(), justAborted.begin(), justAborted.end()); @@ -397,28 +379,25 @@ Status dropIndexes(OperationContext* opCtx, hangAfterAbortingIndexes.pauseWhileSet(); } - // Abandon the snapshot as the index catalog will compare the in-memory state to the disk - // state, which may have changed when we released the lock temporarily. + // Abandon the snapshot as the index catalog will compare the in-memory state to the + // disk state, which may have changed when we released the lock temporarily. opCtx->recoveryUnit()->abandonSnapshot(); - // Take an exclusive lock on the collection now to be able to perform index catalog writes - // when removing ready indexes from disk. + // Take an exclusive lock on the collection now to be able to perform index catalog + // writes when removing ready indexes from disk. collection.emplace(opCtx, dbAndUUID, MODE_X); db = collection->getDb(); if (!*collection) { - return Status(ErrorCodes::NamespaceNotFound, - str::stream() - << "Collection '" << nss << "' with UUID " << dbAndUUID.uuid() - << " in database " << dbAndUUID.db() << " does not exist."); + uasserted(ErrorCodes::NamespaceNotFound, + str::stream() << "Collection '" << nss << "' with UUID " << dbAndUUID.uuid() + << " in database " << dbAndUUID.db() << " does not exist."); } - status = checkReplState(opCtx, dbAndUUID, collection->getCollection()); - if (!status.isOK()) { - return status; - } + uassertStatusOK(checkReplState(opCtx, dbAndUUID, collection->getCollection())); - // Check to see if a new index build was started that the caller requested to be aborted. + // Check to see if a new index build was started that the caller requested to be + // aborted. bool abortAgain = false; if (isWildcard) { abortAgain = indexBuildsCoord->inProgForCollection(collectionUUID); @@ -435,15 +414,15 @@ Status dropIndexes(OperationContext* opCtx, // Drop any ready indexes that were created while we yielded our locks while aborting using // similar index specs. if (!isWildcard && !abortedIndexBuilders.empty()) { - return writeConflictRetry(opCtx, "dropIndexes", dbAndUUID.toString(), [&] { + writeConflictRetry(opCtx, "dropIndexes", dbAndUUID.toString(), [&] { WriteUnitOfWork wuow(opCtx); // This is necessary to check shard version. OldClientContext ctx(opCtx, (*collection)->ns().ns()); - // Iterate through all the aborted indexes and drop any indexes that are ready in the - // index catalog. This would indicate that while we yielded our locks during the abort - // phase, a new identical index was created. + // Iterate through all the aborted indexes and drop any indexes that are ready in + // the index catalog. This would indicate that while we yielded our locks during the + // abort phase, a new identical index was created. auto indexCatalog = collection->getWritableCollection()->getIndexCatalog(); const bool includeUnfinished = false; for (const auto& indexName : indexNames) { @@ -453,21 +432,19 @@ Status dropIndexes(OperationContext* opCtx, continue; } - Status status = - dropIndexByDescriptor(opCtx, collection->getCollection(), indexCatalog, desc); - if (!status.isOK()) { - return status; - } + uassertStatusOK( + dropIndexByDescriptor(opCtx, collection->getCollection(), indexCatalog, desc)); } wuow.commit(); - return Status::OK(); }); + + return reply; } if (!abortedIndexBuilders.empty()) { - // All the index builders were sent the abort signal, remove all the remaining indexes in - // the index catalog. + // All the index builders were sent the abort signal, remove all the remaining indexes + // in the index catalog. invariant(isWildcard); invariant(indexNames.size() == 1); invariant(indexNames.front() == "*"); @@ -478,34 +455,28 @@ Status dropIndexes(OperationContext* opCtx, IndexBuildsCoordinator::get(opCtx)->assertNoIndexBuildInProgForCollection(collectionUUID); } - return writeConflictRetry( - opCtx, "dropIndexes", dbAndUUID.toString(), [opCtx, &collection, &indexNames, result] { + writeConflictRetry( + opCtx, "dropIndexes", dbAndUUID.toString(), [opCtx, &collection, &indexNames, &reply] { WriteUnitOfWork wunit(opCtx); // This is necessary to check shard version. OldClientContext ctx(opCtx, (*collection)->ns().ns()); - - // Use an empty BSONObjBuilder to avoid duplicate appends to result on retry loops. - BSONObjBuilder tempObjBuilder; - Status status = dropReadyIndexes( - opCtx, collection->getWritableCollection(), indexNames, &tempObjBuilder); - if (!status.isOK()) { - return status; - } - + dropReadyIndexes(opCtx, collection->getWritableCollection(), indexNames, &reply); wunit.commit(); - - result->appendElementsUnique( - tempObjBuilder.done()); // This append will only happen once. - return Status::OK(); }); + + return reply; } Status dropIndexesForApplyOps(OperationContext* opCtx, const NamespaceString& nss, - const BSONObj& cmdObj, - BSONObjBuilder* result) { - return writeConflictRetry(opCtx, "dropIndexes", nss.db(), [opCtx, &nss, &cmdObj, result] { + const BSONObj& cmdObj) try { + BSONObjBuilder bob(cmdObj); + bob.append("$db", nss.db()); + auto cmdObjWithDb = bob.obj(); + auto parsed = DropIndexes::parse({"dropIndexes"}, cmdObjWithDb); + + return writeConflictRetry(opCtx, "dropIndexes", nss.db(), [opCtx, &nss, &cmdObj, &parsed] { AutoGetCollection collection(opCtx, nss, MODE_X); // If db/collection does not exist, short circuit and return. @@ -525,8 +496,7 @@ Status dropIndexesForApplyOps(OperationContext* opCtx, IndexBuildsCoordinator::get(opCtx)->assertNoIndexBuildInProgForCollection( collection->uuid()); - BSONElement indexElem = cmdObj.getField(kIndexFieldName); - auto swIndexNames = getIndexNames(opCtx, collection.getCollection(), indexElem); + auto swIndexNames = getIndexNames(opCtx, collection.getCollection(), parsed.getIndex()); if (!swIndexNames.isOK()) { return swIndexNames.getStatus(); } @@ -536,19 +506,15 @@ Status dropIndexesForApplyOps(OperationContext* opCtx, // This is necessary to check shard version. OldClientContext ctx(opCtx, nss.ns()); - // Use an empty BSONObjBuilder to avoid duplicate appends to result on retry loops. - BSONObjBuilder tempObjBuilder; - status = dropReadyIndexes( - opCtx, collection.getWritableCollection(), swIndexNames.getValue(), &tempObjBuilder); - if (!status.isOK()) { - return status; - } + DropIndexesReply ignoredReply; + dropReadyIndexes( + opCtx, collection.getWritableCollection(), swIndexNames.getValue(), &ignoredReply); wunit.commit(); - - result->appendElementsUnique(tempObjBuilder.done()); // This append will only happen once. return Status::OK(); }); +} catch (const DBException& exc) { + return exc.toStatus(); } } // namespace mongo diff --git a/src/mongo/db/catalog/drop_indexes.h b/src/mongo/db/catalog/drop_indexes.h index c465f6dab52..74b90d75384 100644 --- a/src/mongo/db/catalog/drop_indexes.h +++ b/src/mongo/db/catalog/drop_indexes.h @@ -29,34 +29,36 @@ #include "mongo/base/status.h" +#include "mongo/db/drop_indexes_gen.h" + namespace mongo { class BSONObj; class BSONObjBuilder; class NamespaceString; class OperationContext; +using IndexArgument = stdx::variant<std::string, std::vector<std::string>, mongo::BSONObj>; + /** * Drops one or more ready indexes, or aborts a single index builder from the "nss" collection that - * matches the caller's "cmdObj" input. Populates "result" with some statistics about the operation. + * matches the caller's "index" input. * - * "cmdObj" must have a field named "index" that has one of the following as its value: + * The "index" field may be: * 1) "*" <-- Aborts all index builders and drops all ready indexes except the _id index. * 2) "indexName" <-- Aborts an index builder or drops a ready index with the given name. * 3) { keyPattern } <-- Aborts an index builder or drops a ready index with a matching key pattern. * 4) ["indexName1", ..., "indexNameN"] <-- Aborts an index builder or drops ready indexes that * match the given names. */ -Status dropIndexes(OperationContext* opCtx, - const NamespaceString& nss, - const BSONObj& cmdObj, - BSONObjBuilder* result); +DropIndexesReply dropIndexes(OperationContext* opCtx, + const NamespaceString& nss, + const IndexArgument& index); /** * Same behaviour as "dropIndexes" but only drops ready indexes. */ Status dropIndexesForApplyOps(OperationContext* opCtx, const NamespaceString& nss, - const BSONObj& cmdObj, - BSONObjBuilder* result); + const BSONObj& cmdObj); } // namespace mongo diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 2d3df2eb106..813c5397ab2 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -930,6 +930,23 @@ public: } }; +namespace { +// Used in BasicCommandWithRequestParser below. +template <typename T, typename = int> +struct CommandAlias { + // An empty alias is equivalent to no alias, see CommandRegistry::registerCommand. + static constexpr StringData kAlias = ""_sd; +}; + +template <typename T> +struct CommandAlias<T, decltype((void)T::kCommandAlias, 0)> { + static constexpr StringData kAlias = T::kCommandAlias; +}; + +template <typename T> +constexpr StringData command_alias_v = CommandAlias<T>::kAlias; +} // namespace + /** * A CRTP base class for BasicCommandWithRequestParser, which simplifies writing commands that * accept requests generated by IDL to enforce API versioning and to overcome the complexity @@ -952,7 +969,8 @@ public: * * which enables it to be parsed as an IDL command. * - * - a 'constexpr StringData kCommandName' member. + * - a 'static constexpr StringData kCommandName' member. + * - (optional) a 'static constexpr StringData kCommandAlias' member. * * - validateResult: that has a custom logic to validate the result BSON object * to enforce API versioning. @@ -961,9 +979,9 @@ public: template <typename Derived> class BasicCommandWithRequestParser : public BasicCommandWithReplyBuilderInterface { protected: - // Commands that only have a single name don't need to define any constructors. BasicCommandWithRequestParser() - : BasicCommandWithReplyBuilderInterface(Derived::Request::kCommandName) {} + : BasicCommandWithReplyBuilderInterface(Derived::Request::kCommandName, + command_alias_v<typename Derived::Request>) {} bool runWithReplyBuilder(OperationContext* opCtx, const std::string& db, @@ -1003,7 +1021,7 @@ protected: auto wcStatus = getWriteConcernStatusFromCommandResult(resultObj); if (!wcStatus.isOK()) { if (wcStatus.code() == ErrorCodes::TypeMismatch) { - // Result has "writeConcerError" field but it is not valid wce object. + // Result has "writeConcernError" field but it is not valid wce object. uassertStatusOK(wcStatus); } } diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 7ddcfcbab10..9a4ef95c51f 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -34,6 +34,7 @@ #include <string> #include <vector> +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/catalog/drop_indexes.h" @@ -45,6 +46,7 @@ #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/db_raii.h" +#include "mongo/db/drop_indexes_gen.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/index_builds_coordinator.h" #include "mongo/db/op_observer.h" @@ -65,46 +67,38 @@ using std::vector; MONGO_FAIL_POINT_DEFINE(reIndexCrashAfterDrop); -/* "dropIndexes" is now the preferred form - "deleteIndexes" deprecated */ -class CmdDropIndexes : public BasicCommand { +class CmdDropIndexes : public DropIndexesCmdVersion1Gen<CmdDropIndexes> { public: - const std::set<std::string>& apiVersions() const { - return kApiVersions1; - } - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } - - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return true; - } - bool collectsResourceConsumptionMetrics() const override { return true; } - std::string help() const override { return "drop indexes for a collection"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::dropIndex); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); - } - - CmdDropIndexes() : BasicCommand("dropIndexes", "deleteIndexes") {} - bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& jsobj, - BSONObjBuilder& result) { - const NamespaceString nss = CommandHelpers::parseNsCollectionRequired(dbname, jsobj); - uassertStatusOK(dropIndexes(opCtx, nss, jsobj, &result)); - return true; - } - + class Invocation final : public InvocationBaseGen { + public: + using InvocationBaseGen::InvocationBaseGen; + bool supportsWriteConcern() const final { + return true; + } + NamespaceString ns() const final { + return request().getNamespace(); + } + void doCheckAuthorization(OperationContext* opCtx) const final { + uassert(ErrorCodes::Unauthorized, + str::stream() << "Not authorized to drop index(es) on collection" + << request().getNamespace(), + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnNamespace(request().getNamespace(), + ActionType::dropIndex)); + } + Reply typedRun(OperationContext* opCtx) final { + return dropIndexes(opCtx, request().getNamespace(), request().getIndex()); + } + }; } cmdDropIndexes; class CmdReIndex : public ErrmsgCommandDeprecated { diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp index a2c478ef871..15fe66d7c37 100644 --- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp @@ -498,21 +498,11 @@ private: continue; } - // Construct a dropIndexes command to drop the indexes in 'haystackIndexes'. - BSONObjBuilder dropIndexesCmd; - dropIndexesCmd.append("dropIndexes", collName.nss()->coll()); - BSONArrayBuilder indexNames; + std::vector<std::string> indexNames; for (auto&& haystackIndex : haystackIndexes) { - indexNames.append(haystackIndex->indexName()); + indexNames.emplace_back(haystackIndex->indexName()); } - dropIndexesCmd.append("index", indexNames.arr()); - - BSONObjBuilder response; // This response is ignored. - uassertStatusOK( - dropIndexes(opCtx, - *collName.nss(), - CommandHelpers::appendMajorityWriteConcern(dropIndexesCmd.obj()), - &response)); + dropIndexes(opCtx, *collName.nss(), indexNames); } } } diff --git a/src/mongo/db/drop_indexes.idl b/src/mongo/db/drop_indexes.idl new file mode 100644 index 00000000000..914688e4b15 --- /dev/null +++ b/src/mongo/db/drop_indexes.idl @@ -0,0 +1,68 @@ +# Copyright (C) 2021-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# <http://www.mongodb.com/licensing/server-side-public-license>. +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# + +global: + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" + +structs: + DropIndexesReply: + description: Reply to the dropIndexes command + strict: false + fields: + nIndexesWas: + description: Number of indexes on the collection at start of dropIndexes command + (mongod only) + type: int + optional: true + msg: + description: Optional message (mongod only) + type: string + optional: true + +commands: + dropIndexes: + description: "Parser for the dropIndexes command" + command_name: dropIndexes + command_alias: deleteIndexes + namespace: concatenate_with_db + cpp_name: dropIndexes + strict: true + api_version: "1" + fields: + index: + description: An index name, or array of names, or "*" for all indexes, or an index + spec (an object). + type: + variant: + - string + - array<string> + - object + reply_type: DropIndexesReply diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 126a51eae0c..251153830c5 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -910,34 +910,30 @@ const StringMap<ApplyOpMetadata> kOpsMap = { // deleteIndex(es) is deprecated but still works as of April 10, 2015 {"deleteIndex", {[](OperationContext* opCtx, const OplogEntry& entry, OplogApplication::Mode mode) -> Status { - BSONObjBuilder resultWeDontCareAbout; const auto& cmd = entry.getObject(); return dropIndexesForApplyOps( - opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd, &resultWeDontCareAbout); + opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd); }, {ErrorCodes::NamespaceNotFound, ErrorCodes::IndexNotFound}}}, {"deleteIndexes", {[](OperationContext* opCtx, const OplogEntry& entry, OplogApplication::Mode mode) -> Status { - BSONObjBuilder resultWeDontCareAbout; const auto& cmd = entry.getObject(); return dropIndexesForApplyOps( - opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd, &resultWeDontCareAbout); + opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd); }, {ErrorCodes::NamespaceNotFound, ErrorCodes::IndexNotFound}}}, {"dropIndex", {[](OperationContext* opCtx, const OplogEntry& entry, OplogApplication::Mode mode) -> Status { - BSONObjBuilder resultWeDontCareAbout; const auto& cmd = entry.getObject(); return dropIndexesForApplyOps( - opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd, &resultWeDontCareAbout); + opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd); }, {ErrorCodes::NamespaceNotFound, ErrorCodes::IndexNotFound}}}, {"dropIndexes", {[](OperationContext* opCtx, const OplogEntry& entry, OplogApplication::Mode mode) -> Status { - BSONObjBuilder resultWeDontCareAbout; const auto& cmd = entry.getObject(); return dropIndexesForApplyOps( - opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd, &resultWeDontCareAbout); + opCtx, extractNsFromUUID(opCtx, entry.getUuid().get()), cmd); }, {ErrorCodes::NamespaceNotFound, ErrorCodes::IndexNotFound}}}, {"renameCollection", |