summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorFaustoleyva54 <fausto.leyva@mongodb.com>2022-06-10 15:56:36 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-06-10 16:58:59 +0000
commit7ad95de6d0d0ff06f5161f7d5e3243b0cdd5e9cc (patch)
tree2976e75cc7ad9bb036d119c7c6f52435ff0a603b /src/mongo
parentd94f6725598eac9b617bd5b1d383254f174b089a (diff)
downloadmongo-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.cpp4
-rw-r--r--src/mongo/db/exec/bucket_unpacker.h5
-rw-r--r--src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp62
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) {