mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-30 00:56:44 +01:00
110 lines
4.4 KiB
JavaScript
110 lines
4.4 KiB
JavaScript
/**
|
|
* Test that the find command can spill to disk while executing a blocking sort, if the client
|
|
* explicitly allows disk usage.
|
|
*
|
|
* Must be run with read commands enabled, since legacy OP_QUERY reads do not support the
|
|
* 'allowDiskUse' parameter.
|
|
* @tags: [requires_find_command]
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
load("jstests/libs/analyze_plan.js");
|
|
|
|
// Only allow blocking sort execution to use 100 kB of memory.
|
|
const kMaxMemoryUsageBytes = 100 * 1024;
|
|
|
|
const kNumDocsWithinMemLimit = 70;
|
|
const kNumDocsExceedingMemLimit = 100;
|
|
|
|
const options = {
|
|
setParameter: "internalQueryMaxBlockingSortMemoryUsageBytes=" + kMaxMemoryUsageBytes
|
|
};
|
|
const conn = MongoRunner.runMongod(options);
|
|
assert.neq(null, conn, "mongod was unable to start up with options: " + tojson(options));
|
|
|
|
const testDb = conn.getDB("test");
|
|
const collection = testDb.external_sort_find;
|
|
|
|
// Construct a document that is just over 1 kB.
|
|
const charToRepeat = "-";
|
|
const templateDoc = {
|
|
padding: charToRepeat.repeat(1024)
|
|
};
|
|
|
|
// Insert data into the collection without exceeding the memory threshold.
|
|
for (let i = 0; i < kNumDocsWithinMemLimit; ++i) {
|
|
templateDoc.sequenceNumber = i;
|
|
assert.commandWorked(collection.insert(templateDoc));
|
|
}
|
|
|
|
// We should be able to successfully sort the collection with or without disk use allowed.
|
|
assert.eq(kNumDocsWithinMemLimit, collection.find().sort({sequenceNumber: -1}).itcount());
|
|
assert.eq(kNumDocsWithinMemLimit,
|
|
collection.find().sort({sequenceNumber: -1}).allowDiskUse().itcount());
|
|
|
|
function getSortStats(allowDiskUse) {
|
|
let cursor = collection.find().sort({sequenceNumber: -1});
|
|
if (allowDiskUse) {
|
|
cursor = cursor.allowDiskUse();
|
|
}
|
|
const explain = cursor.explain("executionStats");
|
|
return getPlanStage(explain.executionStats.executionStages, "SORT");
|
|
}
|
|
|
|
// Explain should report that less than 100 kB of memory was used, and we did not spill to disk.
|
|
// Test that this result is the same whether or not 'allowDiskUse' is set.
|
|
let sortStats = getSortStats(false);
|
|
assert.eq(sortStats.memLimit, kMaxMemoryUsageBytes);
|
|
assert.lt(sortStats.totalDataSizeSorted, kMaxMemoryUsageBytes);
|
|
assert.eq(sortStats.usedDisk, false);
|
|
sortStats = getSortStats(true);
|
|
assert.eq(sortStats.memLimit, kMaxMemoryUsageBytes);
|
|
assert.lt(sortStats.totalDataSizeSorted, kMaxMemoryUsageBytes);
|
|
assert.eq(sortStats.usedDisk, false);
|
|
|
|
// Add enough data to exceed the memory threshold.
|
|
for (let i = kNumDocsWithinMemLimit; i < kNumDocsExceedingMemLimit; ++i) {
|
|
templateDoc.sequenceNumber = i;
|
|
assert.commandWorked(collection.insert(templateDoc));
|
|
}
|
|
|
|
// The sort should fail if disk use is not allowed, but succeed if disk use is allowed.
|
|
assert.commandFailedWithCode(
|
|
testDb.runCommand({find: collection.getName(), sort: {sequenceNumber: -1}}),
|
|
ErrorCodes.QueryExceededMemoryLimitNoDiskUseAllowed);
|
|
assert.eq(kNumDocsExceedingMemLimit,
|
|
collection.find().sort({sequenceNumber: -1}).allowDiskUse().itcount());
|
|
|
|
// Explain should report that the SORT stage failed if disk use is not allowed.
|
|
sortStats = getSortStats(false);
|
|
assert.eq(sortStats.failed, true);
|
|
assert.eq(sortStats.usedDisk, false);
|
|
assert.lt(sortStats.totalDataSizeSorted, kMaxMemoryUsageBytes);
|
|
assert(!sortStats.inputStage.hasOwnProperty("failed"));
|
|
|
|
// Explain should report that >=100 kB of memory was used, and that we spilled to disk.
|
|
sortStats = getSortStats(true);
|
|
assert.eq(sortStats.memLimit, kMaxMemoryUsageBytes);
|
|
assert.gte(sortStats.totalDataSizeSorted, kMaxMemoryUsageBytes);
|
|
assert.eq(sortStats.usedDisk, true);
|
|
|
|
// If disk use is not allowed but there is a limit, we should be able to avoid exceeding the memory
|
|
// limit.
|
|
assert.eq(kNumDocsWithinMemLimit,
|
|
collection.find().sort({sequenceNumber: -1}).limit(kNumDocsWithinMemLimit).itcount());
|
|
|
|
// Create a view on top of the collection. When a find command is run against the view without disk
|
|
// use allowed, the command should fail with the expected error code. When the find command allows
|
|
// disk use, however, the command should succeed.
|
|
assert.commandWorked(testDb.createView("identityView", collection.getName(), []));
|
|
const identityView = testDb.identityView;
|
|
assert.commandFailedWithCode(
|
|
testDb.runCommand({find: identityView.getName(), sort: {sequenceNumber: -1}}),
|
|
ErrorCodes.QueryExceededMemoryLimitNoDiskUseAllowed);
|
|
assert.eq(kNumDocsExceedingMemLimit,
|
|
identityView.find().sort({sequenceNumber: -1}).allowDiskUse().itcount());
|
|
|
|
MongoRunner.stopMongod(conn);
|
|
}());
|