diff options
author | Adrian Gonzalez <adriangonzalezmontemayor@gmail.com> | 2022-10-07 02:14:09 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-10-07 03:13:43 +0000 |
commit | 0406b63884d9993f0eafd7d6dcd680e0ecdc1a1f (patch) | |
tree | 64af3e807ec0dcf7a65e31ad42f3db054b726e11 /src/mongo/db/timeseries | |
parent | 84e93642a6d7f52ae2df506cff0df2679f526a2c (diff) | |
download | mongo-0406b63884d9993f0eafd7d6dcd680e0ecdc1a1f.tar.gz |
SERVER-67598 Add support for maxSpanSeconds and roundingSeconds arguments
Diffstat (limited to 'src/mongo/db/timeseries')
-rw-r--r-- | src/mongo/db/timeseries/timeseries.idl | 2 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_options.cpp | 164 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_options.h | 7 |
3 files changed, 153 insertions, 20 deletions
diff --git a/src/mongo/db/timeseries/timeseries.idl b/src/mongo/db/timeseries/timeseries.idl index 83e89ae580c..0d4fd2726b6 100644 --- a/src/mongo/db/timeseries/timeseries.idl +++ b/src/mongo/db/timeseries/timeseries.idl @@ -106,7 +106,7 @@ structs: granularity: description: "Describes the expected interval between subsequent measurements" type: BucketGranularity - default: Seconds + optional: true stability: stable bucketRoundingSeconds: description: "Used to determine the minimum time boundary when opening a new bucket diff --git a/src/mongo/db/timeseries/timeseries_options.cpp b/src/mongo/db/timeseries/timeseries_options.cpp index 250dbb33979..f19c781bcae 100644 --- a/src/mongo/db/timeseries/timeseries_options.cpp +++ b/src/mongo/db/timeseries/timeseries_options.cpp @@ -99,10 +99,14 @@ StatusWith<std::pair<TimeseriesOptions, bool>> applyTimeseriesOptionsModificatio TimeseriesOptions newOptions = currentOptions; bool changed = false; - if (auto granularity = mod.getGranularity()) { - BucketGranularityEnum target = *granularity; - if (target != currentOptions.getGranularity()) { - if (!isValidTimeseriesGranularityTransition(currentOptions.getGranularity(), target)) { + // TODO SERVER-67599 run tests for changing between custom granularity to a default one. + if (mod.getGranularity() && currentOptions.getGranularity()) { + auto granularity = mod.getGranularity(); + BucketGranularityEnum target = granularity.get(); + auto currentGranularity = currentOptions.getGranularity().get(); + + if (target != currentGranularity) { + if (!isValidTimeseriesGranularityTransition(currentGranularity, target)) { return Status{ErrorCodes::InvalidOptions, "Invalid transition for timeseries.granularity. Can only transition " "from 'seconds' to 'minutes' or 'minutes' to 'hours'."}; @@ -110,6 +114,12 @@ StatusWith<std::pair<TimeseriesOptions, bool>> applyTimeseriesOptionsModificatio newOptions.setGranularity(target); newOptions.setBucketMaxSpanSeconds( timeseries::getMaxSpanSecondsFromGranularity(target)); + + if (feature_flags::gTimeseriesScalabilityImprovements.isEnabled( + serverGlobalParams.featureCompatibility)) + newOptions.setBucketRoundingSeconds( + timeseries::getBucketRoundingSecondsFromGranularity(target)); + changed = true; } } @@ -132,16 +142,52 @@ BSONObj generateViewPipeline(const TimeseriesOptions& options, bool asArray) { } bool optionsAreEqual(const TimeseriesOptions& option1, const TimeseriesOptions& option2) { - const auto option1BucketSpan = option1.getBucketMaxSpanSeconds() - ? *option1.getBucketMaxSpanSeconds() - : getMaxSpanSecondsFromGranularity(option1.getGranularity()); - const auto option2BucketSpan = option2.getBucketMaxSpanSeconds() - ? *option2.getBucketMaxSpanSeconds() - : getMaxSpanSecondsFromGranularity(option2.getGranularity()); - return option1.getTimeField() == option1.getTimeField() && - option1.getMetaField() == option2.getMetaField() && - option1.getGranularity() == option2.getGranularity() && - option1BucketSpan == option2BucketSpan; + // The time field for both options must match. + if (option1.getTimeField() != option2.getTimeField()) { + return false; + } + + // The meta field for both options must match. + if (option1.getMetaField() != option2.getMetaField()) { + return false; + } + + auto const granularity1 = option1.getGranularity(); + auto const granularity2 = option2.getGranularity(); + + // We accept granularity as equal if they are the same or if one is + // BucketGranularityEnum::Seconds while the other one is boost::none + if (granularity1 != granularity2 && + ((!granularity1 && granularity2 != BucketGranularityEnum::Seconds) || + (granularity1 != BucketGranularityEnum::Seconds && !granularity2))) { + return false; + } + + const auto option1BucketSpan = + option1.getBucketMaxSpanSeconds().get_value_or(getMaxSpanSecondsFromGranularity( + granularity1.get_value_or(BucketGranularityEnum::Seconds))); + + const auto option2BucketSpan = + option2.getBucketMaxSpanSeconds().get_value_or(getMaxSpanSecondsFromGranularity( + granularity2.get_value_or(BucketGranularityEnum::Seconds))); + + if (option1BucketSpan != option2BucketSpan) { + return false; + } + + const auto option1BucketRounding = + option1.getBucketRoundingSeconds().get_value_or(getBucketRoundingSecondsFromGranularity( + granularity1.get_value_or(BucketGranularityEnum::Seconds))); + + const auto option2BucketRounding = + option2.getBucketRoundingSeconds().get_value_or(getBucketRoundingSecondsFromGranularity( + granularity2.get_value_or(BucketGranularityEnum::Seconds))); + + if (option1BucketRounding != option2BucketRounding) { + return false; + } + + return true; } int getBucketRoundingSecondsFromGranularity(BucketGranularityEnum granularity) { @@ -160,14 +206,94 @@ int getBucketRoundingSecondsFromGranularity(BucketGranularityEnum granularity) { } Date_t roundTimestampToGranularity(const Date_t& time, const TimeseriesOptions& options) { - auto roundingSeconds = feature_flags::gTimeseriesScalabilityImprovements.isEnabled( - serverGlobalParams.featureCompatibility) && - options.getBucketRoundingSeconds() - ? options.getBucketRoundingSeconds().value() - : getBucketRoundingSecondsFromGranularity(options.getGranularity()); + long long roundingSeconds = 0; + auto granularity = options.getGranularity(); + if (granularity) { + roundingSeconds = getBucketRoundingSecondsFromGranularity(granularity.get()); + } else { + roundingSeconds = options.getBucketRoundingSeconds().get_value_or( + getBucketRoundingSecondsFromGranularity(BucketGranularityEnum::Seconds)); + } + long long timeSeconds = durationCount<Seconds>(time.toDurationSinceEpoch()); long long roundedTimeSeconds = (timeSeconds - (timeSeconds % roundingSeconds)); return Date_t::fromDurationSinceEpoch(Seconds{roundedTimeSeconds}); } + +Status validateAndSetBucketingParameters(TimeseriesOptions& timeseriesOptions) { + auto roundingSeconds = timeseriesOptions.getBucketRoundingSeconds(); + auto maxSpanSeconds = timeseriesOptions.getBucketMaxSpanSeconds(); + auto granularity = timeseriesOptions.getGranularity(); + + bool allowSecondsParameters = feature_flags::gTimeseriesScalabilityImprovements.isEnabled( + serverGlobalParams.featureCompatibility); + bool maxSpanAndRoundingSecondsSpecified = maxSpanSeconds && roundingSeconds; + auto maxSpanSecondsFromGranularity = + getMaxSpanSecondsFromGranularity(granularity.get_value_or(BucketGranularityEnum::Seconds)); + auto roundingSecondsFromGranularity = getBucketRoundingSecondsFromGranularity( + granularity.get_value_or(BucketGranularityEnum::Seconds)); + + if (allowSecondsParameters) { + if (granularity) { + if (maxSpanSeconds && maxSpanSeconds != maxSpanSecondsFromGranularity) { + return Status{ + ErrorCodes::InvalidOptions, + fmt::format("Timeseries 'bucketMaxSpanSeconds' is not configurable to a value " + "other than the default of {} for the provided granularity", + maxSpanSecondsFromGranularity)}; + } + + if (roundingSeconds && roundingSeconds != roundingSecondsFromGranularity) { + return Status{ + ErrorCodes::InvalidOptions, + fmt::format("Timeseries 'bucketRoundingSeconds' is not configurable to a value " + "other than the default of {} for the provided granularity", + roundingSecondsFromGranularity)}; + } + + if (!maxSpanSeconds) + timeseriesOptions.setBucketMaxSpanSeconds(maxSpanSecondsFromGranularity); + + if (!roundingSeconds) + timeseriesOptions.setBucketRoundingSeconds(roundingSecondsFromGranularity); + + return Status::OK(); + } + + if (!maxSpanAndRoundingSecondsSpecified && (maxSpanSeconds || roundingSeconds)) { + return Status{ + ErrorCodes::InvalidOptions, + "Timeseries 'bucketMaxSpanSeconds' and 'bucketRoundingSeconds' need to be " + "set alongside each other"}; + } + + if (roundingSeconds != maxSpanSeconds) { + return Status{ErrorCodes::InvalidOptions, + "Timeseries 'bucketRoundingSeconds' needs to be equal to " + "'bucketMaxSpanSeconds'"}; + } + + if (!maxSpanSeconds) { + timeseriesOptions.setBucketMaxSpanSeconds(maxSpanSecondsFromGranularity); + timeseriesOptions.setBucketRoundingSeconds(roundingSecondsFromGranularity); + timeseriesOptions.setGranularity(BucketGranularityEnum::Seconds); + } + } else { + if (maxSpanSeconds && maxSpanSecondsFromGranularity != maxSpanSeconds) { + return Status{ + ErrorCodes::InvalidOptions, + fmt::format("Timeseries 'bucketMaxSpanSeconds' is not configurable to a value " + "other than the default of {} for the provided granularity", + maxSpanSecondsFromGranularity)}; + } + if (!granularity) + timeseriesOptions.setGranularity(BucketGranularityEnum::Seconds); + + if (!maxSpanSeconds) + timeseriesOptions.setBucketMaxSpanSeconds(maxSpanSecondsFromGranularity); + } + + return Status::OK(); +} } // namespace timeseries } // namespace mongo diff --git a/src/mongo/db/timeseries/timeseries_options.h b/src/mongo/db/timeseries/timeseries_options.h index 6c95cb01e3c..9704704a5ad 100644 --- a/src/mongo/db/timeseries/timeseries_options.h +++ b/src/mongo/db/timeseries/timeseries_options.h @@ -65,5 +65,12 @@ int getBucketRoundingSecondsFromGranularity(BucketGranularityEnum granularity); * Rounds down timestamp to the specified granularity. */ Date_t roundTimestampToGranularity(const Date_t& time, const TimeseriesOptions& options); + +/** + * Validates the combination of bucketRoundingSeconds, bucketMaxSpanSeconds and granularity in + * TimeseriesOptions. If the parameters are not valid we return a bad status and if no parameters + * are passed through we set them to their default values. + */ +Status validateAndSetBucketingParameters(TimeseriesOptions& timeseriesOptions); } // namespace timeseries } // namespace mongo |