mirror of https://github.com/mongodb/mongo
179 lines
6.7 KiB
JavaScript
179 lines
6.7 KiB
JavaScript
/**
|
|
* Test expected behavior for hidden indexes. A hidden index is invisible to the query planner so
|
|
* it will not be used in planning. It is handled in the same way as other indexes by the index
|
|
* catalog and for TTL purposes.
|
|
* @tags: [
|
|
* # CollMod is not retryable.
|
|
* requires_non_retryable_commands,
|
|
* not_allowed_with_signed_security_token,
|
|
* requires_capped,
|
|
* ]
|
|
*/
|
|
|
|
import {assertDropAndRecreateCollection} from "jstests/libs/collection_drop_recreate.js";
|
|
import {FixtureHelpers} from "jstests/libs/fixture_helpers.js";
|
|
import {IndexCatalogHelpers} from "jstests/libs/index_catalog_helpers.js";
|
|
import {getNumberOfIndexScans} from "jstests/libs/query/analyze_plan.js";
|
|
|
|
const collName = "hidden_index";
|
|
let coll = assertDropAndRecreateCollection(db, collName);
|
|
|
|
function numOfUsedIndexes(explain) {
|
|
return getNumberOfIndexScans(explain);
|
|
}
|
|
|
|
function validateHiddenIndexBehaviour({query = {}, projection = {}, index_type = 1, wildcard = false}) {
|
|
let index_name;
|
|
if (wildcard) index_name = "a.$**_" + index_type;
|
|
else index_name = "a_" + index_type;
|
|
|
|
if (wildcard) assert.commandWorked(coll.createIndex({"a.$**": index_type}));
|
|
else assert.commandWorked(coll.createIndex({"a": index_type}));
|
|
|
|
let idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), index_name);
|
|
assert.eq(idxSpec.hidden, undefined);
|
|
|
|
// Assert the plan is using an index scan.
|
|
let explain = assert.commandWorked(coll.find(query, projection).explain());
|
|
assert.gt(numOfUsedIndexes(explain), 0);
|
|
|
|
assert.commandWorked(coll.hideIndex(index_name));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), index_name);
|
|
assert(idxSpec.hidden);
|
|
if (index_type === "text") {
|
|
assert.commandFailedWithCode(coll.runCommand("find", {filter: query}, {hint: {a: 1}}), 291);
|
|
assert.commandWorked(coll.dropIndexes());
|
|
return;
|
|
}
|
|
|
|
// Assert the plan is not using an index scan.
|
|
explain = assert.commandWorked(coll.find(query, projection).explain());
|
|
assert.eq(numOfUsedIndexes(explain), 0);
|
|
|
|
assert.commandWorked(coll.unhideIndex(index_name));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), index_name);
|
|
assert.eq(idxSpec.hidden, undefined);
|
|
|
|
// Assert the plan is using an index scan.
|
|
explain = assert.commandWorked(coll.find(query, projection).explain());
|
|
assert.gt(numOfUsedIndexes(explain), 0);
|
|
|
|
assert.commandWorked(coll.dropIndex(index_name));
|
|
|
|
if (wildcard) assert.commandWorked(coll.createIndex({"a.$**": index_type}, {hidden: true}));
|
|
else assert.commandWorked(coll.createIndex({"a": index_type}, {hidden: true}));
|
|
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), index_name);
|
|
assert(idxSpec.hidden);
|
|
explain = assert.commandWorked(coll.find(query, projection).explain());
|
|
assert.eq(numOfUsedIndexes(explain), 0);
|
|
|
|
if (wildcard)
|
|
assert.commandFailedWithCode(
|
|
coll.createIndex({"a.$**": index_type}, {hidden: false}),
|
|
ErrorCodes.IndexOptionsConflict,
|
|
);
|
|
else
|
|
assert.commandFailedWithCode(
|
|
coll.createIndex({"a": index_type}, {hidden: false}),
|
|
ErrorCodes.IndexOptionsConflict,
|
|
);
|
|
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), index_name);
|
|
assert(idxSpec.hidden);
|
|
|
|
assert.commandWorked(coll.dropIndexes());
|
|
}
|
|
|
|
// Normal index testing.
|
|
validateHiddenIndexBehaviour({query: {a: 1}, index_type: 1});
|
|
|
|
// GEO index testing.
|
|
validateHiddenIndexBehaviour({
|
|
query: {
|
|
a: {
|
|
$geoWithin: {
|
|
$geometry: {
|
|
type: "Polygon",
|
|
coordinates: [
|
|
[
|
|
[0, 0],
|
|
[3, 6],
|
|
[6, 1],
|
|
[0, 0],
|
|
],
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
index_type: "2dsphere",
|
|
});
|
|
|
|
// Fts index.
|
|
validateHiddenIndexBehaviour({query: {$text: {$search: "java"}}, index_type: "text"});
|
|
|
|
// Wildcard index.
|
|
validateHiddenIndexBehaviour({query: {"a.f": 1}, index_type: 1, wildcard: true});
|
|
|
|
// Hidden index on capped collection.
|
|
if (!FixtureHelpers.isMongos(db) && !TestData.testingReplicaSetEndpoint) {
|
|
coll = assertDropAndRecreateCollection(db, collName, {capped: true, size: 100});
|
|
validateHiddenIndexBehaviour({query: {a: 1}, index_type: 1});
|
|
coll = assertDropAndRecreateCollection(db, collName);
|
|
}
|
|
// Test that index 'hidden' status can be found in listIndexes command.
|
|
assert.commandWorked(coll.createIndex({lsIdx: 1}, {hidden: true}));
|
|
let res = assert.commandWorked(db.runCommand({"listIndexes": collName}));
|
|
let idxSpec = IndexCatalogHelpers.findByName(res.cursor.firstBatch, "lsIdx_1");
|
|
assert.eq(idxSpec.hidden, true);
|
|
|
|
// Can't hide any index in a system collection.
|
|
const systemColl = db.getSiblingDB("admin").system.version;
|
|
assert.commandWorked(systemColl.createIndex({a: 1}));
|
|
// The collMod command throws ShardingStateNotInitialized on DDL coordinator implementation and
|
|
// BadValue on old implementation.
|
|
assert.commandFailedWithCode(systemColl.hideIndex("a_1"), [
|
|
ErrorCodes.ShardingStateNotInitialized,
|
|
ErrorCodes.BadValue,
|
|
]);
|
|
assert.commandFailedWithCode(systemColl.createIndex({a: 1}, {hidden: true}), 2);
|
|
|
|
// Can't hide the '_id' index.
|
|
assert.commandFailed(coll.hideIndex("_id_"));
|
|
|
|
// Can't 'hint' a hidden index.
|
|
assert.commandWorked(coll.createIndex({"a": 1}, {"hidden": true}));
|
|
assert.commandFailedWithCode(coll.runCommand("find", {hint: {a: 1}}), 2);
|
|
|
|
// We can change ttl index and hide info at the same time.
|
|
assert.commandWorked(coll.dropIndexes());
|
|
assert.commandWorked(coll.createIndex({"tm": 1}, {expireAfterSeconds: 10}));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), "tm_1");
|
|
assert.eq(idxSpec.hidden, undefined);
|
|
assert.eq(idxSpec.expireAfterSeconds, 10);
|
|
|
|
db.runCommand({
|
|
"collMod": coll.getName(),
|
|
"index": {"name": "tm_1", "expireAfterSeconds": 1, "hidden": true},
|
|
});
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), "tm_1");
|
|
assert(idxSpec.hidden);
|
|
assert.eq(idxSpec.expireAfterSeconds, 1);
|
|
|
|
//
|
|
// Ensure that "hidden: false" won't be added to index specification.
|
|
//
|
|
assert.commandWorked(db.runCommand({createIndexes: collName, indexes: [{key: {y: 1}, name: "y", hidden: false}]}));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), "y");
|
|
assert.eq(idxSpec.hidden, undefined);
|
|
|
|
assert.commandWorked(coll.hideIndex("y"));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), "y");
|
|
assert(idxSpec.hidden);
|
|
|
|
// Ensure that unhiding the hidden index won't add 'hidden: false' to the index spec as well.
|
|
assert.commandWorked(coll.unhideIndex("y"));
|
|
idxSpec = IndexCatalogHelpers.findByName(coll.getIndexes(), "y");
|
|
assert.eq(idxSpec.hidden, undefined);
|