summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-05-11 17:36:52 -0400
committerMathias Stearn <mathias@10gen.com>2015-05-14 18:59:03 -0400
commit463d3343d559590d60cfd5c48ac98ad675d5390e (patch)
tree5ab045f64656074016c08229ae0bcc6734579e6e
parent22de12dd4ac510cd2a37b643eb528673f651e21b (diff)
downloadmongo-463d3343d559590d60cfd5c48ac98ad675d5390e.tar.gz
SERVER-18227 Add bypassDocumentValidation option to commands that need it
-rw-r--r--src/mongo/db/auth/action_types.txt1
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp15
-rw-r--r--src/mongo/db/catalog/document_validation.h9
-rw-r--r--src/mongo/db/commands/clone.cpp9
-rw-r--r--src/mongo/db/commands/clone_collection.cpp8
-rw-r--r--src/mongo/db/commands/copydb.cpp5
-rw-r--r--src/mongo/db/commands/copydb_common.cpp5
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp5
-rw-r--r--src/mongo/db/commands/find_and_modify_common.cpp5
-rw-r--r--src/mongo/db/commands/mr.cpp9
-rw-r--r--src/mongo/db/commands/mr_common.cpp5
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp5
-rw-r--r--src/mongo/db/commands/write_commands/write_commands_common.cpp28
-rw-r--r--src/mongo/db/pipeline/document_source.h7
-rw-r--r--src/mongo/db/pipeline/document_source_out.cpp9
-rw-r--r--src/mongo/db/pipeline/expression_context.h20
-rw-r--r--src/mongo/db/pipeline/pipeline.cpp14
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp18
-rw-r--r--src/mongo/s/commands/cluster_map_reduce_cmd.cpp9
-rw-r--r--src/mongo/s/commands/cluster_move_primary_cmd.cpp4
-rw-r--r--src/mongo/s/write_ops/batch_write_op.cpp1
-rw-r--r--src/mongo/s/write_ops/batched_command_request.cpp8
-rw-r--r--src/mongo/s/write_ops/batched_command_request.h3
-rw-r--r--src/mongo/s/write_ops/batched_delete_request.h7
-rw-r--r--src/mongo/s/write_ops/batched_insert_request.cpp8
-rw-r--r--src/mongo/s/write_ops/batched_insert_request.h6
-rw-r--r--src/mongo/s/write_ops/batched_update_request.cpp8
-rw-r--r--src/mongo/s/write_ops/batched_update_request.h6
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;
};