summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-03-30 19:43:11 -0400
committerRamon Fernandez <ramon.fernandez@mongodb.com>2015-03-31 15:20:06 -0400
commit5006eb81f94ce90eebb68828b299761b622f0ec1 (patch)
tree0103cc000ae2a36e9793e15feeb9509d453b2e7b
parentb8975422d78ad3c1f189414b765fa09472ce6f2e (diff)
downloadmongo-5006eb81f94ce90eebb68828b299761b622f0ec1.tar.gz
SERVER-17642 WCE retry loop per document in index build
(cherry picked from commit a853cabd7e65ca545636af6b6c957d1ee1d4b39d)
-rw-r--r--src/mongo/db/catalog/index_create.cpp66
1 files changed, 44 insertions, 22 deletions
diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp
index 5018bc5816a..a4e59139b83 100644
--- a/src/mongo/db/catalog/index_create.cpp
+++ b/src/mongo/db/catalog/index_create.cpp
@@ -255,37 +255,59 @@ namespace mongo {
exec->setYieldPolicy(PlanExecutor::YIELD_AUTO);
}
- BSONObj objToIndex;
+ Snapshotted<BSONObj> objToIndex;
RecordId loc;
PlanExecutor::ExecState state;
- while (PlanExecutor::ADVANCED == (state = exec->getNext(&objToIndex, &loc))) {
- {
+ int retries = 0; // non-zero when retrying our last document.
+ while (retries
+ || (PlanExecutor::ADVANCED == (state = exec->getNextSnapshotted(&objToIndex,
+ &loc)))) {
+ try {
if (_allowInterruption)
_txn->checkForInterrupt();
- bool shouldCommitWUnit = true;
- WriteUnitOfWork wunit(_txn);
- Status ret = insert(objToIndex, loc);
- if (!ret.isOK()) {
- if (dupsOut && ret.code() == ErrorCodes::DuplicateKey) {
- // If dupsOut is non-null, we should only fail the specific insert that
- // led to a DuplicateKey rather than the whole index build.
- dupsOut->insert(loc);
- shouldCommitWUnit = false;
- }
- else {
- return ret;
- }
+ // Make sure we are working with the latest version of the document.
+ if (objToIndex.snapshotId() != _txn->recoveryUnit()->getSnapshotId()
+ && !_collection->findDoc(_txn, loc, &objToIndex)) {
+ // doc was deleted so don't index it.
+ retries = 0;
+ continue;
}
- if (shouldCommitWUnit)
- wunit.commit();
- }
+ // Done before insert so we can retry document if it WCEs.
+ progress->setTotalWhileRunning( _collection->numRecords(_txn) );
- n++;
- progress->hit();
+ WriteUnitOfWork wunit(_txn);
+ Status ret = insert(objToIndex.value(), loc);
+ if (ret.isOK()) {
+ wunit.commit();
+ }
+ else if (dupsOut && ret.code() == ErrorCodes::DuplicateKey) {
+ // If dupsOut is non-null, we should only fail the specific insert that
+ // led to a DuplicateKey rather than the whole index build.
+ dupsOut->insert(loc);
+ }
+ else {
+ // Fail the index build hard.
+ return ret;
+ }
- progress->setTotalWhileRunning( _collection->numRecords(_txn) );
+ // Go to the next document
+ progress->hit();
+ n++;
+ retries = 0;
+ }
+ catch (const WriteConflictException& wce) {
+ _txn->getCurOp()->debug().writeConflicts++;
+ retries++; // logAndBackoff expects this to be 1 on first call.
+ wce.logAndBackoff(retries, "index creation", _collection->ns().ns());
+
+ // Can't use WRITE_CONFLICT_RETRY_LOOP macros since we need to save/restore exec
+ // around call to commitAndRestart.
+ exec->saveState();
+ _txn->recoveryUnit()->commitAndRestart();
+ exec->restoreState(_txn); // Handles any WCEs internally.
+ }
}
if (state != PlanExecutor::IS_EOF) {