summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/apply_ops.cpp
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-01-22 19:06:05 -0500
committerMathias Stearn <mathias@10gen.com>2015-01-23 11:24:31 -0500
commit8e2052f745ffaa1cf15ff79e6661b5cf72633a0a (patch)
tree6b3ec4ef761a20ad31fcfc4a6fea14d3b4250088 /src/mongo/db/commands/apply_ops.cpp
parentc3413d543ca676ffe55209507c83cebc6be841b1 (diff)
downloadmongo-8e2052f745ffaa1cf15ff79e6661b5cf72633a0a.tar.gz
SERVER-17003 Add WriteConflict retry logic to applyOps command
Diffstat (limited to 'src/mongo/db/commands/apply_ops.cpp')
-rw-r--r--src/mongo/db/commands/apply_ops.cpp50
1 files changed, 42 insertions, 8 deletions
diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp
index d2522ba6c29..2cc5794c61b 100644
--- a/src/mongo/db/commands/apply_ops.cpp
+++ b/src/mongo/db/commands/apply_ops.cpp
@@ -26,6 +26,10 @@
* it in the license file.
*/
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand
+
+#include "mongo/platform/basic.h"
+
#include <sstream>
#include <string>
#include <vector>
@@ -38,11 +42,13 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/dbhash.h"
+#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/matcher/matcher.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/db/repl/oplog.h"
+#include "mongo/util/log.h"
namespace mongo {
@@ -149,11 +155,26 @@ namespace mongo {
};
Client::Context ctx(txn, ns);
- bool failed = repl::applyOperation_inlock(txn,
- ctx.db(),
- temp,
- false,
- alwaysUpsert);
+
+ bool failed;
+ while (true) {
+ try {
+ // We assume that in the WriteConflict retry case, either the op rolls back
+ // any changes it makes or is otherwise safe to rerun.
+ failed = repl::applyOperation_inlock(txn,
+ ctx.db(),
+ temp,
+ false,
+ alwaysUpsert);
+ break;
+ }
+ catch (const WriteConflictException& wce) {
+ LOG(2) << "WriteConflictException in applyOps command, retrying.";
+ txn->recoveryUnit()->commitAndRestart();
+ continue;
+ }
+ }
+
ab.append(!failed);
if ( failed )
errors++;
@@ -184,13 +205,26 @@ namespace mongo {
}
}
+ const BSONObj cmdRewritten = cmdBuilder.done();
+
// We currently always logOp the command regardless of whether the individial ops
// succeeded and rely on any failures to also happen on secondaries. This isn't
// perfect, but it's what the command has always done and is part of its "correct"
// behavior.
- WriteUnitOfWork wunit(txn);
- repl::logOp(txn, "c", tempNS.c_str(), cmdBuilder.done());
- wunit.commit();
+ while (true) {
+ try {
+ WriteUnitOfWork wunit(txn);
+ repl::logOp(txn, "c", tempNS.c_str(), cmdRewritten);
+ wunit.commit();
+ break;
+ }
+ catch (const WriteConflictException& wce) {
+ LOG(2) <<
+ "WriteConflictException while logging applyOps command, retrying.";
+ txn->recoveryUnit()->commitAndRestart();
+ continue;
+ }
+ }
}
if (errors != 0) {