summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Percy <david.percy@mongodb.com>2022-03-30 19:40:38 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-04 17:02:21 +0000
commit7ecd542de5c542c27856032c219a06900778ea3a (patch)
tree5cd411ef82947cb86b07d617d5fde631817ccdd5 /src
parent797daddf5dac8aa111f488d4102e1b88d49e56e3 (diff)
downloadmongo-7ecd542de5c542c27856032c219a06900778ea3a.tar.gz
SERVER-63902 Fix $natural hint on time-series collections
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp12
-rw-r--r--src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.cpp20
-rw-r--r--src/mongo/db/timeseries/timeseries_index_schema_conversion_functions.h9
-rw-r--r--src/mongo/db/timeseries/timeseries_index_schema_conversion_functions_test.cpp8
-rw-r--r--src/mongo/db/views/resolved_view.cpp5
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()) {