SERVER-113897 Report existence of invalid compound wildcard index (#44001)

GitOrigin-RevId: bdbef6a80cd18e4aac5a77d738b1d2ed21a63092
This commit is contained in:
Militsa Sotirova 2025-11-21 11:37:57 -05:00 committed by MongoDB Bot
parent 42e5a8d976
commit 976cf4d33f
3 changed files with 114 additions and 1 deletions

View File

@ -42,7 +42,7 @@ local_args="--edition $edition \
--debug \ --debug \
--fallbackToMaster \ --fallbackToMaster \
${last_lts_arg} \ ${last_lts_arg} \
${last_continuous_arg} 6.0 7.0" ${last_continuous_arg} 6.0 7.0 8.0.16"
remote_invocation="${base_command} ${evergreen_args} ${local_args}" remote_invocation="${base_command} ${evergreen_args} ${local_args}"
eval "${remote_invocation}" eval "${remote_invocation}"

View File

@ -0,0 +1,95 @@
/**
* Tests that a server containing an invalid wildcard index will log a warning on startup.
*
* @tags: [
* requires_persistence,
* requires_replication,
* ]
*/
import {ReplSetTest} from "jstests/libs/replsettest.js";
// This is a version that allows the bad index to be created.
const oldVersion = "8.0.16";
// Standalone mongod
{
const testName = "invalid_wildcard_index_log_at_startup";
const dbpath = MongoRunner.dataPath + testName;
const collName = "collectionWithInvalidWildcardIndex";
{
// Startup mongod version where we are allowed to create the invalid index.
const conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: oldVersion});
assert.neq(null, conn, "mongod was unable to start up");
const testDB = conn.getDB("test");
assert.commandWorked(testDB[collName].insert({a: 1}));
// Invalid index
assert.commandWorked(testDB[collName].createIndex({"a": 1, "$**": 1}, {wildcardProjection: {"_id": 0}}));
MongoRunner.stopMongod(conn);
}
{
const conn = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true});
assert.neq(null, conn, "mongod was unable to start up");
const testDB = conn.getDB("test");
const cmdRes = assert.commandWorked(testDB.adminCommand({getLog: "startupWarnings"}));
assert(
/Found a compound wildcard index with an invalid wildcardProjection. Such indexes can no longer be created./.test(
cmdRes.log,
),
);
// Be sure that inserting to the collection with the invalid index succeeds.
assert.commandWorked(testDB[collName].insert({a: 2}));
// Inserting to another collection should succeed.
assert.commandWorked(testDB.someOtherCollection.insert({a: 1}));
assert.eq(testDB.someOtherCollection.find().itcount(), 1);
MongoRunner.stopMongod(conn);
}
}
// Replica set
{
let nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion},
};
const rst = new ReplSetTest({nodes: nodes});
rst.startSet();
rst.initiate();
let primary = rst.getPrimary();
const db = primary.getDB("test");
const coll = db.t;
assert.commandWorked(coll.insert({a: 1}));
assert.commandWorked(coll.createIndex({"a": 1, "$**": 1}, {wildcardProjection: {"_id": 0}}));
// Force checkpoint in storage engine to ensure index is part of the catalog in
// in finished state at startup.
rst.awaitReplication();
let secondary = rst.getSecondary();
assert.commandWorked(secondary.adminCommand({fsync: 1}));
// Check that initial sync works, this node would not allow the index to be created
// (since it is on a version with the new validation logic) but should not fail on startup.
const initialSyncNode = rst.add({rsConfig: {priority: 0}});
rst.reInitiate();
rst.awaitSecondaryNodes(null, [initialSyncNode]);
// Restart the new node and check for the startup warning in the logs.
rst.restart(initialSyncNode);
rst.awaitSecondaryNodes(null, [initialSyncNode]);
checkLog.containsJson(initialSyncNode, 11389700, {
ns: coll.getFullName(),
});
rst.stopSet();
}

View File

@ -49,6 +49,7 @@
#include "mongo/db/index/index_constants.h" #include "mongo/db/index/index_constants.h"
#include "mongo/db/index/s2_access_method.h" #include "mongo/db/index/s2_access_method.h"
#include "mongo/db/index/s2_bucket_access_method.h" #include "mongo/db/index/s2_bucket_access_method.h"
#include "mongo/db/index/wildcard_validation.h"
#include "mongo/db/index_builds/index_build_block.h" #include "mongo/db/index_builds/index_build_block.h"
#include "mongo/db/index_builds/index_builds_common.h" #include "mongo/db/index_builds/index_builds_common.h"
#include "mongo/db/index_names.h" #include "mongo/db/index_names.h"
@ -272,6 +273,23 @@ void IndexCatalogImpl::init(OperationContext* opCtx,
"spec"_attr = spec); "spec"_attr = spec);
} }
// Look for an invalid compound wildcard index.
if (IndexNames::findPluginName(keyPattern) == IndexNames::WILDCARD &&
keyPattern.nFields() > 1 && spec.hasField("wildcardProjection")) {
auto validationStatus =
validateWildcardProjection(keyPattern, spec.getObjectField("wildcardProjection"));
if (!validationStatus.isOK()) {
LOGV2_OPTIONS(11389700,
{logv2::LogTag::kStartupWarnings},
"Found a compound wildcard index with an invalid wildcardProjection. "
"Such indexes can no longer be created.",
"ns"_attr = collection->ns(),
"uuid"_attr = collection->uuid(),
"index"_attr = indexName,
"spec"_attr = spec);
}
}
auto descriptor = IndexDescriptor(_getAccessMethodName(keyPattern), spec); auto descriptor = IndexDescriptor(_getAccessMethodName(keyPattern), spec);
if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName)) { if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName)) {