diff options
author | Benety Goh <benety@mongodb.com> | 2022-08-28 20:02:36 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-11 18:36:57 +0000 |
commit | 17d15eb7f3d8b044456ea9191d5777af3fbc5651 (patch) | |
tree | 47818747ccb1bb1952c5ca96a9392d80d7064f5e /src/mongo/db | |
parent | 6a1b08c8108635be9a7624243ca9f4ff191fd48c (diff) | |
download | mongo-17d15eb7f3d8b044456ea9191d5777af3fbc5651.tar.gz |
SERVER-68477 remove epoch restriction on ttl indexes
(cherry picked from commit eb2f7f03f8c0522f85a9cae2c61bec4673251103)
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/catalog/create_collection.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_key_validate.cpp | 42 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_key_validate.h | 9 |
4 files changed, 48 insertions, 19 deletions
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 21b5d6dc920..9fc32c239cd 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -250,7 +250,8 @@ StatusWith<std::pair<ParsedCollModRequest, BSONObj>> parseCollModRequest(Operati "TTL indexes are not supported for capped collections."}; } if (auto status = index_key_validate::validateExpireAfterSeconds( - *cmdIndex.getExpireAfterSeconds()); + *cmdIndex.getExpireAfterSeconds(), + index_key_validate::ValidateExpireAfterSecondsMode::kSecondaryTTLIndex); !status.isOK()) { return {ErrorCodes::InvalidOptions, status.reason()}; } @@ -533,7 +534,9 @@ StatusWith<std::pair<ParsedCollModRequest, BSONObj>> parseCollModRequest(Operati }, [&oplogEntryBuilder](std::int64_t value) { oplogEntryBuilder.append(CollMod::kExpireAfterSecondsFieldName, value); - return index_key_validate::validateExpireAfterSeconds(value); + return index_key_validate::validateExpireAfterSeconds( + value, + index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex); }, }, *expireAfterSeconds); diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp index 74be2bd73e4..0a4400680b2 100644 --- a/src/mongo/db/catalog/create_collection.cpp +++ b/src/mongo/db/catalog/create_collection.cpp @@ -117,7 +117,9 @@ Status validateClusteredIndexSpec(OperationContext* opCtx, if (expireAfterSeconds) { // Not included in the indexSpec itself. - auto status = index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds); + auto status = index_key_validate::validateExpireAfterSeconds( + *expireAfterSeconds, + index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex); if (!status.isOK()) { return status; } @@ -321,8 +323,9 @@ Status _createTimeseries(OperationContext* opCtx, // Cluster time-series buckets collections by _id. auto expireAfterSeconds = options.expireAfterSeconds; if (expireAfterSeconds) { - uassertStatusOK( - index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds)); + uassertStatusOK(index_key_validate::validateExpireAfterSeconds( + *expireAfterSeconds, + index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex)); bucketsOptions.expireAfterSeconds = expireAfterSeconds; } diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp index 501df1931bb..af71c30bea7 100644 --- a/src/mongo/db/catalog/index_key_validate.cpp +++ b/src/mongo/db/catalog/index_key_validate.cpp @@ -778,7 +778,8 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx, return indexSpec; } -Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds) { +Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds, + ValidateExpireAfterSecondsMode mode) { if (expireAfterSeconds < 0) { return {ErrorCodes::InvalidOptions, str::stream() << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName @@ -789,16 +790,31 @@ Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds) { << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName << "' option must be within an acceptable range, try a lower number"; - // 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. - if (expireAfterSeconds > std::numeric_limits<std::int64_t>::max() / 1000) { - return {ErrorCodes::InvalidOptions, tooLargeErr}; - } - auto expireAfterMillis = duration_cast<Milliseconds>(Seconds(expireAfterSeconds)); - if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) { - return {ErrorCodes::InvalidOptions, tooLargeErr}; + if (mode == ValidateExpireAfterSecondsMode::kSecondaryTTLIndex) { + // Relax epoch restriction on TTL indexes. This allows us to export and import existing + // TTL indexes with large values or NaN for the 'expireAfterSeconds' field. + // Additionally, the 'expireAfterSeconds' for TTL indexes is defined as safeInt (int32_t) + // in the IDL for listIndexes and collMod. See list_indexes.idl and coll_mod.idl. + if (expireAfterSeconds > std::numeric_limits<std::int32_t>::max()) { + return {ErrorCodes::InvalidOptions, tooLargeErr}; + } + } else { + // Clustered collections with TTL. + // Note that 'expireAfterSeconds' is defined as safeInt64 in the IDL for the create and + // collMod commands. See create.idl and coll_mod.idl. + // 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. This isn't necessarily problematic for the general case, but for the specific case + // of time series collections, we cluster the collection by an OID value, where the + // timestamp portion is only a 32-bit unsigned integer offset of seconds since the epoch. + if (expireAfterSeconds > std::numeric_limits<std::int64_t>::max() / 1000) { + return {ErrorCodes::InvalidOptions, tooLargeErr}; + } + auto expireAfterMillis = duration_cast<Milliseconds>(Seconds(expireAfterSeconds)); + if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) { + return {ErrorCodes::InvalidOptions, tooLargeErr}; + } } return Status::OK(); } @@ -822,7 +838,9 @@ Status validateIndexSpecTTL(const BSONObj& indexSpec) { << "'. Index spec: " << indexSpec}; } - if (auto status = validateExpireAfterSeconds(expireAfterSecondsElt.safeNumberLong()); + if (auto status = + validateExpireAfterSeconds(expireAfterSecondsElt.safeNumberLong(), + ValidateExpireAfterSecondsMode::kSecondaryTTLIndex); !status.isOK()) { return {ErrorCodes::CannotCreateIndex, str::stream() << status.reason() << ". Index spec: " << indexSpec}; diff --git a/src/mongo/db/catalog/index_key_validate.h b/src/mongo/db/catalog/index_key_validate.h index 49ffa120e60..af819f4286a 100644 --- a/src/mongo/db/catalog/index_key_validate.h +++ b/src/mongo/db/catalog/index_key_validate.h @@ -127,9 +127,14 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx, const CollatorInterface* defaultCollator); /** - * Validates the the 'expireAfterSeconds' value for a TTL index.. + * Validates the the 'expireAfterSeconds' value for a TTL index or clustered collection. */ -Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds); +enum class ValidateExpireAfterSecondsMode { + kSecondaryTTLIndex, + kClusteredTTLIndex, +}; +Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds, + ValidateExpireAfterSecondsMode mode); /** * Returns true if 'indexSpec' refers to a TTL index. |