summaryrefslogtreecommitdiff
path: root/jstests/libs/override_methods/retry_writes_at_least_once.js
blob: f122769eadcf2feac7272dc2c6bd5c9648852ed1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * Overrides Mongo.prototype.runCommand and Mongo.prototype.runCommandWithMetadata to retry all
 * retryable writes at least once, randomly more than that, regardless of the outcome of the
 * command. Returns the result of the latest attempt.
 */
(function() {
    "use strict";

    load("jstests/libs/override_methods/override_helpers.js");
    load("jstests/libs/retryable_writes_util.js");

    Random.setRandomSeed();

    const kExtraRetryProbability = 0.2;

    const mongoRunCommandOriginal = Mongo.prototype.runCommand;
    const mongoRunCommandWithMetadataOriginal = Mongo.prototype.runCommandWithMetadata;

    Mongo.prototype.runCommand = function runCommand(dbName, cmdObj, options) {
        return runWithRetries(this, cmdObj, mongoRunCommandOriginal, arguments);
    };

    Mongo.prototype.runCommandWithMetadata = function runCommandWithMetadata(
        dbName, metadata, cmdObj) {
        return runWithRetries(this, cmdObj, mongoRunCommandWithMetadataOriginal, arguments);
    };

    function runWithRetries(mongo, cmdObj, clientFunction, clientFunctionArguments) {
        let cmdName = Object.keys(cmdObj)[0];

        // If the command is in a wrapped form, then we look for the actual command object
        // inside the query/$query object.
        if (cmdName === "query" || cmdName === "$query") {
            cmdObj = cmdObj[cmdName];
            cmdName = Object.keys(cmdObj)[0];
        }

        const isRetryableWriteCmd = RetryableWritesUtil.isRetryableWriteCmdName(cmdName);
        const canRetryWrites = _ServerSession.canRetryWrites(cmdObj);

        let res = clientFunction.apply(mongo, clientFunctionArguments);

        if (isRetryableWriteCmd && canRetryWrites) {
            let retryAttempt = 1;
            do {
                print("*** Retry attempt: " + retryAttempt + ", for command: " + cmdName +
                      " with txnNumber: " + tojson(cmdObj.txnNumber) + ", and lsid: " +
                      tojson(cmdObj.lsid));
                ++retryAttempt;
                res = clientFunction.apply(mongo, clientFunctionArguments);
            } while (Random.rand() <= kExtraRetryProbability);
        }

        return res;
    }

    OverrideHelpers.prependOverrideInParallelShell(
        "jstests/libs/override_methods/retry_writes_at_least_once.js");
})();