mongo/jstests/multiVersion/genericBinVersion/query-execution-query-settings/query_settings_upgrade_down...

210 lines
9.7 KiB
JavaScript

/**
* Tests that the 'representativeQueries' are migrated to the dedicated collection on FCV upgrade
* and back to 'querySettings' cluster parameter on FCV downgrade.
*
* @tags: [requires_fcv_83]
**/
import {assertDropAndRecreateCollection} from "jstests/libs/collection_drop_recreate.js";
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {describe, it} from "jstests/libs/mochalite.js";
import {QuerySettingsUtils} from "jstests/libs/query/query_settings_utils.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
import {testPerformUpgradeReplSet} from "jstests/multiVersion/libs/mixed_version_fixture_test.js";
import {testPerformUpgradeSharded} from "jstests/multiVersion/libs/mixed_version_sharded_fixture_test.js";
const dbName = "test";
const collName = jsTestName();
const getDB = (primaryConnection) => primaryConnection.getDB(jsTestName());
describe("QuerySettings", function () {
describe("should migrate 'representativeQueries' to the dedicated collection on FCV upgrade and migrate it back to 'querySettings' cluster parameter on FCV downgrade", function () {
let qsutils;
let queryA;
let queryB;
const exampleQuerySettings = {reject: true};
const setupFn = function (conn) {
const db = getDB(conn);
const coll = assertDropAndRecreateCollection(db, collName);
qsutils = new QuerySettingsUtils(db, coll.getName());
qsutils.removeAllQuerySettings();
queryA = qsutils.makeFindQueryInstance({filter: {a: 15}});
queryB = qsutils.makeFindQueryInstance({filter: {b: 15}});
assert.commandWorked(db.adminCommand({setQuerySettings: queryA, settings: exampleQuerySettings}));
assert.commandWorked(db.adminCommand({setQuerySettings: queryB, settings: exampleQuerySettings}));
};
const assertQueryShapeConfigurations = function (isFullyUpgraded) {
return function (conn) {
qsutils.assertQueryShapeConfiguration([
qsutils.makeQueryShapeConfiguration(exampleQuerySettings, queryA),
qsutils.makeQueryShapeConfiguration(exampleQuerySettings, queryB),
]);
// Ensure that the 'representativeQueries' are migrated to the dedicated
// collection.
const isBackfillEnabled = FeatureFlagUtil.isPresentAndEnabled(getDB(conn).getMongo(), "PQSBackfill");
const expectedRepresentativeQueries = isFullyUpgraded && isBackfillEnabled ? [queryA, queryB] : [];
qsutils.assertRepresentativeQueries(expectedRepresentativeQueries);
};
};
const assertQueryShapeConfigurationsWithEmptyRepresentativeQueries = assertQueryShapeConfigurations(false);
const assertQueryShapeConfigurationsWithMigratedRepresentativeQueries = assertQueryShapeConfigurations(true);
it("in replica set", function () {
testPerformUpgradeReplSet({
setupFn,
whenFullyDowngraded: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenSecondariesAreLatestBinary: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenBinariesAreLatestAndFCVIsLastLTS: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenFullyUpgraded: assertQueryShapeConfigurationsWithMigratedRepresentativeQueries,
});
});
it("in sharded cluster", function () {
testPerformUpgradeSharded({
setupFn,
whenFullyDowngraded: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenOnlyConfigIsLatestBinary: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenSecondariesAndConfigAreLatestBinary: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenMongosBinaryIsLastLTS: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenBinariesAreLatestAndFCVIsLastLTS: assertQueryShapeConfigurationsWithEmptyRepresentativeQueries,
whenFullyUpgraded: assertQueryShapeConfigurationsWithMigratedRepresentativeQueries,
});
});
});
describe("should migrate as many 'representativeQuery's as possible on FCV downgrade and not fail with BSONObjectTooLarge exception", function () {
function runTest(db) {
const qsutils = new QuerySettingsUtils(db, collName);
const queryA = qsutils.makeFindQueryInstance({filter: {a: "a".repeat(9 * 1024 * 1024)}});
const queryB = qsutils.makeFindQueryInstance({filter: {b: "b".repeat(10 * 1024 * 1024)}});
for (const queryInstance of [queryA, queryB]) {
assert.commandWorked(db.adminCommand({setQuerySettings: queryInstance, settings: {reject: true}}));
}
// Perform FCV downgrade to the last LTS version, which should migrate
// representativeQueries back to the 'querySettings' cluster parameter.
assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV, confirm: true}));
const expectedQuerySettings = [
{
"settings": {"reject": true},
"representativeQuery": {
"find": "query_settings_upgrade_downgrade",
"$db": "test",
"filter": {"a": "a".repeat(9 * 1024 * 1024)},
},
},
{"settings": {"reject": true}},
];
// Wrap the assertion into assert.soon as mongos needs some time to refresh
// 'querySettings' cluster parameter value.
assert.soonNoExcept(() => {
assert.sameMembers(qsutils.getQuerySettings(), expectedQuerySettings);
return true;
});
// Clean up all query settings.
qsutils.removeAllQuerySettings();
}
it("in replica set", function () {
const rst = new ReplSetTest({nodes: 2, nodeOptions: {binVersion: "latest"}});
rst.startSet();
rst.initiate();
const db = rst.getPrimary().getDB(dbName);
try {
runTest(db);
} finally {
rst.stopSet();
}
});
it("in sharded cluster", function () {
const st = new ShardingTest({shards: 1, mongos: 1, config: 1, rs: {nodes: 2}});
const db = st.s.getDB(dbName);
try {
runTest(db);
} finally {
st.stop();
}
});
});
describe("should perform FCV upgrade and downgrade successully after first failed attempt due to repeated failure of setClusterParamater command", function () {
function runTest(db) {
// Ensure we are on the last LTS FCV before starting the test.
assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV, confirm: true}));
const qsutils = new QuerySettingsUtils(db, collName);
const queryA = qsutils.makeFindQueryInstance({filter: {a: 1}});
const queryB = qsutils.makeFindQueryInstance({filter: {b: "string"}});
for (const queryInstance of [queryA, queryB]) {
assert.commandWorked(db.adminCommand({setQuerySettings: queryInstance, settings: {reject: true}}));
}
qsutils.assertQueryShapeConfiguration(
[
qsutils.makeQueryShapeConfiguration({reject: true}, queryA),
qsutils.makeQueryShapeConfiguration({reject: true}, queryB),
],
false /* shouldRunExplain */,
);
// Attempt to upgrade the FCV, which should fail due to the failpoint.
qsutils.withFailpoint("throwConflictingOperationInProgressOnQuerySettingsSetClusterParameter", {}, () => {
assert.commandFailedWithCode(
db.adminCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}),
ErrorCodes.TemporarilyUnavailable,
);
});
// Run FCV upgrade command again, which should succeed now.
assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
// Attempt to downgrade the FCV, which should fail due to the failpoint.
qsutils.withFailpoint("throwConflictingOperationInProgressOnQuerySettingsSetClusterParameter", {}, () => {
assert.commandFailedWithCode(
db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV, confirm: true}),
ErrorCodes.TemporarilyUnavailable,
);
});
// Run FCV downgrade command again, which should succeed now.
assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV, confirm: true}));
// Clean up all query settings.
qsutils.removeAllQuerySettings();
}
it("in replica set", function () {
const rst = new ReplSetTest({nodes: 2, nodeOptions: {binVersion: "latest"}});
rst.startSet();
rst.initiate();
const db = rst.getPrimary().getDB(dbName);
try {
runTest(db);
} finally {
rst.stopSet();
}
});
it("in sharded cluster", function () {
const st = new ShardingTest({shards: 1, mongos: 1, config: 1, rs: {nodes: 2}});
const db = st.s.getDB(dbName);
try {
runTest(db);
} finally {
st.stop();
}
});
});
});