summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2020-11-20 16:39:11 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-11-20 22:17:02 +0000
commitee08d86e202e58f488d1303341839a831e9bfc68 (patch)
tree3eebeb4c5dc43680f32e25c4e9cce300b5360648
parent49cc63d73eddfa176f9c2e46792b3d97242b4839 (diff)
downloadmongo-ee08d86e202e58f488d1303341839a831e9bfc68.tar.gz
SERVER-52525 extract index_key_validate::validateIndexSpecTTL() from createIndexes command
-rw-r--r--jstests/noPassthroughWithMongod/time_series_create.js2
-rw-r--r--src/mongo/db/catalog/index_key_validate.cpp51
-rw-r--r--src/mongo/db/catalog/index_key_validate.h6
-rw-r--r--src/mongo/db/commands/create_indexes.cpp47
4 files changed, 62 insertions, 44 deletions
diff --git a/jstests/noPassthroughWithMongod/time_series_create.js b/jstests/noPassthroughWithMongod/time_series_create.js
index 197bc20c4a6..20a68811472 100644
--- a/jstests/noPassthroughWithMongod/time_series_create.js
+++ b/jstests/noPassthroughWithMongod/time_series_create.js
@@ -94,6 +94,8 @@ testInvalidTimeseriesOptions("", ErrorCodes.TypeMismatch);
testInvalidTimeseriesOptions({timeField: 100}, ErrorCodes.TypeMismatch);
testInvalidTimeseriesOptions({timeField: "time", metaField: 100}, ErrorCodes.TypeMismatch);
testInvalidTimeseriesOptions({timeField: "time", expireAfterSeconds: ""}, ErrorCodes.TypeMismatch);
+testInvalidTimeseriesOptions({timeField: "time", expireAfterSeconds: NumberLong(-10)},
+ ErrorCodes.TypeMismatch);
testInvalidTimeseriesOptions({timeField: "time", invalidOption: {}}, 40415);
testCompatibleCreateOptions({storageEngine: {}});
diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp
index 829a2b7392c..14e0ca05bdd 100644
--- a/src/mongo/db/catalog/index_key_validate.cpp
+++ b/src/mongo/db/catalog/index_key_validate.cpp
@@ -610,6 +610,57 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx,
return indexSpec;
}
+Status validateIndexSpecTTL(const BSONObj& indexSpec) {
+ if (!indexSpec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName)) {
+ return Status::OK();
+ }
+
+ const BSONElement expireAfterSecondsElt =
+ indexSpec[IndexDescriptor::kExpireAfterSecondsFieldName];
+ if (!expireAfterSecondsElt.isNumber()) {
+ return {ErrorCodes::CannotCreateIndex,
+ str::stream() << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName
+ << "' option must be numeric, but received a type of '"
+ << typeName(expireAfterSecondsElt.type())
+ << "'. Index spec: " << indexSpec};
+ }
+
+ if (expireAfterSecondsElt.safeNumberLong() < 0) {
+ return {ErrorCodes::CannotCreateIndex,
+ str::stream() << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName
+ << "' option cannot be less than 0. Index spec: " << indexSpec};
+ }
+
+ const std::string tooLargeErr = str::stream()
+ << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName
+ << "' option must be within an acceptable range, try a lower number. Index spec: "
+ << indexSpec;
+
+ // There are two cases where we can encounter an issue here.
+ // The first case is when we try to cast to millseconds from seconds, which could cause an
+ // overflow. The second case is where 'expireAfterSeconds' is larger than the current epoch
+ // time.
+ try {
+ auto expireAfterMillis =
+ duration_cast<Milliseconds>(Seconds(expireAfterSecondsElt.safeNumberLong()));
+ if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) {
+ return {ErrorCodes::CannotCreateIndex, tooLargeErr};
+ }
+ } catch (const AssertionException&) {
+ return {ErrorCodes::CannotCreateIndex, tooLargeErr};
+ }
+
+ const BSONObj key = indexSpec["key"].Obj();
+ if (key.nFields() != 1) {
+ return {ErrorCodes::CannotCreateIndex,
+ str::stream() << "TTL indexes are single-field indexes, compound indexes do "
+ "not support TTL. Index spec: "
+ << indexSpec};
+ }
+
+ return Status::OK();
+}
+
GlobalInitializerRegisterer filterAllowedIndexFieldNamesInitializer(
"FilterAllowedIndexFieldNames", [](InitializerContext* service) {
if (filterAllowedIndexFieldNames)
diff --git a/src/mongo/db/catalog/index_key_validate.h b/src/mongo/db/catalog/index_key_validate.h
index 7c177c50355..e3e29f08bef 100644
--- a/src/mongo/db/catalog/index_key_validate.h
+++ b/src/mongo/db/catalog/index_key_validate.h
@@ -87,6 +87,12 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx,
const CollatorInterface* defaultCollator);
/**
+ * Validates the key pattern and the 'expireAfterSeconds' duration in the index specification
+ * 'indexSpec' for a TTL index. Returns success if 'indexSpec' does not refer to a TTL index.
+ */
+Status validateIndexSpecTTL(const BSONObj& indexSpec);
+
+/**
* Optional filtering function to adjust allowed index field names at startup.
* Set it in a MONGO_INITIALIZER with 'FilterAllowedIndexFieldNames' as a dependant.
*/
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index 3ecaafbc401..43f5a813313 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -227,50 +227,9 @@ Status validateTTLOptions(OperationContext* opCtx, const BSONObj& cmdObj) {
const BSONElement& indexes = cmdObj[kIndexesFieldName];
for (const auto& index : indexes.Array()) {
BSONObj indexObj = index.Obj();
- if (!indexObj.hasField(kExpireAfterSeconds)) {
- continue;
- }
-
- const BSONElement expireAfterSecondsElt = indexObj[kExpireAfterSeconds];
- if (!expireAfterSecondsElt.isNumber()) {
- return {ErrorCodes::CannotCreateIndex,
- str::stream() << "TTL index '" << kExpireAfterSeconds
- << "' option must be numeric, but received a type of '"
- << typeName(expireAfterSecondsElt.type())
- << "'. Index spec: " << indexObj};
- }
-
- if (expireAfterSecondsElt.safeNumberLong() < 0) {
- return {ErrorCodes::CannotCreateIndex,
- str::stream() << "TTL index '" << kExpireAfterSeconds
- << "' option cannot be less than 0. Index spec: " << indexObj};
- }
-
- const std::string tooLargeErr = str::stream()
- << "TTL index '" << kExpireAfterSeconds
- << "' option must be within an acceptable range, try a lower number. Index spec: "
- << indexObj;
-
- // There are two cases where we can encounter an issue here.
- // The first case is when we try to cast to millseconds from seconds, which could cause an
- // overflow. The second case is where 'expireAfterSeconds' is larger than the current epoch
- // time.
- try {
- auto expireAfterMillis =
- duration_cast<Milliseconds>(Seconds(expireAfterSecondsElt.safeNumberLong()));
- if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) {
- return {ErrorCodes::CannotCreateIndex, tooLargeErr};
- }
- } catch (const AssertionException&) {
- return {ErrorCodes::CannotCreateIndex, tooLargeErr};
- }
-
- const BSONObj key = indexObj["key"].Obj();
- if (key.nFields() != 1) {
- return {ErrorCodes::CannotCreateIndex,
- str::stream() << "TTL indexes are single-field indexes, compound indexes do "
- "not support TTL. Index spec: "
- << indexObj};
+ auto status = index_key_validate::validateIndexSpecTTL(indexObj);
+ if (!status.isOK()) {
+ return status;
}
}