summaryrefslogtreecommitdiff
path: root/jstests/core/txns/transaction_too_large_for_cache.js
blob: 5b7f3d1bcf5faee7dab3846acd9afa0c3fa96ab0 (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
 * Tests a multi-document transaction requiring more cache than available fails with the expected
 * error code instead of a generic WriteConflictException.
 *
 * @tags: [
 *   does_not_support_config_fuzzer,
 *   requires_fcv_62,
 *   requires_persistence,
 *   requires_non_retryable_writes,
 *   requires_wiredtiger,
 *   uses_transactions,
 * ]
 */

(function() {
load("jstests/libs/fixture_helpers.js");  // For FixtureHelpers.
load('jstests/libs/transactions_util.js');

function getWtCacheSizeBytes() {
    let serverStatus;
    if (FixtureHelpers.isReplSet(db) || FixtureHelpers.isMongos(db)) {
        serverStatus = FixtureHelpers.getPrimaries(db)[0].getDB('admin').serverStatus();
    } else {
        serverStatus = db.serverStatus();
    }

    assert.commandWorked(serverStatus);
    return serverStatus.wiredTiger.cache["maximum bytes configured"];
}

const doc1 = {
    x: []
};
for (var j = 0; j < 100000; j++) {
    doc1.x.push("" + Math.random() + Math.random());
}

const session = db.getMongo().startSession();
const sessionDb = session.getDatabase(db.getName());
const coll = sessionDb[jsTestName()];
coll.drop();

// Scale the load in proportion to WT cache size, to reduce test run time.
// A single collection can only have up to 64 indexes. Cap at _id + 1 text index + 62 indexes.
const nIndexes = Math.min(Math.ceil(getWtCacheSizeBytes() * 2 / (1024 * 1024 * 1024)), 62);
assert.commandWorked(coll.createIndex({x: "text"}));
for (let i = 0; i < nIndexes; i++) {
    assert.commandWorked(coll.createIndex({x: 1, ["field" + i]: 1}));
}

// Retry the transaction until we eventually hit the TransactionTooLargeForCache. Only retry on
// WriteConflict error, which is the only expected error besides TransactionTooLargeForCache.
assert.soon(() => {
    session.startTransaction();

    // Keep inserting documents in the transaction until we eventually hit the cache limit.
    let insertCount = 0;
    let result;
    try {
        while (true) {
            try {
                ++insertCount;
                result = coll.insert(doc1);
                assert.commandWorked(result);
            } catch (e) {
                session.abortTransaction();
                assert.commandFailedWithCode(result, ErrorCodes.TransactionTooLargeForCache);
                break;
            }
        }
    } catch (e) {
        assert.commandFailedWithCode(result, ErrorCodes.WriteConflict);
        return false;
    }

    // The error should not have a transient transaction error label. At this point the error must
    // have been TransactionTooLargeForCache. We do this check here to avoid having to check
    // exception types in the outermost catch, in case this assertion fires.
    assert(!TransactionsUtil.isTransientTransactionError(result), result);

    jsTestLog("Iterations until TransactionTooLargeForCache occured: " + insertCount);

    return true;
}, "Expected a transaction to eventually fail with TransactionTooLargeForCache error.");
}());