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
|
/**
* Enables sessions on the db object
*/
(function() {
"use strict";
var runCommandOriginal = Mongo.prototype.runCommand;
var runCommandWithMetadataOriginal = Mongo.prototype.runCommandWithMetadata;
var getDBOriginal = Mongo.prototype.getDB;
var sessionMap = new WeakMap();
let sessionOptions = {};
if (typeof TestData !== "undefined" && TestData.hasOwnProperty("sessionOptions")) {
sessionOptions = TestData.sessionOptions;
}
const driverSession = startSession(db.getMongo());
db = driverSession.getDatabase(db.getName());
sessionMap.set(db.getMongo(), driverSession);
var originalStartParallelShell = startParallelShell;
startParallelShell = function(jsCode, port, noConnect) {
var newCode;
var overridesFile = "jstests/libs/override_methods/enable_sessions.js";
if (typeof(jsCode) === "function") {
// Load the override file and immediately invoke the supplied function.
newCode = `load("${overridesFile}"); (${jsCode})();`;
} else {
newCode = `load("${overridesFile}"); ${jsCode};`;
}
return originalStartParallelShell(newCode, port, noConnect);
};
function startSession(conn) {
const driverSession = conn.startSession(sessionOptions);
// Override the endSession function to be a no-op so fuzzer doesn't accidentally end the
// session.
driverSession.endSession = Function.prototype;
return driverSession;
}
// Override the runCommand to check for any command obj that does not contain a logical session
// and throw an error.
function runCommandWithLsidCheck(conn, dbName, cmdObj, func, funcArgs) {
const 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.
let cmdObjUnwrapped = cmdObj;
if (cmdName === "query" || cmdName === "$query") {
cmdObj[cmdName] = Object.assign({}, cmdObj[cmdName]);
cmdObjUnwrapped = cmdObj[cmdName];
}
if (!cmdObjUnwrapped.hasOwnProperty("lsid")) {
// TODO: SERVER-30848 fixes getMore requests to use a session in the mongo shell.
// Until that happens, we bypass throwing an error for getMore and only throw an error
// for other requests not using sessions.
if (cmdName !== "getMore") {
throw new Error("command object does not have session id: " + tojson(cmdObj));
}
}
return func.apply(conn, funcArgs);
}
Mongo.prototype.runCommand = function(dbName, commandObj, options) {
return runCommandWithLsidCheck(this, dbName, commandObj, runCommandOriginal, arguments);
};
Mongo.prototype.runCommandWithMetadata = function(dbName, metadata, commandObj) {
return runCommandWithLsidCheck(
this, dbName, commandObj, runCommandWithMetadataOriginal, arguments);
};
// Override the getDB to return a db object with the correct driverSession. We use a WeakMap
// to cache the session for each connection instance so we can retrieve the same session on
// subsequent calls to getDB.
Mongo.prototype.getDB = function(dbName) {
if (!sessionMap.has(this)) {
const session = startSession(this);
sessionMap.set(this, session);
}
const db = getDBOriginal.apply(this, arguments);
db._session = sessionMap.get(this);
return db;
};
})();
|