diff options
author | Mathias Stearn <mathias@10gen.com> | 2015-01-22 19:06:05 -0500 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2015-01-23 11:24:31 -0500 |
commit | 8e2052f745ffaa1cf15ff79e6661b5cf72633a0a (patch) | |
tree | 6b3ec4ef761a20ad31fcfc4a6fea14d3b4250088 | |
parent | c3413d543ca676ffe55209507c83cebc6be841b1 (diff) | |
download | mongo-8e2052f745ffaa1cf15ff79e6661b5cf72633a0a.tar.gz |
SERVER-17003 Add WriteConflict retry logic to applyOps command
-rw-r--r-- | src/mongo/db/commands/apply_ops.cpp | 50 |
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) { |