diff options
author | David Percy <david.percy@mongodb.com> | 2022-03-30 19:40:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-04-04 17:02:21 +0000 |
commit | 7ecd542de5c542c27856032c219a06900778ea3a (patch) | |
tree | 5cd411ef82947cb86b07d617d5fde631817ccdd5 /src | |
parent | 797daddf5dac8aa111f488d4102e1b88d49e56e3 (diff) | |
download | mongo-7ecd542de5c542c27856032c219a06900778ea3a.tar.gz |
SERVER-63902 Fix $natural hint on time-series collections
Diffstat (limited to 'src')
5 files changed, 35 insertions, 19 deletions
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index b0b23e3e42b..d1afdc8dde9 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -809,10 +809,8 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, "Cannot perform an upsert on a time-series collection", !updateRequest->isUpsert()); - // Only translate the hint (if there is one) if it is specified with an index specification - // document. - if (!updateRequest->getHint().isEmpty() && - updateRequest->getHint().firstElement().fieldNameStringData() != "$hint"_sd) { + // Only translate the hint if it is specified with an index key. + if (timeseries::isHintIndexKey(updateRequest->getHint())) { updateRequest->setHint( uassertStatusOK(timeseries::createBucketsIndexSpecFromTimeseriesIndexSpec( *timeseriesOptions, updateRequest->getHint()))); @@ -1144,10 +1142,8 @@ static SingleWriteResult performSingleDeleteOp(OperationContext* opCtx, "Time-series buckets collection is missing time-series options", timeseriesOptions); - // Only translate the hint if it is specified by index spec. - if (!request.getHint().isEmpty() && - (request.getHint().firstElement().fieldNameStringData() != "$hint"_sd || - request.getHint().firstElement().type() != BSONType::String)) { + // Only translate the hint if it is specified by index key. + if (timeseries::isHintIndexKey(request.getHint())) { request.setHint( uassertStatusOK(timeseries::createBucketsIndexSpecFromTimeseriesIndexSpec( *timeseriesOptions, request.getHint()))); 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 1dff8c06341..9338f2c237d 100644 --- a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp +++ b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp @@ -71,6 +71,14 @@ std::pair<std::string, std::string> extractControlPrefixAndKey(const StringData& StatusWith<BSONObj> createBucketsSpecFromTimeseriesSpec(const TimeseriesOptions& timeseriesOptions, const BSONObj& timeseriesIndexSpecBSON, bool isShardKeySpec) { + tassert(6390200, "Empty object is not a valid index spec", !timeseriesIndexSpecBSON.isEmpty()); + tassert(6390201, + str::stream() << "Invalid index spec (perhaps it's a valid hint, that was incorrectly " + << "passed to createBucketsSpecFromTimeseriesSpec): " + << timeseriesIndexSpecBSON, + timeseriesIndexSpecBSON.firstElement().fieldNameStringData() != "$hint"_sd && + timeseriesIndexSpecBSON.firstElement().fieldNameStringData() != "$natural"_sd); + auto timeField = timeseriesOptions.getTimeField(); auto metaField = timeseriesOptions.getMetaField(); @@ -474,4 +482,16 @@ bool doesBucketsIndexIncludeMeasurement(OperationContext* opCtx, return false; } +bool isHintIndexKey(const BSONObj& obj) { + if (obj.isEmpty()) + return false; + StringData fieldName = obj.firstElement().fieldNameStringData(); + if (fieldName == "$hint"_sd) + return false; + if (fieldName == "$natural"_sd) + return false; + + return true; +} + } // namespace mongo::timeseries diff --git a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.h b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.h index ca9fc2e1a77..ad1bb795fd2 100644 --- a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.h +++ b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.h @@ -88,4 +88,13 @@ bool doesBucketsIndexIncludeMeasurement(OperationContext* opCtx, const TimeseriesOptions& timeseriesOptions, const BSONObj& bucketsIndex); +/** + * Takes a 'hint' object, in the same format used by FindCommandRequest, and returns + * true if the hint is an index key. + * + * Besides an index key, a hint can be {$hint: <index name>} or {$natural: <direction>}, + * or it can be {} which means no hint is given. + */ +bool isHintIndexKey(const BSONObj& obj); + } // namespace mongo::timeseries diff --git a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions_test.cpp b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions_test.cpp index 88a2fd76b7d..db6eadda021 100644 --- a/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions_test.cpp +++ b/src/mongo/db/timeseries/timeseries_index_schema_conversion_functions_test.cpp @@ -128,14 +128,6 @@ TEST(TimeseriesIndexSchemaConversionTest, OriginalSpecFieldName) { } } -// {} <=> {} -TEST(TimeseriesIndexSchemaConversionTest, EmptyTimeseriesIndexSpecDoesNothing) { - TimeseriesOptions timeseriesOptions = makeTimeseriesOptions(); - BSONObj emptyIndexSpec = {}; - - testBothWaysIndexSpecConversion(timeseriesOptions, emptyIndexSpec, emptyIndexSpec); -} - // {tm: 1} <=> {control.min.tm: 1, control.max.tm: 1} TEST(TimeseriesIndexSchemaConversionTest, AscendingTimeIndexSpecConversion) { TimeseriesOptions timeseriesOptions = makeTimeseriesOptions(); diff --git a/src/mongo/db/views/resolved_view.cpp b/src/mongo/db/views/resolved_view.cpp index ec60c6f0826..244d38a0b55 100644 --- a/src/mongo/db/views/resolved_view.cpp +++ b/src/mongo/db/views/resolved_view.cpp @@ -183,9 +183,8 @@ AggregateCommandRequest ResolvedView::asExpandedViewAggregation( if (request.getHint() && _timeseriesOptions) { BSONObj original = *request.getHint(); BSONObj rewritten = original; - // Only convert if we are given an index spec, not an index name. An index name is provided - // in the form of {"$hint": <name>}. - if (!original.isEmpty() && original.firstElementFieldNameStringData() != "$hint"_sd) { + // Only convert if we are given an index spec, not an index name or a $natural hint. + if (timeseries::isHintIndexKey(original)) { auto converted = timeseries::createBucketsIndexSpecFromTimeseriesIndexSpec( *_timeseriesOptions, original); if (converted.isOK()) { |