diff options
author | Faustoleyva54 <fausto.leyva@mongodb.com> | 2022-06-10 15:56:36 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-06-10 16:58:59 +0000 |
commit | 7ad95de6d0d0ff06f5161f7d5e3243b0cdd5e9cc (patch) | |
tree | 2976e75cc7ad9bb036d119c7c6f52435ff0a603b /src/mongo | |
parent | d94f6725598eac9b617bd5b1d383254f174b089a (diff) | |
download | mongo-7ad95de6d0d0ff06f5161f7d5e3243b0cdd5e9cc.tar.gz |
SERVER-66692 Allow creating TTL index over timeField with partialFilterExpression defined over metaField
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/exec/bucket_unpacker.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/exec/bucket_unpacker.h | 5 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp | 62 |
3 files changed, 59 insertions, 12 deletions
diff --git a/src/mongo/db/exec/bucket_unpacker.cpp b/src/mongo/db/exec/bucket_unpacker.cpp index 0651aae78ee..6d96dd51676 100644 --- a/src/mongo/db/exec/bucket_unpacker.cpp +++ b/src/mongo/db/exec/bucket_unpacker.cpp @@ -606,7 +606,7 @@ std::unique_ptr<MatchExpression> BucketSpec::createPredicatesOnBucketLevelField( return handleIneligible(policy, matchExpr, "can't handle this predicate"); } -BSONObj BucketSpec::pushdownPredicate( +std::pair<bool, BSONObj> BucketSpec::pushdownPredicate( const boost::intrusive_ptr<ExpressionContext>& expCtx, const TimeseriesOptions& tsOptions, ExpressionContext::CollationMatchesDefault collationMatchesDefault, @@ -666,7 +666,7 @@ BSONObj BucketSpec::pushdownPredicate( metaOnlyPredicate->serialize(&result); if (bucketMetricPredicate) bucketMetricPredicate->serialize(&result); - return result.obj(); + return std::make_pair(bucketMetricPredicate.get(), result.obj()); } class BucketUnpacker::UnpackingImpl { diff --git a/src/mongo/db/exec/bucket_unpacker.h b/src/mongo/db/exec/bucket_unpacker.h index 287bd9f2540..7e32629407d 100644 --- a/src/mongo/db/exec/bucket_unpacker.h +++ b/src/mongo/db/exec/bucket_unpacker.h @@ -167,8 +167,11 @@ public: * * When using IneligiblePredicatePolicy::kIgnore, if the predicate can't be pushed down, it * returns null. When using IneligiblePredicatePolicy::kError it raises a user error. + * + * Returns a boolean (alongside the bucket-level predicate) describing if the result contains + * a metric predicate. */ - static BSONObj pushdownPredicate( + static std::pair<bool, BSONObj> pushdownPredicate( const boost::intrusive_ptr<ExpressionContext>& expCtx, const TimeseriesOptions& tsOptions, ExpressionContext::CollationMatchesDefault collationMatchesDefault, diff --git a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp index 7b8899a101a..6481aa7bbf9 100644 --- a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp +++ b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp @@ -50,6 +50,28 @@ namespace { NamespaceString makeTimeseriesBucketsNamespace(const NamespaceString& nss) { return nss.isTimeseriesBucketsCollection() ? nss : nss.makeTimeseriesBucketsNamespace(); } + +/** + * Converts the key field on time to 'control.min.$timeField' field. Depends on error checking from + * 'createBucketsSpecFromTimeseriesSpec()' which should be called before this function. + */ +BSONObj convertToTTLTimeField(const BSONObj& origKeyField, StringData timeField) { + BSONObjBuilder keyBuilder; + uassert(ErrorCodes::CannotCreateIndex, + str::stream() << "TTL indexes are single-field indexes, compound indexes do " + "not support TTL. Index spec: " + << origKeyField, + origKeyField.nFields() == 1); + + const auto& firstElem = origKeyField.firstElement(); + uassert(ErrorCodes::InvalidOptions, + "TTL indexes on non-time fields are not supported on time-series collections", + firstElem.fieldName() == timeField); + + keyBuilder.appendAs(firstElem, + str::stream() << timeseries::kControlMinFieldNamePrefix << timeField); + return keyBuilder.obj(); +} } // namespace @@ -83,7 +105,12 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, std::vector<mongo::BSONObj> indexes; for (const auto& origIndex : origIndexes) { BSONObjBuilder builder; + BSONObj keyField; + BSONObj originalKeyField; + bool isTTLIndex = false; + bool hasPartialFilterOnMetaField = false; bool includeOriginalSpec = false; + for (const auto& elem : origIndex) { if (elem.fieldNameStringData() == IndexDescriptor::kPartialFilterExprFieldName) { if (feature_flags::gTimeseriesMetricIndexes.isEnabled( @@ -135,7 +162,7 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, // planner, this will be true. bool assumeNoMixedSchemaData = true; - BSONObj bucketPred = + auto [hasMetricPred, bucketPred] = BucketSpec::pushdownPredicate(expCtx, options, collationMatchesDefault, @@ -144,6 +171,9 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, includeMetaField, assumeNoMixedSchemaData, BucketSpec::IneligiblePredicatePolicy::kError); + + hasPartialFilterOnMetaField = !hasMetricPred; + builder.append(IndexDescriptor::kPartialFilterExprFieldName, bucketPred); continue; } @@ -171,11 +201,11 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, } if (elem.fieldNameStringData() == IndexDescriptor::kExpireAfterSecondsFieldName) { - uasserted(ErrorCodes::InvalidOptions, - "TTL indexes are not supported on time-series collections"); + isTTLIndex = true; + builder.append(elem); + continue; } - if (elem.fieldNameStringData() == IndexDescriptor::kUniqueFieldName) { uassert(ErrorCodes::InvalidOptions, "Unique indexes are not supported on time-series collections", @@ -183,13 +213,16 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, } if (elem.fieldNameStringData() == NewIndexSpec::kKeyFieldName) { - auto pluginName = IndexNames::findPluginName(elem.Obj()); + originalKeyField = elem.Obj(); + + auto pluginName = IndexNames::findPluginName(originalKeyField); uassert(ErrorCodes::InvalidOptions, "Text indexes are not supported on time-series collections", pluginName != IndexNames::TEXT); auto bucketsIndexSpecWithStatus = - timeseries::createBucketsIndexSpecFromTimeseriesIndexSpec(options, elem.Obj()); + timeseries::createBucketsIndexSpecFromTimeseriesIndexSpec(options, + originalKeyField); uassert(ErrorCodes::CannotCreateIndex, str::stream() << bucketsIndexSpecWithStatus.getStatus().toString() << " Command request: " << redact(origCmd.toBSON({})), @@ -201,9 +234,7 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, << bucketsIndexSpecWithStatus.getValue()))) { includeOriginalSpec = true; } - - builder.append(NewIndexSpec::kKeyFieldName, - std::move(bucketsIndexSpecWithStatus.getValue())); + keyField = std::move(bucketsIndexSpecWithStatus.getValue()); continue; } @@ -212,6 +243,19 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, builder.append(elem); } + if (isTTLIndex) { + uassert(ErrorCodes::InvalidOptions, + "TTL indexes are not supported on time-series collections", + feature_flags::gTimeseriesScalabilityImprovements.isEnabled( + serverGlobalParams.featureCompatibility)); + uassert(ErrorCodes::InvalidOptions, + "TTL indexes on time-series collections require a partialFilterExpression on " + "the metaField", + hasPartialFilterOnMetaField); + keyField = convertToTTLTimeField(originalKeyField, options.getTimeField()); + } + builder.append(NewIndexSpec::kKeyFieldName, std::move(keyField)); + if (feature_flags::gTimeseriesMetricIndexes.isEnabled( serverGlobalParams.featureCompatibility) && includeOriginalSpec) { |