mirror of https://github.com/mongodb/mongo
150 lines
6.3 KiB
JavaScript
150 lines
6.3 KiB
JavaScript
/**
|
|
* Confirms that, for a query with 'allowPartialResults' enabled, the 'nShards' log entry reflects
|
|
* the number of shards that were actually available during each find or getMore operation.
|
|
* @tags: [
|
|
* requires_replication,
|
|
* requires_sharding,
|
|
* ]
|
|
*/
|
|
|
|
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
|
|
|
// This test looks for exact matches in log output, which does not account for implicit sessions.
|
|
TestData.disableImplicitSessions = true;
|
|
|
|
// Prevent the mongo shell from gossiping its cluster time, since this will increase the amount
|
|
// of data logged for each op. For some of the testcases below, including the cluster time would
|
|
// cause them to be truncated at the 512-byte RamLog limit, and some of the fields we need to
|
|
// check would be lost.
|
|
TestData.skipGossipingClusterTime = true;
|
|
|
|
// Skip the following checks across the cluster at the end, since the test shuts down a shard.
|
|
TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
|
|
TestData.skipCheckingIndexesConsistentAcrossCluster = true;
|
|
TestData.skipCheckShardFilteringMetadata = true;
|
|
|
|
// Set up a 2-shard single-node replicaset cluster.
|
|
const st = new ShardingTest({name: jsTestName(), shards: 2, rs: {nodes: 1}});
|
|
|
|
// Obtain a connection to the test database on mongoS, and to the test collection.
|
|
const mongosDB = st.s.getDB(jsTestName());
|
|
const testColl = mongosDB.test;
|
|
|
|
// Enable sharding on the the test database and ensure that the primary is on shard0.
|
|
assert.commandWorked(mongosDB.adminCommand({enableSharding: mongosDB.getName(), primaryShard: st.rs1.getURL()}));
|
|
|
|
// Shard the collection on _id, split at {_id:0}, and move the upper chunk to the second shard.
|
|
st.shardColl(testColl, {_id: 1}, {_id: 0}, {_id: 1}, mongosDB.getName(), true);
|
|
|
|
// Insert 10 documents on each shard, in the range [-10, 10).
|
|
for (let i = -10; i < 10; ++i) {
|
|
assert.commandWorked(testColl.insert({_id: i}));
|
|
}
|
|
|
|
// Set the slowms threshold to -1 on mongoS, so that all operations will be logged.
|
|
assert.commandWorked(mongosDB.adminCommand({profile: 0, slowms: -1}));
|
|
|
|
// Helper to find a logline containing all the specified fields. Throws if no such line exists.
|
|
function assertMatchingLogLineExists(fields) {
|
|
function escapeRegex(input) {
|
|
return typeof input === "string" ? input.replace(/[\^\$\\\.\*\+\?\(\)\[\]\{\}]/g, "\\$&") : input;
|
|
}
|
|
function lineMatches(line, fields) {
|
|
const fieldNames = Object.keys(fields);
|
|
return fieldNames.every((fieldName) => {
|
|
const fieldValue = fields[fieldName];
|
|
let regex;
|
|
const regexDecimal =
|
|
'"' +
|
|
escapeRegex(fieldName) +
|
|
'":? ?(' +
|
|
escapeRegex(checkLog.formatAsJsonLogLine(fieldValue, false, true)) +
|
|
"|" +
|
|
escapeRegex(checkLog.formatAsJsonLogLine(fieldValue, true, true)) +
|
|
")";
|
|
|
|
const regexNoDecimal =
|
|
'"' +
|
|
escapeRegex(fieldName) +
|
|
'":? ?(' +
|
|
escapeRegex(checkLog.formatAsJsonLogLine(fieldValue, false, false)) +
|
|
"|" +
|
|
escapeRegex(checkLog.formatAsJsonLogLine(fieldValue, true, false)) +
|
|
")";
|
|
|
|
const matchDecimal = line.match(regexDecimal);
|
|
const matchNoDecimal = line.match(regexNoDecimal);
|
|
return (matchDecimal && matchDecimal[0]) || (matchNoDecimal && matchNoDecimal[0]);
|
|
});
|
|
}
|
|
|
|
const globalLog = assert.commandWorked(mongosDB.adminCommand({getLog: "global"}));
|
|
assert(
|
|
globalLog.log.find((line) => lineMatches(line, fields)),
|
|
"failed to find log line ",
|
|
);
|
|
}
|
|
|
|
// Issue a query with {allowPartialResults:true} on the collection. We sort by {_id:1} so that all
|
|
// results from shard0 will be returned before any from shard1. We also set a small batchSize so
|
|
// that not all results are returned at once.
|
|
const findCmd = {
|
|
find: testColl.getName(),
|
|
filter: {},
|
|
sort: {_id: 1},
|
|
allowPartialResults: true,
|
|
comment: "allow_partial_results_find_nshards_2",
|
|
batchSize: 2,
|
|
};
|
|
let findRes = assert.commandWorked(mongosDB.runCommand(findCmd));
|
|
|
|
// Confirm that the cursor did not report partial results, and that the command logs {nShards:2}.
|
|
assertMatchingLogLineExists(Object.assign({nShards: 2}, findCmd));
|
|
assert.eq(findRes.cursor.partialResultsReturned, undefined);
|
|
|
|
// Issue a getMore with the same batchSize...
|
|
const getMoreCmd = {
|
|
getMore: findRes.cursor.id,
|
|
collection: testColl.getName(),
|
|
comment: "allow_partial_results_getmore_nshards_2",
|
|
batchSize: 2,
|
|
};
|
|
let getMoreRes = assert.commandWorked(mongosDB.runCommand(getMoreCmd));
|
|
|
|
// ... and confirm that nShards is still 2.
|
|
assertMatchingLogLineExists(Object.assign({nShards: 2}, getMoreCmd));
|
|
assert.eq(getMoreRes.cursor.partialResultsReturned, undefined);
|
|
|
|
// Now stop shard0.
|
|
st.rs1.stopSet();
|
|
|
|
// Issue another getMore with a higher batchSize.
|
|
getMoreCmd.comment = "allow_partial_results_getmore_nshards_2_again";
|
|
getMoreCmd.batchSize = 4;
|
|
getMoreRes = assert.commandWorked(mongosDB.runCommand(getMoreCmd));
|
|
|
|
// We record the number of shards at the outset of the getMore, so this should again result in a
|
|
// logline with nShards:2. But the larger batchSize burns through all results that mongoS buffered
|
|
// from shard0 before it went down, and when we attempt to acquire a new batch from the shard we
|
|
// discover that it is no longer available. We therefore return {partialResultsReturned:true}.
|
|
assertMatchingLogLineExists(Object.assign({nShards: 2}, getMoreCmd));
|
|
assert.eq(getMoreRes.cursor.partialResultsReturned, true);
|
|
|
|
// When we issue the next getMore, shard0 has already been marked as unavailable...
|
|
getMoreCmd.comment = "allow_partial_results_getmore_nshards_1";
|
|
getMoreRes = assert.commandWorked(mongosDB.runCommand(getMoreCmd));
|
|
|
|
// ... so nShards is now 1. The 'partialResultsReturned' cursor field remains true.
|
|
assertMatchingLogLineExists(Object.assign({nShards: 1}, getMoreCmd));
|
|
assert.eq(getMoreRes.cursor.partialResultsReturned, true);
|
|
|
|
// Finally, issue the original 'find' command again...
|
|
findCmd.comment = "allow_partial_results_find_nshards_1";
|
|
findRes = assert.commandWorked(mongosDB.runCommand(findCmd));
|
|
|
|
// ... and confirm that nShards is 1 now that one shard is down.
|
|
assertMatchingLogLineExists(Object.assign({nShards: 1}, findCmd));
|
|
assert.eq(findRes.cursor.partialResultsReturned, true);
|
|
|
|
st.stop();
|