0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00
mongodb/jstests/noPassthrough/verify_sessions_expiration.js
2019-07-27 11:02:23 -04:00

144 lines
5.1 KiB
JavaScript

// Tests valid coordination of the expiration and vivification of documents between the
// config.system.sessions collection and the logical session cache.
//
// 1. Sessions should be removed from the logical session cache when they expire from
// the config.system.sessions collection.
// 2. getMores run on open cursors should update the lastUse field on documents in the
// config.system.sessions collection, prolonging the time for expiration on said document
// and corresponding session.
// 3. Open cursors that are not currently in use should be killed when their corresponding sessions
// expire from the config.system.sessions collection.
// 4. Currently running operations corresponding to a session should prevent said session from
// expiring from the config.system.sessions collection. If the expiration date has been reached
// during a currently running operation, the logical session cache should vivify the session and
// replace it in the config.system.sessions collection.
(function() {
"use strict";
// This test makes assertions about the number of logical session records.
TestData.disableImplicitSessions = true;
load("jstests/libs/pin_getmore_cursor.js"); // For "withPinnedCursor".
const refresh = {
refreshLogicalSessionCacheNow: 1
};
const startSession = {
startSession: 1
};
const failPointName = "waitAfterPinningCursorBeforeGetMoreBatch";
function refreshSessionsAndVerifyCount(config, expectedCount) {
config.runCommand(refresh);
assert.eq(config.system.sessions.count(), expectedCount);
}
function getSessions(config) {
return config.system.sessions.aggregate([{'$listSessions': {allUsers: true}}]).toArray();
}
function verifyOpenCursorCount(db, expectedCount) {
assert.eq(db.serverStatus().metrics.cursor.open.total, expectedCount);
}
const dbName = "test";
const testCollName = "verify_sessions_find_get_more";
let conn = MongoRunner.runMongod();
let db = conn.getDB(dbName);
let config = conn.getDB("config");
// 1. Verify that sessions expire from config.system.sessions after the timeout has passed.
for (let i = 0; i < 5; i++) {
let res = db.runCommand(startSession);
assert.commandWorked(res, "unable to start session");
}
refreshSessionsAndVerifyCount(config, 5);
// Manually delete entries in config.system.sessions to simulate TTL expiration.
assert.commandWorked(config.system.sessions.remove({}));
refreshSessionsAndVerifyCount(config, 0);
// 2. Verify that getMores after finds will update the 'lastUse' field on documents in the
// config.system.sessions collection.
for (let i = 0; i < 10; i++) {
db[testCollName].insert({_id: i, a: i, b: 1});
}
let cursors = [];
for (let i = 0; i < 5; i++) {
let session = db.getMongo().startSession({});
assert.commandWorked(session.getDatabase("admin").runCommand({usersInfo: 1}),
"initialize the session");
cursors.push(session.getDatabase(dbName)[testCollName].find({b: 1}).batchSize(1));
assert(cursors[i].hasNext());
}
refreshSessionsAndVerifyCount(config, 5);
verifyOpenCursorCount(config, 5);
let sessionsCollectionArray;
let lastUseValues = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < cursors.length; j++) {
cursors[j].next();
}
refreshSessionsAndVerifyCount(config, 5);
verifyOpenCursorCount(config, 5);
sessionsCollectionArray = getSessions(config);
if (i == 0) {
for (let j = 0; j < sessionsCollectionArray.length; j++) {
lastUseValues.push(sessionsCollectionArray[j].lastUse);
}
} else {
for (let j = 0; j < sessionsCollectionArray.length; j++) {
assert.gt(sessionsCollectionArray[j].lastUse, lastUseValues[j]);
lastUseValues[j] = sessionsCollectionArray[j].lastUse;
}
}
}
// 3. Verify that letting sessions expire (simulated by manual deletion) will kill their
// cursors.
assert.commandWorked(config.system.sessions.remove({}));
refreshSessionsAndVerifyCount(config, 0);
verifyOpenCursorCount(config, 0);
for (let i = 0; i < cursors.length; i++) {
assert.commandFailedWithCode(
db.runCommand({getMore: cursors[i]._cursor._cursorid, collection: testCollName}),
ErrorCodes.CursorNotFound,
'expected getMore to fail because the cursor was killed');
}
// 4. Verify that an expired session (simulated by manual deletion) that has a currently running
// operation will be vivified during the logical session cache refresh.
let pinnedCursorSession = db.getMongo().startSession();
withPinnedCursor({
conn: conn,
db: pinnedCursorSession.getDatabase(dbName),
assertFunction: (cursorId, coll) => {
assert.commandWorked(config.system.sessions.remove({}));
refreshSessionsAndVerifyCount(config, 1);
verifyOpenCursorCount(config, 1);
let db = coll.getDB();
assert.commandWorked(db.runCommand({killCursors: coll.getName(), cursors: [cursorId]}));
},
sessionId: pinnedCursorSession,
runGetMoreFunc: () => {
assert.commandFailed(
db.runCommand({getMore: cursorId, collection: collName, lsid: sessionId}));
},
failPointName: failPointName,
});
MongoRunner.stopMongod(conn);
})();