125 lines
4.8 KiB
JavaScript
125 lines
4.8 KiB
JavaScript
// Basic integration tests for the background job that periodically kills idle cursors, in both
|
|
// mongod and mongos. This test creates the following four cursors:
|
|
//
|
|
// 1. A no-timeout cursor through mongos.
|
|
// 2. A no-timeout cursor through mongod.
|
|
// 3. A normal cursor through mongos.
|
|
// 4. A normal cursor through mongod.
|
|
//
|
|
// After a period of inactivity, the test asserts that cursors #1 and #2 are still alive, and that
|
|
// #3 and #4 have been killed.
|
|
(function() {
|
|
'use strict';
|
|
|
|
// Cursor timeout on mongod is handled by a single thread/timer that will sleep for
|
|
// "clientCursorMonitorFrequencySecs" and add the sleep value to each operation's duration when
|
|
// it wakes up, timing out those whose "now() - last accessed since" time exceeds. A cursor
|
|
// timeout of 2 seconds with a monitor frequency of 1 second means an effective timeout period
|
|
// of 1 to 2 seconds.
|
|
const mongodCursorTimeoutMs = 2000;
|
|
|
|
// Cursor timeout on mongos is handled by checking whether the "last accessed" cursor time stamp
|
|
// is older than "now() - cursorTimeoutMillis" and is checked every
|
|
// "clientCursorMonitorFrequencySecs" by a global thread/timer. A timeout of 1 second with a
|
|
// monitor frequency of 1 second means an effective timeout period of 1 to 2 seconds.
|
|
const mongosCursorTimeoutMs = 1000;
|
|
|
|
const cursorMonitorFrequencySecs = 1;
|
|
|
|
var st = new ShardingTest({
|
|
shards: 2,
|
|
other: {
|
|
chunkSize: 1,
|
|
shardOptions: {
|
|
verbose: 1,
|
|
setParameter: {
|
|
cursorTimeoutMillis: mongodCursorTimeoutMs,
|
|
clientCursorMonitorFrequencySecs: cursorMonitorFrequencySecs
|
|
}
|
|
},
|
|
mongosOptions: {
|
|
verbose: 1,
|
|
setParameter: {
|
|
cursorTimeoutMillis: mongosCursorTimeoutMs,
|
|
clientCursorMonitorFrequencySecs: cursorMonitorFrequencySecs
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var adminDB = st.admin;
|
|
var configDB = st.config;
|
|
var coll = st.s.getDB('test').user;
|
|
|
|
assert.commandWorked(adminDB.runCommand({enableSharding: coll.getDB().getName()}));
|
|
st.ensurePrimaryShard(coll.getDB().getName(), 'shard0001');
|
|
assert.commandWorked(adminDB.runCommand({shardCollection: coll.getFullName(), key: {x: 1}}));
|
|
|
|
var data = 'c';
|
|
for (var x = 0; x < 18; x++) {
|
|
data += data;
|
|
}
|
|
|
|
for (x = 0; x < 200; x++) {
|
|
coll.insert({x: x, v: data});
|
|
}
|
|
|
|
var chunkDoc = configDB.chunks.findOne();
|
|
var chunkOwner = chunkDoc.shard;
|
|
var toShard = configDB.shards.findOne({_id: {$ne: chunkOwner}})._id;
|
|
var cmd =
|
|
{moveChunk: coll.getFullName(), find: chunkDoc.min, to: toShard, _waitForDelete: true};
|
|
var res = adminDB.runCommand(cmd);
|
|
|
|
jsTest.log('move result: ' + tojson(res));
|
|
|
|
var shardedCursorWithTimeout = coll.find();
|
|
var shardedCursorWithNoTimeout = coll.find();
|
|
shardedCursorWithNoTimeout.addOption(DBQuery.Option.noTimeout);
|
|
|
|
// Query directly to mongod
|
|
var shardHost = configDB.shards.findOne({_id: chunkOwner}).host;
|
|
var mongod = new Mongo(shardHost);
|
|
var shardColl = mongod.getCollection(coll.getFullName());
|
|
|
|
var cursorWithTimeout = shardColl.find();
|
|
var cursorWithNoTimeout = shardColl.find();
|
|
cursorWithNoTimeout.addOption(DBQuery.Option.noTimeout);
|
|
|
|
shardedCursorWithTimeout.next();
|
|
shardedCursorWithNoTimeout.next();
|
|
|
|
cursorWithTimeout.next();
|
|
cursorWithNoTimeout.next();
|
|
|
|
// Wait until the idle cursor background job has killed the cursors that do not have the "no
|
|
// timeout" flag set. We use the "cursorTimeoutMillis" and "clientCursorMonitorFrequencySecs"
|
|
// setParameters above to reduce the amount of time we need to wait here.
|
|
assert.soon(function() {
|
|
return coll.getDB().serverStatus().metrics.cursor.timedOut > 0;
|
|
}, "sharded cursor failed to time out");
|
|
|
|
// Wait for the shard to have two open cursors on it (shardedCursorWithNoTimeout and
|
|
// cursorWithNoTimeout).
|
|
// We cannot reliably use metrics.cursor.timedOut here, because this will be 2 if
|
|
// shardedCursorWithTimeout is killed for timing out on the shard, and 1 if
|
|
// shardedCursorWithTimeout is killed by a killCursors command from the mongos.
|
|
assert.soon(function() {
|
|
return shardColl.getDB().serverStatus().metrics.cursor.open.total == 2;
|
|
}, "cursor failed to time out");
|
|
|
|
assert.throws(function() {
|
|
shardedCursorWithTimeout.itcount();
|
|
});
|
|
assert.throws(function() {
|
|
cursorWithTimeout.itcount();
|
|
});
|
|
|
|
// +1 because we already advanced once
|
|
assert.eq(coll.count(), shardedCursorWithNoTimeout.itcount() + 1);
|
|
|
|
assert.eq(shardColl.count(), cursorWithNoTimeout.itcount() + 1);
|
|
|
|
st.stop();
|
|
})();
|