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
86
87
88
89
90
91
92
93
|
/**
* Test that only the primary can reap a session and remove the config.transactions doc for the
* session, and that arbiters never try to a reap session.
*/
(function() {
"use strict";
// This test makes assertions about the number of sessions, which are not compatible with
// implicit sessions.
TestData.disableImplicitSessions = true;
let replTest = new ReplSetTest({
name: 'reaping',
nodes: [
{/* primary */},
{/* secondary */ rsConfig: {priority: 0}},
{/* arbiter */ rsConfig: {arbiterOnly: true}}
],
nodeOptions: {
setParameter: {
TransactionRecordMinimumLifetimeMinutes: 0,
storeFindAndModifyImagesInSideCollection: true
}
}
});
let nodes = replTest.startSet();
replTest.initiate();
let primary = replTest.getPrimary();
let sessionsCollOnPrimary = primary.getDB("config").system.sessions;
let transactionsCollOnPrimary = primary.getDB("config").transactions;
let imageCollOnPrimary = primary.getDB("config").image_collection;
replTest.awaitSecondaryNodes();
let secondary = replTest.getSecondary();
let arbiter = replTest.getArbiter();
const dbName = jsTestName();
const collName = "test";
const reapErrorMsgRegex =
new RegExp("Sessions collection is not set up.*waiting until next sessions reap interval");
// Set up a session with a retryable insert and findAndModify.
let session = primary.startSession({retryWrites: 1});
assert.commandWorked(session.getDatabase(dbName)[collName].save({x: 1}));
let result =
session.getDatabase(dbName)[collName].findAndModify({query: {x: 1}, update: {$set: {y: 1}}});
// The findAndModify helper returns the document and not the whole response. Assert on the value of
// `x`. Though it's expected a command error would become an exception that fails the test.
assert.eq(1, result['x'], "Whole result: " + result);
assert.commandWorked(primary.adminCommand({refreshLogicalSessionCacheNow: 1}));
assert.eq(1, sessionsCollOnPrimary.find().itcount());
assert.eq(1, transactionsCollOnPrimary.find().itcount());
assert.eq(1, imageCollOnPrimary.find().itcount());
// Remove the session doc so the session gets reaped when reapLogicalSessionCacheNow is run.
assert.commandWorked(sessionsCollOnPrimary.remove({}));
// Test that a reap on a secondary does not lead to the on-disk state reaping of the session
// since the session does not exist in the secondary's session catalog.
{
assert.commandWorked(secondary.adminCommand({clearLog: 'global'}));
assert.commandWorked(secondary.adminCommand({reapLogicalSessionCacheNow: 1}));
assert.eq(1, transactionsCollOnPrimary.find().itcount());
assert.eq(false, checkLog.checkContainsOnce(secondary, reapErrorMsgRegex));
}
// Test that a reap on an arbiter does not lead to reaping of the session.
{
assert.commandWorked(arbiter.adminCommand({clearLog: 'global'}));
assert.commandWorked(arbiter.adminCommand({reapLogicalSessionCacheNow: 1}));
assert.eq(1, transactionsCollOnPrimary.find().itcount());
if (!jsTest.options().useRandomBinVersionsWithinReplicaSet) {
// Verify that the arbiter did not try to reap the session.
assert.eq(false, checkLog.checkContainsOnce(arbiter, reapErrorMsgRegex));
}
}
// Test that a reap on the primary works as expected.
{
assert.commandWorked(primary.adminCommand({clearLog: 'global'}));
assert.commandWorked(primary.adminCommand({reapLogicalSessionCacheNow: 1}));
assert.eq(0, transactionsCollOnPrimary.find().itcount());
assert.eq(0, imageCollOnPrimary.find().itcount());
}
replTest.stopSet();
})();
|