diff options
author | Mathias Stearn <mathias@10gen.com> | 2015-05-11 17:36:52 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2015-05-14 18:59:03 -0400 |
commit | 463d3343d559590d60cfd5c48ac98ad675d5390e (patch) | |
tree | 5ab045f64656074016c08229ae0bcc6734579e6e /src/mongo | |
parent | 22de12dd4ac510cd2a37b643eb528673f651e21b (diff) | |
download | mongo-463d3343d559590d60cfd5c48ac98ad675d5390e.tar.gz |
SERVER-18227 Add bypassDocumentValidation option to commands that need it
Diffstat (limited to 'src/mongo')
28 files changed, 194 insertions, 43 deletions
diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt index 62120c7156e..f6c9164b1e8 100644 --- a/src/mongo/db/auth/action_types.txt +++ b/src/mongo/db/auth/action_types.txt @@ -11,6 +11,7 @@ "auditLogRotate", # Not used for permissions checks, but to id the event in logs. "authCheck", # Not used for permissions checks, but to id the authorization-checking event in logs. "authenticate", # Not used for permission checks, but to id authentication events in logs. +"bypassDocumentValidation", # For bypassDocumentValidation command option. "changeCustomData", "changePassword", "changeOwnPassword", diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp index deaee655416..479cc0de9fa 100644 --- a/src/mongo/db/auth/role_graph_builtin_roles.cpp +++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp @@ -149,6 +149,7 @@ namespace { // DB admin role dbAdminRoleActions + << ActionType::bypassDocumentValidation << ActionType::collMod << ActionType::collStats // clusterMonitor gets this also << ActionType::compact @@ -555,11 +556,15 @@ namespace { void addRestorePrivileges(PrivilegeVector* privileges) { ActionSet actions; - actions << ActionType::insert - << ActionType::dropCollection - << ActionType::createIndex - << ActionType::createCollection - << ActionType::collMod; + actions + << ActionType::bypassDocumentValidation + << ActionType::collMod + << ActionType::createCollection + << ActionType::createIndex + << ActionType::dropCollection + << ActionType::insert + ; + Privilege::addPrivilegeToPrivilegeVector( privileges, Privilege(ResourcePattern::forAnyNormalResource(), actions)); diff --git a/src/mongo/db/catalog/document_validation.h b/src/mongo/db/catalog/document_validation.h index 0f838f6184a..a0e6cb349e3 100644 --- a/src/mongo/db/catalog/document_validation.h +++ b/src/mongo/db/catalog/document_validation.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/base/disallow_copying.h" +#include "mongo/base/string_data.h" #include "mongo/db/operation_context.h" namespace mongo { @@ -39,6 +40,14 @@ namespace mongo { */ extern const OperationContext::Decoration<bool> documentValidationDisabled; + inline StringData bypassDocumentValidationCommandOption() { + return "bypassDocumentValidation"; + } + + inline bool shouldBypassDocumentValidationforCommand(const BSONObj& cmdObj) { + return cmdObj[bypassDocumentValidationCommandOption()].trueValue(); + } + /** * Disables document validation on a single OperationContext while in scope. * Resets to original value when leaving scope so they are safe to nest. diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index 78b576553b3..76a801caa35 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -36,6 +36,7 @@ #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/cloner.h" #include "mongo/db/commands.h" #include "mongo/db/commands/copydb.h" @@ -80,6 +81,10 @@ namespace mongo { ActionSet actions; actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + actions.addAction(ActionType::bypassDocumentValidation); + } + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(dbname), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -94,6 +99,10 @@ namespace mongo { string& errmsg, BSONObjBuilder& result) { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmdObj)) + maybeDisableValidation.emplace(txn); + string from = cmdObj.getStringField("clone"); if ( from.empty() ) return false; diff --git a/src/mongo/db/commands/clone_collection.cpp b/src/mongo/db/commands/clone_collection.cpp index e924e870e33..d0be61d3955 100644 --- a/src/mongo/db/commands/clone_collection.cpp +++ b/src/mongo/db/commands/clone_collection.cpp @@ -38,6 +38,7 @@ #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/cloner.h" #include "mongo/db/commands.h" #include "mongo/db/commands/copydb.h" @@ -85,6 +86,9 @@ namespace mongo { ActionSet actions; actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); // SERVER-11418 + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + actions.addAction(ActionType::bypassDocumentValidation); + } if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) { @@ -107,6 +111,10 @@ namespace mongo { string& errmsg, BSONObjBuilder& result) { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmdObj)) + maybeDisableValidation.emplace(txn); + string fromhost = cmdObj.getStringField("from"); if ( fromhost.empty() ) { errmsg = "missing 'from' parameter"; diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index 415f3b396c7..1d5a5b590b0 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -38,6 +38,7 @@ #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/cloner.h" #include "mongo/db/commands.h" #include "mongo/db/commands/copydb.h" @@ -128,6 +129,10 @@ namespace mongo { string& errmsg, BSONObjBuilder& result) { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmdObj)) + maybeDisableValidation.emplace(txn); + string fromhost = cmdObj.getStringField("fromhost"); bool fromSelf = fromhost.empty(); if ( fromSelf ) { diff --git a/src/mongo/db/commands/copydb_common.cpp b/src/mongo/db/commands/copydb_common.cpp index ca2d78e937d..778fc39a93c 100644 --- a/src/mongo/db/commands/copydb_common.cpp +++ b/src/mongo/db/commands/copydb_common.cpp @@ -35,6 +35,7 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/client_basic.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" @@ -64,6 +65,10 @@ namespace copydb { ActionSet actions; actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + actions.addAction(ActionType::bypassDocumentValidation); + } + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(todb), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 7de1b1ff966..099750539ab 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -38,6 +38,7 @@ #include "mongo/base/status_with.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -426,6 +427,10 @@ namespace { txn->setWriteConcern(wcResult.getValue()); setupSynchronousCommit(txn); + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmdObj)) + maybeDisableValidation.emplace(txn); + // We may encounter a WriteConflictException when creating a collection during an // upsert, even when holding the exclusive lock on the database (due to other load on // the system). The query framework should handle all other WriteConflictExceptions, diff --git a/src/mongo/db/commands/find_and_modify_common.cpp b/src/mongo/db/commands/find_and_modify_common.cpp index 796b6db415a..a5f0e91fb8d 100644 --- a/src/mongo/db/commands/find_and_modify_common.cpp +++ b/src/mongo/db/commands/find_and_modify_common.cpp @@ -37,6 +37,7 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/resource_pattern.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" @@ -50,6 +51,7 @@ namespace find_and_modify { bool update = cmdObj["update"].trueValue(); bool upsert = cmdObj["upsert"].trueValue(); bool remove = cmdObj["remove"].trueValue(); + bool bypassDocumentValidation = shouldBypassDocumentValidationforCommand(cmdObj); ActionSet actions; actions.addAction(ActionType::find); @@ -62,6 +64,9 @@ namespace find_and_modify { if (remove) { actions.addAction(ActionType::remove); } + if (bypassDocumentValidation) { + actions.addAction(ActionType::bypassDocumentValidation); + } ResourcePattern resource(commandTemplate->parseResourcePattern(dbname, cmdObj)); uassert(17137, "Invalid target namespace " + resource.toString(), resource.isExactNamespacePattern()); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 54d971dd212..e723e533889 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -40,6 +40,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands.h" #include "mongo/db/db.h" @@ -1287,6 +1288,10 @@ namespace mongo { BSONObjBuilder& result) { Timer t; + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmd)) + maybeDisableValidation.emplace(txn); + if (txn->getClient()->isInDirectClient()) { return appendCommandStatus(result, Status(ErrorCodes::IllegalOperation, @@ -1569,6 +1574,10 @@ namespace mongo { int, string& errmsg, BSONObjBuilder& result) { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (shouldBypassDocumentValidationforCommand(cmdObj)) + maybeDisableValidation.emplace(txn); + ShardedConnectionInfo::addHook(); // legacy name string shardedOutputCollection = cmdObj["shardedOutputCollection"].valuestrsafe(); diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp index cf507b2aded..02a5afe1ca5 100644 --- a/src/mongo/db/commands/mr_common.cpp +++ b/src/mongo/db/commands/mr_common.cpp @@ -34,6 +34,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/privilege.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" #include "mongo/util/mongoutils/str.h" @@ -126,6 +127,10 @@ namespace mongo { outputActions.addAction(ActionType::update); } + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + outputActions.addAction(ActionType::bypassDocumentValidation); + } + ResourcePattern outputResource( ResourcePattern::forExactNamespace( NamespaceString(outputOptions.finalNamespace))); diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index e65ffe04f85..3c2750dfb16 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -38,6 +38,7 @@ #include "mongo/base/error_codes.h" #include "mongo/db/catalog/database.h" #include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/catalog/index_create.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands.h" @@ -734,6 +735,10 @@ namespace mongo { void WriteBatchExecutor::bulkExecute( const BatchedCommandRequest& request, std::vector<BatchedUpsertDetail*>* upsertedIds, std::vector<WriteErrorDetail*>* errors ) { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (request.shouldBypassValidation()) { + maybeDisableValidation.emplace(_txn); + } if ( request.getBatchType() == BatchedCommandRequest::BatchType_Insert ) { execInserts( request, errors ); diff --git a/src/mongo/db/commands/write_commands/write_commands_common.cpp b/src/mongo/db/commands/write_commands/write_commands_common.cpp index 72c132ae1c0..92265e72507 100644 --- a/src/mongo/db/commands/write_commands/write_commands_common.cpp +++ b/src/mongo/db/commands/write_commands/write_commands_common.cpp @@ -36,6 +36,7 @@ #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/util/assert_util.h" namespace mongo { @@ -50,12 +51,16 @@ namespace auth { const BSONObj& cmdObj ) { vector<Privilege> privileges; + ActionSet actionsOnCommandNSSS; + + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + actionsOnCommandNSSS.addAction(ActionType::bypassDocumentValidation); + } if ( cmdType == BatchedCommandRequest::BatchType_Insert ) { if ( !cmdNSS.isSystemDotIndexes() ) { - privileges.push_back( Privilege( ResourcePattern::forExactNamespace( cmdNSS ), - ActionType::insert ) ); + actionsOnCommandNSSS.addAction(ActionType::insert); } else { // Special-case indexes until we have a command @@ -70,23 +75,22 @@ namespace auth { } } else if ( cmdType == BatchedCommandRequest::BatchType_Update ) { - - ActionSet actions; - actions.addAction( ActionType::update ); + actionsOnCommandNSSS.addAction(ActionType::update); // Upsert also requires insert privs if ( BatchedCommandRequest::containsUpserts( cmdObj ) ) { - actions.addAction( ActionType::insert ); + actionsOnCommandNSSS.addAction(ActionType::insert); } - - privileges.push_back( Privilege( ResourcePattern::forExactNamespace( cmdNSS ), - actions ) ); - } else { fassert( 17251, cmdType == BatchedCommandRequest::BatchType_Delete ); - privileges.push_back( Privilege( ResourcePattern::forExactNamespace( cmdNSS ), - ActionType::remove ) ); + actionsOnCommandNSSS.addAction(ActionType::remove); + } + + + if (!actionsOnCommandNSSS.empty()) { + privileges.emplace_back(ResourcePattern::forExactNamespace(cmdNSS), + actionsOnCommandNSSS); } if ( authzSession->isAuthorizedForPrivileges( privileges ) ) diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h index a2b6c2225da..fd88833611d 100644 --- a/src/mongo/db/pipeline/document_source.h +++ b/src/mongo/db/pipeline/document_source.h @@ -233,6 +233,11 @@ namespace mongo { virtual bool isCapped(const NamespaceString& ns) = 0; + /** + * Inserts 'objs' into 'ns' and returns the "detailed" last error object. + */ + virtual BSONObj insert(const NamespaceString& ns, const std::vector<BSONObj>& objs) = 0; + // Add new methods as needed. }; @@ -711,7 +716,7 @@ namespace mongo { // Sets _tempsNs and prepares it to receive data. void prepTempCollection(); - void spill(DBClientBase* conn, const std::vector<BSONObj>& toInsert); + void spill(const std::vector<BSONObj>& toInsert); bool _done; diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp index fb58cb1565a..bdb8d1d7055 100644 --- a/src/mongo/db/pipeline/document_source_out.cpp +++ b/src/mongo/db/pipeline/document_source_out.cpp @@ -109,9 +109,8 @@ namespace mongo { } } - void DocumentSourceOut::spill(DBClientBase* conn, const vector<BSONObj>& toInsert) { - conn->insert(_tempNs.ns(), toInsert); - BSONObj err = conn->getLastErrorDetailed(); + void DocumentSourceOut::spill(const vector<BSONObj>& toInsert) { + BSONObj err = _mongod->insert(_tempNs, toInsert); uassert(16996, str::stream() << "insert for $out failed: " << err, DBClientWithCommands::getLastErrorString(err).empty()); } @@ -136,7 +135,7 @@ namespace mongo { BSONObj toInsert = next->toBson(); bufferedBytes += toInsert.objsize(); if (!bufferedObjects.empty() && bufferedBytes > BSONObjMaxUserSize) { - spill(conn, bufferedObjects); + spill(bufferedObjects); bufferedObjects.clear(); bufferedBytes = toInsert.objsize(); } @@ -144,7 +143,7 @@ namespace mongo { } if (!bufferedObjects.empty()) - spill(conn, bufferedObjects); + spill(bufferedObjects); // Checking again to make sure we didn't become sharded while running. uassert(17018, str::stream() << "namespace '" << _outputNs.ns() diff --git a/src/mongo/db/pipeline/expression_context.h b/src/mongo/db/pipeline/expression_context.h index 5b4b6f55acf..96cce9e4b4f 100644 --- a/src/mongo/db/pipeline/expression_context.h +++ b/src/mongo/db/pipeline/expression_context.h @@ -39,12 +39,8 @@ namespace mongo { struct ExpressionContext : public IntrusiveCounterUnsigned { public: ExpressionContext(OperationContext* opCtx, const NamespaceString& ns) - : inShard(false) - , inRouter(false) - , extSortAllowed(false) - , ns(ns) + : ns(ns) , opCtx(opCtx) - , interruptCounter(interruptCheckPeriod) {} /** Used by a pipeline to check for interrupts so that killOp() works. @@ -54,18 +50,20 @@ namespace mongo { if (opCtx && --interruptCounter == 0) { // XXX SERVER-13931 for opCtx check // The checkForInterrupt could be expensive, at least in relative terms. opCtx->checkForInterrupt(); - interruptCounter = interruptCheckPeriod; + interruptCounter = kInterruptCheckPeriod; } } - bool inShard; - bool inRouter; - bool extSortAllowed; + bool inShard = false; + bool inRouter = false; + bool extSortAllowed = false; + bool bypassDocumentValidation = false; + NamespaceString ns; std::string tempDir; // Defaults to empty to prevent external sorting in mongos. OperationContext* opCtx; - static const int interruptCheckPeriod = 128; - int interruptCounter; // when 0, check interruptStatus + static const int kInterruptCheckPeriod = 128; + int interruptCounter = kInterruptCheckPeriod; // when 0, check interruptStatus }; } diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp index de7b7590bff..4804189982d 100644 --- a/src/mongo/db/pipeline/pipeline.cpp +++ b/src/mongo/db/pipeline/pipeline.cpp @@ -34,6 +34,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/privilege.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" #include "mongo/db/pipeline/accumulator.h" @@ -162,6 +163,11 @@ namespace mongo { continue; } + if (pFieldName == bypassDocumentValidationCommandOption()) { + pCtx->bypassDocumentValidation = cmdElement.trueValue(); + continue; + } + /* we didn't recognize a field in the command */ ostringstream sb; sb << "unrecognized field '" << cmdElement.fieldName() << "'"; @@ -353,6 +359,10 @@ namespace mongo { ActionSet actions; actions.addAction(ActionType::remove); actions.addAction(ActionType::insert); + if (shouldBypassDocumentValidationforCommand(cmdObj)) { + actions.addAction(ActionType::bypassDocumentValidation); + } + out->push_back(Privilege(ResourcePattern::forExactNamespace(outputNs), actions)); } } @@ -481,6 +491,10 @@ namespace mongo { serialized.setField("allowDiskUse", Value(true)); } + if (pCtx->bypassDocumentValidation) { + serialized.setField(bypassDocumentValidationCommandOption(), Value(true)); + } + return serialized.freeze(); } diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 51a4a6ef4cd..2709cc7f8d5 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -36,6 +36,7 @@ #include "mongo/client/dbclientinterface.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/pipeline/document_source.h" @@ -51,31 +52,40 @@ namespace mongo { using std::string; namespace { - class MongodImplementation : public DocumentSourceNeedsMongod::MongodInterface { + class MongodImplementation final : public DocumentSourceNeedsMongod::MongodInterface { public: MongodImplementation(const intrusive_ptr<ExpressionContext>& ctx) : _ctx(ctx) , _client(ctx->opCtx) {} - DBClientBase* directClient() { + DBClientBase* directClient() final { // opCtx may have changed since our last call invariant(_ctx->opCtx); _client.setOpCtx(_ctx->opCtx); return &_client; } - bool isSharded(const NamespaceString& ns) { + bool isSharded(const NamespaceString& ns) final { const ChunkVersion unsharded(0, 0, OID()); return !(shardingState.getVersion(ns.ns()).isWriteCompatibleWith(unsharded)); } - bool isCapped(const NamespaceString& ns) { + bool isCapped(const NamespaceString& ns) final { AutoGetCollectionForRead ctx(_ctx->opCtx, ns.ns()); Collection* collection = ctx.getCollection(); return collection && collection->isCapped(); } + BSONObj insert(const NamespaceString& ns, const std::vector<BSONObj>& objs) final { + boost::optional<DisableDocumentValidation> maybeDisableValidation; + if (_ctx->bypassDocumentValidation) + maybeDisableValidation.emplace(_ctx->opCtx); + + _client.insert(ns.ns(), objs); + return _client.getLastErrorDetailed(); + } + private: intrusive_ptr<ExpressionContext> _ctx; DBDirectClient _client; diff --git a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp index 2485eefe284..926ade44806 100644 --- a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp +++ b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp @@ -37,6 +37,7 @@ #include <vector> #include "mongo/client/connpool.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands.h" #include "mongo/db/commands/mr.h" #include "mongo/s/catalog/catalog_cache.h" @@ -88,7 +89,8 @@ namespace { BSONElement e = i.next(); const string fn = e.fieldName(); - if (fn == "map" || + if (fn == bypassDocumentValidationCommandOption() || + fn == "map" || fn == "mapreduce" || fn == "mapReduce" || fn == "mapparams" || @@ -401,9 +403,8 @@ namespace { BSONObj aggCounts = aggCountsB.done(); finalCmd.append("counts", aggCounts); - if (cmdObj.hasField(LiteParsedQuery::cmdOptionMaxTimeMS)) { - finalCmd.append(cmdObj[LiteParsedQuery::cmdOptionMaxTimeMS]); - } + if (auto elem = cmdObj[LiteParsedQuery::cmdOptionMaxTimeMS]) finalCmd.append(elem); + if (auto elem = cmdObj[bypassDocumentValidationCommandOption()]) finalCmd.append(elem); Timer t2; diff --git a/src/mongo/s/commands/cluster_move_primary_cmd.cpp b/src/mongo/s/commands/cluster_move_primary_cmd.cpp index 993731723a5..79f22547f1f 100644 --- a/src/mongo/s/commands/cluster_move_primary_cmd.cpp +++ b/src/mongo/s/commands/cluster_move_primary_cmd.cpp @@ -38,6 +38,7 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_session.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/client_basic.h" #include "mongo/db/commands.h" #include "mongo/db/operation_context.h" @@ -182,7 +183,8 @@ namespace { BSONObj cloneRes; bool worked = toconn->runCommand(dbname.c_str(), BSON("clone" << config->getPrimary().getConnString() - << "collsToIgnore" << barr.arr()), + << "collsToIgnore" << barr.arr() + << bypassDocumentValidationCommandOption() << true), cloneRes); toconn.done(); diff --git a/src/mongo/s/write_ops/batch_write_op.cpp b/src/mongo/s/write_ops/batch_write_op.cpp index d695d93afb9..c12c36d328e 100644 --- a/src/mongo/s/write_ops/batch_write_op.cpp +++ b/src/mongo/s/write_ops/batch_write_op.cpp @@ -431,6 +431,7 @@ namespace mongo { BatchedCommandRequest* request ) const { request->setNS( _clientRequest->getNS() ); + request->setShouldBypassValidation(_clientRequest->shouldBypassValidation()); const vector<TargetedWrite*>& targetedWrites = targetedBatch.getWrites(); diff --git a/src/mongo/s/write_ops/batched_command_request.cpp b/src/mongo/s/write_ops/batched_command_request.cpp index 1dc014cb824..e4f39905a12 100644 --- a/src/mongo/s/write_ops/batched_command_request.cpp +++ b/src/mongo/s/write_ops/batched_command_request.cpp @@ -277,6 +277,14 @@ namespace mongo { INVOKE( getMetadata ); } + void BatchedCommandRequest::setShouldBypassValidation(bool newVal) { + INVOKE(setShouldBypassValidation, newVal); + } + + bool BatchedCommandRequest::shouldBypassValidation() const { + INVOKE(shouldBypassValidation); + } + /** * Generates a new request with insert _ids if required. Otherwise returns NULL. */ diff --git a/src/mongo/s/write_ops/batched_command_request.h b/src/mongo/s/write_ops/batched_command_request.h index a56b74f6ed4..9cf7fb1a92d 100644 --- a/src/mongo/s/write_ops/batched_command_request.h +++ b/src/mongo/s/write_ops/batched_command_request.h @@ -144,6 +144,9 @@ namespace mongo { bool isMetadataSet() const; BatchedRequestMetadata* getMetadata() const; + void setShouldBypassValidation(bool newVal); + bool shouldBypassValidation() const; + // // Helpers for batch pre-processing // diff --git a/src/mongo/s/write_ops/batched_delete_request.h b/src/mongo/s/write_ops/batched_delete_request.h index 3bcbfb48e49..62fd4f94505 100644 --- a/src/mongo/s/write_ops/batched_delete_request.h +++ b/src/mongo/s/write_ops/batched_delete_request.h @@ -124,6 +124,13 @@ namespace mongo { bool isMetadataSet() const; BatchedRequestMetadata* getMetadata() const; + /** + * These are no-ops since delete never validates documents. They only exist to fulfill the + * unified API. + */ + void setShouldBypassValidation(bool newVal) {} + bool shouldBypassValidation() const { return false; } + private: // Convention: (M)andatory, (O)ptional diff --git a/src/mongo/s/write_ops/batched_insert_request.cpp b/src/mongo/s/write_ops/batched_insert_request.cpp index d7300a05575..94f7daabe0a 100644 --- a/src/mongo/s/write_ops/batched_insert_request.cpp +++ b/src/mongo/s/write_ops/batched_insert_request.cpp @@ -28,6 +28,7 @@ #include "mongo/s/write_ops/batched_insert_request.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/field_parser.h" #include "mongo/util/mongoutils/str.h" @@ -92,6 +93,8 @@ namespace mongo { if (_metadata) builder.append(metadata(), _metadata->toBSON()); + if (_shouldBypassValidation) builder.append(bypassDocumentValidationCommandOption(), true); + return builder.obj(); } @@ -152,6 +155,9 @@ namespace mongo { } } } + else if (bypassDocumentValidationCommandOption() == sourceEl.fieldNameStringData()) { + _shouldBypassValidation = sourceEl.trueValue(); + } } return true; @@ -171,6 +177,8 @@ namespace mongo { _ordered = false; _isOrderedSet = false; + _shouldBypassValidation = false; + _metadata.reset(); } diff --git a/src/mongo/s/write_ops/batched_insert_request.h b/src/mongo/s/write_ops/batched_insert_request.h index a1be831497d..0fb6d95d8c5 100644 --- a/src/mongo/s/write_ops/batched_insert_request.h +++ b/src/mongo/s/write_ops/batched_insert_request.h @@ -110,6 +110,9 @@ namespace mongo { bool isOrderedSet() const; bool getOrdered() const; + void setShouldBypassValidation(bool newVal) { _shouldBypassValidation = newVal; } + bool shouldBypassValidation() const { return _shouldBypassValidation; } + /* * metadata ownership will be transferred to this. */ @@ -142,6 +145,9 @@ namespace mongo { // (O) cached copied of target ns NamespaceString _targetNSS; + + // (O) should document validation be bypassed (default false) + bool _shouldBypassValidation; }; } // namespace mongo diff --git a/src/mongo/s/write_ops/batched_update_request.cpp b/src/mongo/s/write_ops/batched_update_request.cpp index 4e03f91a793..98b5c1ccf27 100644 --- a/src/mongo/s/write_ops/batched_update_request.cpp +++ b/src/mongo/s/write_ops/batched_update_request.cpp @@ -28,6 +28,7 @@ #include "mongo/s/write_ops/batched_update_request.h" +#include "mongo/db/catalog/document_validation.h" #include "mongo/db/field_parser.h" #include "mongo/util/mongoutils/str.h" @@ -95,6 +96,8 @@ namespace mongo { if (_metadata) builder.append(metadata(), _metadata->toBSON()); + if (_shouldBypassValidation) builder.append(bypassDocumentValidationCommandOption(), true); + return builder.obj(); } @@ -145,6 +148,9 @@ namespace mongo { } } } + else if (fieldName == bypassDocumentValidationCommandOption()) { + _shouldBypassValidation = elem.trueValue(); + } } return true; } @@ -161,6 +167,8 @@ namespace mongo { _ordered = false; _isOrderedSet = false; + _shouldBypassValidation = false; + _metadata.reset(); } diff --git a/src/mongo/s/write_ops/batched_update_request.h b/src/mongo/s/write_ops/batched_update_request.h index 38633fc1079..94f24f089b1 100644 --- a/src/mongo/s/write_ops/batched_update_request.h +++ b/src/mongo/s/write_ops/batched_update_request.h @@ -116,6 +116,9 @@ namespace mongo { bool isOrderedSet() const; bool getOrdered() const; + void setShouldBypassValidation(bool newVal) { _shouldBypassValidation = newVal; } + bool shouldBypassValidation() const { return _shouldBypassValidation; } + /* * metadata ownership will be transferred to this. */ @@ -143,6 +146,9 @@ namespace mongo { bool _ordered; bool _isOrderedSet; + // (O) should document validation be bypassed (default false) + bool _shouldBypassValidation; + // (O) metadata associated with this request for internal use. boost::scoped_ptr<BatchedRequestMetadata> _metadata; }; |