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.");
}());
|