diff options
author | Kevin Pulo <kevin.pulo@mongodb.com> | 2019-11-13 05:52:35 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-11-13 05:52:35 +0000 |
commit | 3bc3aa7a96971423f428bd9a1e1df4f110ea730b (patch) | |
tree | 03dbe17ea4d7617d2610e10dba142b2d5dfa7ea7 /src/mongo | |
parent | bac1664ab0080de0e49aa6c0b724bd8494ed96cc (diff) | |
download | mongo-3bc3aa7a96971423f428bd9a1e1df4f110ea730b.tar.gz |
SERVER-44289 permit writeConcern on retryable writes that move doc onto another shard
(cherry picked from commit 9861e230bcb9bb37ed1cbb504ed4ff177a0300da)
(partial cherry pick from commit 81238fa87afbe52a9658547f63c79fac126862f1)
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/s/cluster_commands_helpers.cpp | 12 | ||||
-rw-r--r-- | src/mongo/s/cluster_commands_helpers.h | 5 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_and_modify_cmd.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_write_cmd.cpp | 23 | ||||
-rw-r--r-- | src/mongo/s/write_ops/batched_command_request.h | 4 |
5 files changed, 41 insertions, 11 deletions
diff --git a/src/mongo/s/cluster_commands_helpers.cpp b/src/mongo/s/cluster_commands_helpers.cpp index 616433389c5..ba4ae319197 100644 --- a/src/mongo/s/cluster_commands_helpers.cpp +++ b/src/mongo/s/cluster_commands_helpers.cpp @@ -264,6 +264,18 @@ BSONObj appendAllowImplicitCreate(BSONObj cmdObj, bool allow) { return newCmdBuilder.obj(); } +BSONObj stripWriteConcern(const BSONObj& cmdObj) { + BSONObjBuilder output; + for (const auto& elem : cmdObj) { + const auto name = elem.fieldNameStringData(); + if (name == WriteConcernOptions::kWriteConcernField) { + continue; + } + output.append(elem); + } + return output.obj(); +} + std::vector<AsyncRequestsSender::Response> scatterGatherUnversionedTargetAllShards( OperationContext* opCtx, StringData dbName, diff --git a/src/mongo/s/cluster_commands_helpers.h b/src/mongo/s/cluster_commands_helpers.h index 433013c76b6..48bdd58e2d8 100644 --- a/src/mongo/s/cluster_commands_helpers.h +++ b/src/mongo/s/cluster_commands_helpers.h @@ -81,6 +81,11 @@ BSONObj appendShardVersion(BSONObj cmdObj, ChunkVersion version); BSONObj appendAllowImplicitCreate(BSONObj cmdObj, bool allow); /** + * Returns a copy of 'cmdObj' with the writeConcern removed. + */ +BSONObj stripWriteConcern(const BSONObj& cmdObj); + +/** * Utility for dispatching unversioned commands to all shards in a cluster. * * Returns a non-OK status if a failure occurs on *this* node during execution. Otherwise, returns diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index 1f70c6080a0..6d561285d94 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -310,9 +310,13 @@ private: // Re-run the findAndModify command that will change the shard key value in a // transaction. We call _runCommand recursively, and this second time through // since it will be run as a transaction it will take the other code path to - // updateShardKeyValueOnWouldChangeOwningShardError. + // updateShardKeyValueOnWouldChangeOwningShardError. We ensure the retried + // operation does not include WC inside the transaction by stripping it from the + // cmdObj. The transaction commit will still use the WC, because it uses the WC + // from the opCtx (which has been set previously in Strategy). documentShardKeyUpdateUtil::startTransactionForShardKeyUpdate(opCtx); - _runCommand(opCtx, shardId, shardVersion, nss, cmdObj, result); + _runCommand( + opCtx, shardId, shardVersion, nss, stripWriteConcern(cmdObj), result); auto commitResponse = documentShardKeyUpdateUtil::commitShardKeyUpdateTransaction(opCtx); diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index 917589675de..ef49fa8cfa5 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -190,14 +190,14 @@ boost::optional<WouldChangeOwningShardInfo> getWouldChangeOwningShardErrorInfo( * inserts the new one. Returns whether or not we actually complete the delete and insert. */ bool handleWouldChangeOwningShardError(OperationContext* opCtx, - const BatchedCommandRequest& request, + BatchedCommandRequest* request, BatchedCommandResponse* response, BatchWriteExecStats stats) { auto txnRouter = TransactionRouter::get(opCtx); bool isRetryableWrite = opCtx->getTxnNumber() && !txnRouter; auto wouldChangeOwningShardErrorInfo = - getWouldChangeOwningShardErrorInfo(opCtx, request, response, !isRetryableWrite); + getWouldChangeOwningShardErrorInfo(opCtx, *request, response, !isRetryableWrite); if (!wouldChangeOwningShardErrorInfo) return false; @@ -215,12 +215,17 @@ bool handleWouldChangeOwningShardError(OperationContext* opCtx, auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx); readConcernArgs = repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern); + // Ensure the retried operation does not include WC inside the transaction. The + // transaction commit will still use the WC, because it uses the WC from the opCtx + // (which has been set previously in Strategy). + request->unsetWriteConcern(); + documentShardKeyUpdateUtil::startTransactionForShardKeyUpdate(opCtx); // Clear the error details from the response object before sending the write again response->unsetErrDetails(); - ClusterWriter::write(opCtx, request, &stats, response); + ClusterWriter::write(opCtx, *request, &stats, response); wouldChangeOwningShardErrorInfo = - getWouldChangeOwningShardErrorInfo(opCtx, request, response, !isRetryableWrite); + getWouldChangeOwningShardErrorInfo(opCtx, *request, response, !isRetryableWrite); // If we do not get WouldChangeOwningShard when re-running the update, the document has // been modified or deleted concurrently and we do not need to delete it and insert a @@ -229,9 +234,9 @@ bool handleWouldChangeOwningShardError(OperationContext* opCtx, wouldChangeOwningShardErrorInfo && documentShardKeyUpdateUtil::updateShardKeyForDocument( opCtx, - request.getNS(), + request->getNS(), wouldChangeOwningShardErrorInfo.get(), - boost::get_optional_value_or(request.getWriteCommandBase().getStmtId(), 0)); + boost::get_optional_value_or(request->getWriteCommandBase().getStmtId(), 0)); // If the operation was an upsert, record the _id of the new document. if (updatedShardKey && wouldChangeOwningShardErrorInfo->getShouldUpsert()) { @@ -276,9 +281,9 @@ bool handleWouldChangeOwningShardError(OperationContext* opCtx, // Delete the original document and insert the new one updatedShardKey = documentShardKeyUpdateUtil::updateShardKeyForDocument( opCtx, - request.getNS(), + request->getNS(), wouldChangeOwningShardErrorInfo.get(), - boost::get_optional_value_or(request.getWriteCommandBase().getStmtId(), 0)); + boost::get_optional_value_or(request->getWriteCommandBase().getStmtId(), 0)); // If the operation was an upsert, record the _id of the new document. if (updatedShardKey && wouldChangeOwningShardErrorInfo->getShouldUpsert()) { @@ -446,7 +451,7 @@ private: bool updatedShardKey = false; if (_batchedRequest.getBatchType() == BatchedCommandRequest::BatchType_Update) { updatedShardKey = - handleWouldChangeOwningShardError(opCtx, batchedRequest, &response, stats); + handleWouldChangeOwningShardError(opCtx, &batchedRequest, &response, stats); } // Populate the lastError object based on the write response diff --git a/src/mongo/s/write_ops/batched_command_request.h b/src/mongo/s/write_ops/batched_command_request.h index b49e893e5aa..be207399320 100644 --- a/src/mongo/s/write_ops/batched_command_request.h +++ b/src/mongo/s/write_ops/batched_command_request.h @@ -91,6 +91,10 @@ public: _writeConcern = writeConcern.getOwned(); } + void unsetWriteConcern() { + _writeConcern = boost::none; + } + bool hasWriteConcern() const { return _writeConcern.is_initialized(); } |