diff options
Diffstat (limited to 'src/mongo/shell/replsettest.js')
| -rw-r--r-- | src/mongo/shell/replsettest.js | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js index dee9b4c75a0..05c4b584ff2 100644 --- a/src/mongo/shell/replsettest.js +++ b/src/mongo/shell/replsettest.js @@ -570,6 +570,51 @@ var ReplSetTest = function(opts) { }; /** + * A special version of awaitSecondaryNodes() used exclusively by rollback_test.js. + * Wraps around awaitSecondaryNodes() itself and checks for an unrecoverable rollback + * if it throws. + */ + this.awaitSecondaryNodesForRollbackTest = function(timeout, + connToCheckForUnrecoverableRollback) { + try { + this.awaitSecondaryNodes(timeout); + } catch (originalEx) { + // There is a special case where we expect the (rare) possibility of unrecoverable + // rollbacks with EMRC:false in rollback suites with unclean shutdowns. + jsTestLog("Exception in 'awaitSecondaryNodes', checking for unrecoverable rollback"); + if (connToCheckForUnrecoverableRollback) { + const conn = connToCheckForUnrecoverableRollback; + + const statusRes = assert.commandWorked(conn.adminCommand({replSetGetStatus: 1})); + const isRecovering = (statusRes.myState === ReplSetTest.State.RECOVERING); + const hasNoSyncSource = (statusRes.syncSourceId === -1); + + const cmdLineOptsRes = assert.commandWorked(conn.adminCommand("getCmdLineOpts")); + const hasEMRCFalse = + (cmdLineOptsRes.parsed.replication.enableMajorityReadConcern === false); + + if (isRecovering && hasNoSyncSource && hasEMRCFalse) { + try { + const n = this.getNodeId(conn); + const connToCheck = _useBridge ? _unbridgedNodes[n] : this.nodes[n]; + // Confirm that the node is unable to recover after rolling back. + checkLog.contains( + connToCheck, + "remote oplog does not contain entry with optime matching our required optime ", + 60 * 1000); + } catch (checkLogEx) { + throw originalEx; + } + // Add this info to the original exception. + originalEx.unrecoverableRollbackDetected = true; + } + } + // Re-throw the original exception in all cases. + throw originalEx; + } + }; + + /** * Blocks until the specified node says it's syncing from the given upstream node. */ this.awaitSyncSource = function(node, upstreamNode, timeout) { |
