diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2021-11-05 15:47:37 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-11-05 16:34:50 +0000 |
commit | 205bcaa9c722e425e7ca45acf89956841bfcf8da (patch) | |
tree | 252229bf327a17961871cbf69c9c3feab4fc21a0 | |
parent | 7bcb659c013aaf44e1edab7b8a102a738c0bfb8c (diff) | |
download | mongo-205bcaa9c722e425e7ca45acf89956841bfcf8da.tar.gz |
SERVER-61175 Store the original user index definition on the transformed index definition on the buckets collection for partial indexes
6 files changed, 104 insertions, 36 deletions
diff --git a/jstests/core/timeseries/timeseries_index.js b/jstests/core/timeseries/timeseries_index.js index 0a6bbd6d51a..6cddbdc2ea8 100644 --- a/jstests/core/timeseries/timeseries_index.js +++ b/jstests/core/timeseries/timeseries_index.js @@ -4,7 +4,7 @@ * @tags: [ * does_not_support_stepdowns, * does_not_support_transactions, - * requires_fcv_51, + * requires_fcv_52, * requires_getmore, * ] */ @@ -275,10 +275,13 @@ TimeseriesTest.run((insert) => { [ErrorCodes.CannotCreateIndex, ErrorCodes.InvalidOptions]); }; - // Partial indexes are not supported on time-series collections. - testCreateIndexFailed({[metaFieldName]: 1}, {partialFilterExpression: {meta: {$gt: 5}}}); - testCreateIndexFailed({[metaFieldName]: 1}, - {partialFilterExpression: {[metaFieldName]: {$gt: 5}}}); + if (!TimeseriesTest.timeseriesMetricIndexesEnabled(db.getMongo())) { + // Partial indexes are not supported on time-series collections if the time-series metric + // feature flag is disabled. + testCreateIndexFailed({[metaFieldName]: 1}, {partialFilterExpression: {meta: {$gt: 5}}}); + testCreateIndexFailed({[metaFieldName]: 1}, + {partialFilterExpression: {[metaFieldName]: {$gt: 5}}}); + } // Unique indexes are not supported on clustered collections. testCreateIndexFailed({[metaFieldName]: 1}, {unique: true}); diff --git a/jstests/core/timeseries/timeseries_index_spec.js b/jstests/core/timeseries/timeseries_index_spec.js index c27354be313..eaf7065d3e9 100644 --- a/jstests/core/timeseries/timeseries_index_spec.js +++ b/jstests/core/timeseries/timeseries_index_spec.js @@ -30,48 +30,68 @@ TimeseriesTest.run(() => { assert.commandWorked(db.createCollection( coll.getName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}})); - assert.commandWorked(coll.createIndex({[timeFieldName]: 1})); - assert.commandWorked(coll.createIndex({[metaFieldName]: 1})); - - if (TimeseriesTest.timeseriesMetricIndexesEnabled(db.getMongo())) { - assert.commandWorked(coll.createIndex({x: 1}, {name: "x"})); - } - - const checkIndexSpec = function(spec, userIndex) { + const checkIndexSpec = function(spec, userIndex, isDowngradeCompatible) { assert(spec.hasOwnProperty("v")); assert(spec.hasOwnProperty("name")); assert(spec.hasOwnProperty("key")); if (userIndex) { assert(!spec.hasOwnProperty("originalSpec")); - - if (spec.name == "x") { - assert.eq(spec.key, {x: 1}); - } - return; } - if (spec.name == "x") { + if (!isDowngradeCompatible) { assert(spec.hasOwnProperty("originalSpec")); assert.eq(spec.v, spec.originalSpec.v); assert.eq(spec.name, spec.originalSpec.name); assert.neq(spec.key, spec.originalSpec.key); - - assert.eq(spec.key, {"control.min.x": 1, "control.max.x": 1}); } else { assert(!spec.hasOwnProperty("originalSpec")); } }; - let userIndexes = coll.getIndexes(); - for (const index of userIndexes) { - checkIndexSpec(index, /*userIndex=*/true); - } + const verifyAndDropIndex = function(isDowngradeCompatible) { + let userIndexes = coll.getIndexes(); + for (const index of userIndexes) { + checkIndexSpec(index, /*userIndex=*/true, isDowngradeCompatible); + } + + let bucketIndexes = bucketsColl.getIndexes(); + for (const index of bucketIndexes) { + checkIndexSpec(index, /*userIndex=*/false, isDowngradeCompatible); + } + + assert.commandWorked(coll.dropIndexes("*")); + }; + + assert.commandWorked(coll.createIndex({[timeFieldName]: 1})); + verifyAndDropIndex(/*isDowngradeCompatible=*/true); + + assert.commandWorked(coll.createIndex({[metaFieldName]: 1})); + verifyAndDropIndex(/*isDowngradeCompatible=*/true); + + assert.commandWorked(coll.createIndex({[timeFieldName]: 1, [metaFieldName]: 1})); + verifyAndDropIndex(/*isDowngradeCompatible=*/true); + + if (TimeseriesTest.timeseriesMetricIndexesEnabled(db.getMongo())) { + assert.commandWorked(coll.createIndex({x: 1})); + verifyAndDropIndex(/*isDowngradeCompatible=*/false); + + assert.commandWorked( + coll.createIndex({x: 1}, {partialFilterExpression: {x: {$type: "number"}}})); + verifyAndDropIndex(/*isDowngradeCompatible=*/false); + + assert.commandWorked(coll.createIndex({[timeFieldName]: 1}, + {partialFilterExpression: {x: {$type: "number"}}})); + verifyAndDropIndex(/*isDowngradeCompatible=*/false); + + assert.commandWorked(coll.createIndex({[metaFieldName]: 1}, + {partialFilterExpression: {x: {$type: "number"}}})); + verifyAndDropIndex(/*isDowngradeCompatible=*/false); - let bucketIndexes = bucketsColl.getIndexes(); - for (const index of bucketIndexes) { - checkIndexSpec(index, /*userIndex=*/false); + assert.commandWorked(coll.createIndex({[metaFieldName]: 1, x: 1}, + {partialFilterExpression: {x: {$type: "number"}}})); + verifyAndDropIndex(/*isDowngradeCompatible=*/false); } // Creating an index directly on the buckets collection is permitted. However, these types of @@ -82,7 +102,7 @@ TimeseriesTest.run(() => { bucketsColl.createIndex({"control.min.y": 1, "control.max.y": 1}, {name: "y"})); let foundIndex = false; - bucketIndexes = bucketsColl.getIndexes(); + let bucketIndexes = bucketsColl.getIndexes(); for (const index of bucketIndexes) { if (index.name == "y") { foundIndex = true; @@ -94,7 +114,7 @@ TimeseriesTest.run(() => { // Verify that the bucket index can map to a user index. foundIndex = false; - userIndexes = coll.getIndexes(); + let userIndexes = coll.getIndexes(); for (const index of userIndexes) { if (index.name == "y") { foundIndex = true; diff --git a/jstests/noPassthrough/timeseries_measurement_indexes_downgrade.js b/jstests/noPassthrough/timeseries_measurement_indexes_downgrade.js index 9a8593550d2..d1b913832a2 100644 --- a/jstests/noPassthrough/timeseries_measurement_indexes_downgrade.js +++ b/jstests/noPassthrough/timeseries_measurement_indexes_downgrade.js @@ -114,5 +114,36 @@ checkIndexForDowngrade(lastLTSFCV, true, false); assert.commandWorked(coll.createIndex({[metaFieldName]: "2dsphere"})); checkIndexForDowngrade(lastContinuousFCV, true, false); +// Partial indexes are not supported in versions earlier than v5.2. +assert.commandWorked( + coll.createIndex({[timeFieldName]: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastLTSFCV, false, false); + +assert.commandWorked( + coll.createIndex({[timeFieldName]: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastContinuousFCV, false, false); + +assert.commandWorked( + coll.createIndex({[metaFieldName]: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastLTSFCV, false, false); + +assert.commandWorked( + coll.createIndex({[metaFieldName]: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastContinuousFCV, false, false); + +assert.commandWorked(coll.createIndex({x: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastLTSFCV, false, false); + +assert.commandWorked(coll.createIndex({x: 1}, {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastContinuousFCV, false, false); + +assert.commandWorked(coll.createIndex({[metaFieldName]: 1, x: 1}, + {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastLTSFCV, false, false); + +assert.commandWorked(coll.createIndex({x: 1, [metaFieldName]: 1}, + {partialFilterExpression: {x: {$type: "number"}}})); +checkIndexForDowngrade(lastContinuousFCV, false, false); + MongoRunner.stopMongod(conn); }()); diff --git a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp index db4e0295c61..e857ab8a3a8 100644 --- a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp +++ b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp @@ -78,11 +78,17 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, std::vector<mongo::BSONObj> indexes; for (const auto& origIndex : origIndexes) { BSONObjBuilder builder; - bool isBucketsIndexSpecCompatibleForDowngrade = false; + bool isBucketsIndexSpecCompatibleForDowngrade = true; for (const auto& elem : origIndex) { if (elem.fieldNameStringData() == IndexDescriptor::kPartialFilterExprFieldName) { - uasserted(ErrorCodes::InvalidOptions, - "Partial indexes are not supported on time-series collections"); + if (feature_flags::gTimeseriesMetricIndexes.isEnabledAndIgnoreFCV() && + serverGlobalParams.featureCompatibility.isFCVUpgradingToOrAlreadyLatest()) { + // Partial indexes are not supported in FCV < 5.2. + isBucketsIndexSpecCompatibleForDowngrade = false; + } else { + uasserted(ErrorCodes::InvalidOptions, + "Partial indexes are not supported on time-series collections"); + } } if (elem.fieldNameStringData() == IndexDescriptor::kSparseFieldName) { @@ -132,10 +138,12 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, << " Command request: " << redact(origCmd.toBSON({})), bucketsIndexSpecWithStatus.isOK()); - isBucketsIndexSpecCompatibleForDowngrade = - timeseries::isBucketsIndexSpecCompatibleForDowngrade( + if (!timeseries::isBucketsIndexSpecCompatibleForDowngrade( options, - BSON(NewIndexSpec::kKeyFieldName << bucketsIndexSpecWithStatus.getValue())); + BSON(NewIndexSpec::kKeyFieldName + << bucketsIndexSpecWithStatus.getValue()))) { + isBucketsIndexSpecCompatibleForDowngrade = false; + } builder.append(NewIndexSpec::kKeyFieldName, std::move(bucketsIndexSpecWithStatus.getValue())); diff --git a/src/mongo/db/timeseries/timeseries_constants.h b/src/mongo/db/timeseries/timeseries_constants.h index 24e69bc1837..28dfd25ce78 100644 --- a/src/mongo/db/timeseries/timeseries_constants.h +++ b/src/mongo/db/timeseries/timeseries_constants.h @@ -56,6 +56,7 @@ static constexpr StringData kMetaFieldName = "metaField"_sd; // These are hard-coded field names in index specs. static constexpr StringData kKeyFieldName = "key"_sd; static constexpr StringData kOriginalSpecFieldName = "originalSpec"_sd; +static constexpr StringData kPartialFilterExpressionFieldName = "partialFilterExpression"_sd; static constexpr int kTimeseriesControlDefaultVersion = 1; static constexpr int kTimeseriesControlCompressedVersion = 2; diff --git a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp index 06b701a0f92..570ab781281 100644 --- a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp +++ b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp @@ -389,6 +389,11 @@ bool isBucketsIndexSpecCompatibleForDowngrade(const TimeseriesOptions& timeserie return false; } + if (bucketsIndex.hasField(kPartialFilterExpressionFieldName)) { + // Partial indexes are not supported in FCV < 5.2. + return false; + } + return createTimeseriesIndexSpecFromBucketsIndexSpec( timeseriesOptions, bucketsIndex.getField(kKeyFieldName).Obj(), |