diff options
author | Jennifer Peshansky <jennifer.peshansky@mongodb.com> | 2022-11-03 19:39:22 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-11-03 20:10:49 +0000 |
commit | 4aea76be781c61097b945afd70e1c16de0ce5e3e (patch) | |
tree | 0ddcd23877f406e779e06260a2b1f0b8110ba783 | |
parent | 556bf6acd152734c99160bf5cc4f4bb362b5235c (diff) | |
download | mongo-4aea76be781c61097b945afd70e1c16de0ce5e3e.tar.gz |
SERVER-70854 Add telemetry infrastructure and generic memory size tools
-rw-r--r-- | src/mongo/db/query/SConscript | 5 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache_size_parameter_test.cpp | 79 | ||||
-rw-r--r-- | src/mongo/db/query/query_knobs.idl | 27 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_plan_cache.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_plan_cache_on_parameter_change.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_plan_cache_on_parameter_change.h | 6 | ||||
-rw-r--r-- | src/mongo/db/query/telemetry_util.cpp | 52 | ||||
-rw-r--r-- | src/mongo/db/query/telemetry_util.h | 50 | ||||
-rw-r--r-- | src/mongo/util/SConscript | 12 | ||||
-rw-r--r-- | src/mongo/util/memory_util.cpp (renamed from src/mongo/db/query/plan_cache_size_parameter.cpp) | 21 | ||||
-rw-r--r-- | src/mongo/util/memory_util.h (renamed from src/mongo/db/query/plan_cache_size_parameter.h) | 18 | ||||
-rw-r--r-- | src/mongo/util/memory_util_test.cpp | 73 |
12 files changed, 253 insertions, 122 deletions
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 4db9f6b6920..a8e0d995716 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -100,6 +100,7 @@ env.Library( LIBDEPS=[ "$BUILD_DIR/mongo/base", "$BUILD_DIR/mongo/db/exec/sbe/query_sbe", + '$BUILD_DIR/mongo/util/memory_util', "canonical_query", ], ) @@ -257,14 +258,15 @@ env.Library( source=[ 'ce_mode_parameter.cpp', 'framework_control.cpp', - 'plan_cache_size_parameter.cpp', 'query_feature_flags.idl', 'query_knobs.idl', 'sbe_plan_cache_on_parameter_change.cpp', + 'telemetry_util.cpp', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/server_base', '$BUILD_DIR/mongo/db/service_context', + '$BUILD_DIR/mongo/util/memory_util', '$BUILD_DIR/mongo/util/pcre_wrapper', ], ) @@ -372,7 +374,6 @@ env.CppUnitTest( 'map_reduce_output_format_test.cpp', "parsed_distinct_test.cpp", "plan_cache_indexability_test.cpp", - "plan_cache_size_parameter_test.cpp", "plan_cache_key_info_test.cpp", "plan_cache_test.cpp", "plan_ranker_test.cpp", diff --git a/src/mongo/db/query/plan_cache_size_parameter_test.cpp b/src/mongo/db/query/plan_cache_size_parameter_test.cpp deleted file mode 100644 index 1f0fbf76a27..00000000000 --- a/src/mongo/db/query/plan_cache_size_parameter_test.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (C) 2021-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/db/query/plan_cache_size_parameter.h" - -#include "mongo/unittest/unittest.h" - -namespace mongo::plan_cache_util { - -bool operator==(const PlanCacheSizeParameter& lhs, const PlanCacheSizeParameter& rhs) { - constexpr double kEpsilon = 1e-10; - return std::abs(lhs.size - rhs.size) < kEpsilon && lhs.units == rhs.units; -} - -TEST(PlanCacheParameterTest, ParseUnitStringPercent) { - ASSERT_TRUE(PlanCacheSizeUnits::kPercent == parseUnitString("%")); -} - -TEST(PlanCacheParameterTest, ParseUnitStringMB) { - ASSERT_TRUE(PlanCacheSizeUnits::kMB == parseUnitString("MB")); - ASSERT_TRUE(PlanCacheSizeUnits::kMB == parseUnitString("mb")); - ASSERT_TRUE(PlanCacheSizeUnits::kMB == parseUnitString("mB")); - ASSERT_TRUE(PlanCacheSizeUnits::kMB == parseUnitString("Mb")); -} - -TEST(PlanCacheParameterTest, ParseUnitStringGB) { - ASSERT_TRUE(PlanCacheSizeUnits::kGB == parseUnitString("GB")); - ASSERT_TRUE(PlanCacheSizeUnits::kGB == parseUnitString("gb")); - ASSERT_TRUE(PlanCacheSizeUnits::kGB == parseUnitString("gB")); - ASSERT_TRUE(PlanCacheSizeUnits::kGB == parseUnitString("Gb")); -} - -TEST(PlanCacheParameterTest, ParseUnitStringIncorrectValue) { - ASSERT_NOT_OK(parseUnitString("").getStatus()); - ASSERT_NOT_OK(parseUnitString(" ").getStatus()); - ASSERT_NOT_OK(parseUnitString("KB").getStatus()); -} - -TEST(PlanCacheParameterTest, ParsePlanCacheSizeParameter) { - ASSERT_TRUE((PlanCacheSizeParameter{10.0, PlanCacheSizeUnits::kPercent}) == - PlanCacheSizeParameter::parse("10%")); - ASSERT_TRUE((PlanCacheSizeParameter{300.0, PlanCacheSizeUnits::kMB}) == - PlanCacheSizeParameter::parse("300MB")); - ASSERT_TRUE((PlanCacheSizeParameter{4.0, PlanCacheSizeUnits::kGB}) == - PlanCacheSizeParameter::parse("4GB")); - ASSERT_TRUE((PlanCacheSizeParameter{5.1, PlanCacheSizeUnits::kPercent}) == - PlanCacheSizeParameter::parse(" 5.1%")); - ASSERT_TRUE((PlanCacheSizeParameter{11.1, PlanCacheSizeUnits::kMB}) == - PlanCacheSizeParameter::parse("11.1 mb")); - ASSERT_TRUE((PlanCacheSizeParameter{12.1, PlanCacheSizeUnits::kGB}) == - PlanCacheSizeParameter::parse(" 12.1 Gb ")); -} -} // namespace mongo::plan_cache_util diff --git a/src/mongo/db/query/query_knobs.idl b/src/mongo/db/query/query_knobs.idl index 1a7423a9a12..0584ec15b69 100644 --- a/src/mongo/db/query/query_knobs.idl +++ b/src/mongo/db/query/query_knobs.idl @@ -30,8 +30,8 @@ global: cpp_namespace: "mongo" cpp_includes: - "mongo/db/query/ce_mode_parameter.h" - - "mongo/db/query/plan_cache_size_parameter.h" - "mongo/db/query/sbe_plan_cache_on_parameter_change.h" + - "mongo/db/query/telemetry_util.h" - "mongo/platform/atomic_proxy.h" - "mongo/platform/atomic_word.h" @@ -948,6 +948,31 @@ server_parameters: default: false test_only: true + internalQueryConfigureTelemetrySamplingRate: + description: "The maximum number of queries per second that are sampled for query telemetry. + If the rate of queries goes above this number, then rate limiting will kick in, and any + further queries will not be sampled. The default is INT_MAX, effectively meaning that all + queries will be sampled. This can be set to 0 to turn telemetry off completely." + set_at: [ startup, runtime ] + cpp_varname: "queryTelemetrySamplingRate" + cpp_vartype: AtomicWord<int> + default: 2147483647 + + internalQueryConfigureTelemetryCacheSize: + description: "The maximum amount of memory that the system will allocate for the query telemetry + cache. This will accept values in either of the following formats: + 1. <number>% indicates a percentage of the physical memory available to the process. E.g.: 15%. + 2. <number>(MB|GB), indicates the amount of memory in MB or GB. E.g.: 1.5GB, 100MB. + The default value is 5%, which means 5% of the physical memory available to the process." + set_at: [ startup, runtime ] + cpp_varname: "queryTelemetryCacheSize" + cpp_vartype: synchronized_value<std::string> + default: "5%" + on_update: telemetry_util::onTelemetryCacheSizeUpdate + validator: + callback: telemetry_util::validateTelemetryCacheSize + + # Note for adding additional query knobs: # # When adding a new query knob, you should consider whether or not you need to add an 'on_update' diff --git a/src/mongo/db/query/sbe_plan_cache.cpp b/src/mongo/db/query/sbe_plan_cache.cpp index fc267726f64..18d8b9fc5c9 100644 --- a/src/mongo/db/query/sbe_plan_cache.cpp +++ b/src/mongo/db/query/sbe_plan_cache.cpp @@ -30,9 +30,9 @@ #include "mongo/db/query/sbe_plan_cache.h" -#include "mongo/db/query/plan_cache_size_parameter.h" #include "mongo/db/server_options.h" #include "mongo/logv2/log.h" +#include "mongo/util/memory_util.h" #include "mongo/util/processinfo.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery @@ -44,19 +44,19 @@ namespace { const auto sbePlanCacheDecoration = ServiceContext::declareDecoration<std::unique_ptr<sbe::PlanCache>>(); -size_t convertToSizeInBytes(const plan_cache_util::PlanCacheSizeParameter& param) { +size_t convertToSizeInBytes(const memory_util::MemorySize& memSize) { constexpr size_t kBytesInMB = 1024 * 1024; constexpr size_t kMBytesInGB = 1024; - double sizeInMB = param.size; + double sizeInMB = memSize.size; - switch (param.units) { - case plan_cache_util::PlanCacheSizeUnits::kPercent: + switch (memSize.units) { + case memory_util::MemoryUnits::kPercent: sizeInMB *= ProcessInfo::getMemSizeMB() / 100.0; break; - case plan_cache_util::PlanCacheSizeUnits::kMB: + case memory_util::MemoryUnits::kMB: break; - case plan_cache_util::PlanCacheSizeUnits::kGB: + case memory_util::MemoryUnits::kGB: sizeInMB *= kMBytesInGB; break; } @@ -75,8 +75,7 @@ size_t capPlanCacheSize(size_t planCacheSize) { constexpr size_t kMaximumPlanCacheSize = 500 * kBytesInGB; // Maximum size of the plan cache expressed as a share of the memory available to the process. - const plan_cache_util::PlanCacheSizeParameter limitToProcessSize{ - 25, plan_cache_util::PlanCacheSizeUnits::kPercent}; + const memory_util::MemorySize limitToProcessSize{25, memory_util::MemoryUnits::kPercent}; const size_t limitToProcessSizeInBytes = convertToSizeInBytes(limitToProcessSize); // The size will be capped by the minimum of the two values defined above. @@ -93,8 +92,8 @@ size_t capPlanCacheSize(size_t planCacheSize) { return planCacheSize; } -size_t getPlanCacheSizeInBytes(const plan_cache_util::PlanCacheSizeParameter& param) { - size_t planCacheSize = convertToSizeInBytes(param); +size_t getPlanCacheSizeInBytes(const memory_util::MemorySize& memSize) { + size_t planCacheSize = convertToSizeInBytes(memSize); uassert(5968001, "Cache size must be at least 1KB * number of cores", planCacheSize >= 1024 * ProcessInfo::getNumCores()); @@ -103,10 +102,9 @@ size_t getPlanCacheSizeInBytes(const plan_cache_util::PlanCacheSizeParameter& pa class PlanCacheOnParamChangeUpdaterImpl final : public plan_cache_util::OnParamChangeUpdater { public: - void updateCacheSize(ServiceContext* serviceCtx, - plan_cache_util::PlanCacheSizeParameter parameter) final { + void updateCacheSize(ServiceContext* serviceCtx, memory_util::MemorySize memSize) final { if (feature_flags::gFeatureFlagSbeFull.isEnabledAndIgnoreFCV()) { - auto size = getPlanCacheSizeInBytes(parameter); + auto size = getPlanCacheSizeInBytes(memSize); auto& globalPlanCache = sbePlanCacheDecoration(serviceCtx); globalPlanCache->reset(size); } @@ -126,7 +124,7 @@ ServiceContext::ConstructorActionRegisterer planCacheRegisterer{ std::make_unique<PlanCacheOnParamChangeUpdaterImpl>(); if (feature_flags::gFeatureFlagSbeFull.isEnabledAndIgnoreFCV()) { - auto status = plan_cache_util::PlanCacheSizeParameter::parse(planCacheSize.get()); + auto status = memory_util::MemorySize::parse(planCacheSize.get()); uassertStatusOK(status); auto size = getPlanCacheSizeInBytes(status.getValue()); diff --git a/src/mongo/db/query/sbe_plan_cache_on_parameter_change.cpp b/src/mongo/db/query/sbe_plan_cache_on_parameter_change.cpp index b7ea17858d8..5854cea3c57 100644 --- a/src/mongo/db/query/sbe_plan_cache_on_parameter_change.cpp +++ b/src/mongo/db/query/sbe_plan_cache_on_parameter_change.cpp @@ -56,7 +56,7 @@ Status clearSbeCacheOnParameterChangeHelper() { } Status onPlanCacheSizeUpdate(const std::string& str) { - auto newSize = PlanCacheSizeParameter::parse(str); + auto newSize = memory_util::MemorySize::parse(str); if (!newSize.isOK()) { return newSize.getStatus(); } @@ -73,7 +73,7 @@ Status onPlanCacheSizeUpdate(const std::string& str) { } Status validatePlanCacheSize(const std::string& str, const boost::optional<TenantId>&) { - return PlanCacheSizeParameter::parse(str).getStatus(); + return memory_util::MemorySize::parse(str).getStatus(); } const Decorable<ServiceContext>::Decoration<std::unique_ptr<OnParamChangeUpdater>> diff --git a/src/mongo/db/query/sbe_plan_cache_on_parameter_change.h b/src/mongo/db/query/sbe_plan_cache_on_parameter_change.h index fd7f090d766..4135bb7f2b9 100644 --- a/src/mongo/db/query/sbe_plan_cache_on_parameter_change.h +++ b/src/mongo/db/query/sbe_plan_cache_on_parameter_change.h @@ -32,8 +32,8 @@ #include <string> #include "mongo/base/status.h" -#include "mongo/db/query/plan_cache_size_parameter.h" #include "mongo/db/service_context.h" +#include "mongo/util/memory_util.h" namespace mongo::plan_cache_util { @@ -70,11 +70,11 @@ public: virtual ~OnParamChangeUpdater() = default; /** - * Resizes the SBE plan cache decorating 'serviceCtx' to the new size given by 'parameter'. If + * Resizes the SBE plan cache decorating 'serviceCtx' to the new size given by 'memSize'. If * the new cache size is smaller than the old, cache entries are evicted in order to ensure the * cache fits within the new size bound. */ - virtual void updateCacheSize(ServiceContext* serviceCtx, PlanCacheSizeParameter parameter) = 0; + virtual void updateCacheSize(ServiceContext* serviceCtx, memory_util::MemorySize memSize) = 0; /** * Deletes all plans from the SBE plan cache decorating 'serviceCtx'. diff --git a/src/mongo/db/query/telemetry_util.cpp b/src/mongo/db/query/telemetry_util.cpp new file mode 100644 index 00000000000..8e3f6f6361d --- /dev/null +++ b/src/mongo/db/query/telemetry_util.cpp @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/db/query/telemetry_util.h" +#include "mongo/util/memory_util.h" + +namespace mongo { +namespace telemetry_util { + +Status onTelemetryCacheSizeUpdate(const std::string& str) { + auto newSize = memory_util::MemorySize::parse(str); + if (!newSize.isOK()) { + return newSize.getStatus(); + } + + // TODO SERVER-71065 update telemetry cache size + + return Status::OK(); +} + +Status validateTelemetryCacheSize(const std::string& str, const boost::optional<TenantId>&) { + return memory_util::MemorySize::parse(str).getStatus(); +} + +} // namespace telemetry_util +} // namespace mongo diff --git a/src/mongo/db/query/telemetry_util.h b/src/mongo/db/query/telemetry_util.h new file mode 100644 index 00000000000..a55ca035d74 --- /dev/null +++ b/src/mongo/db/query/telemetry_util.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/base/status.h" +#include "mongo/db/service_context.h" + +namespace mongo { + +namespace telemetry_util { + +/** + * Callback called on a change of telemetryCacheSize parameter. + */ +Status onTelemetryCacheSizeUpdate(const std::string& str); + +/** + * Callback called on validation of telemetryCacheSize parameter. + */ +Status validateTelemetryCacheSize(const std::string& str, const boost::optional<TenantId>&); + +} // namespace telemetry_util +} // namespace mongo diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index e90c9ffb348..1ba28162068 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -614,6 +614,16 @@ env.Library( ], ) +env.Library( + target='memory_util', + source=[ + 'memory_util.cpp', + ], + LIBDEPS=[ + 'pcre_wrapper', + ], +) + env.Benchmark( target='hash_table_bm', source='hash_table_bm.cpp', @@ -748,6 +758,7 @@ icuEnv.CppUnitTest( 'lru_cache_test.cpp', 'md5_test.cpp', 'md5main.cpp', + 'memory_util_test.cpp', 'optional_util_test.cpp', 'out_of_line_executor_test.cpp', 'overloaded_visitor_test.cpp', @@ -795,6 +806,7 @@ icuEnv.CppUnitTest( 'icu', 'latch_analyzer' if get_option('use-diagnostic-latches') == 'on' else [], 'md5', + 'memory_util', 'pcre_util', 'pcre_wrapper', 'periodic_runner_impl', diff --git a/src/mongo/db/query/plan_cache_size_parameter.cpp b/src/mongo/util/memory_util.cpp index 5f1f66bcaf8..28b5822c508 100644 --- a/src/mongo/db/query/plan_cache_size_parameter.cpp +++ b/src/mongo/util/memory_util.cpp @@ -27,35 +27,34 @@ * it in the license file. */ -#include "mongo/db/query/plan_cache_size_parameter.h" +#include "mongo/util/memory_util.h" -#include "mongo/db/query/query_knobs_gen.h" #include "mongo/util/pcre.h" -namespace mongo::plan_cache_util { +namespace mongo::memory_util { -StatusWith<PlanCacheSizeUnits> parseUnitString(const std::string& strUnit) { +StatusWith<MemoryUnits> parseUnitString(const std::string& strUnit) { if (strUnit.empty()) { return Status(ErrorCodes::Error{6007010}, "Unit value cannot be empty"); } if (strUnit[0] == '%') { - return PlanCacheSizeUnits::kPercent; + return MemoryUnits::kPercent; } else if (strUnit[0] == 'M' || strUnit[0] == 'm') { - return PlanCacheSizeUnits::kMB; + return MemoryUnits::kMB; } else if (strUnit[0] == 'G' || strUnit[0] == 'g') { - return PlanCacheSizeUnits::kGB; + return MemoryUnits::kGB; } return Status(ErrorCodes::Error{6007011}, "Incorrect unit value"); } -StatusWith<PlanCacheSizeParameter> PlanCacheSizeParameter::parse(const std::string& str) { +StatusWith<MemorySize> MemorySize::parse(const std::string& str) { // Looks for a floating point number with followed by a unit suffix (MB, GB, %). static auto& re = *new pcre::Regex(R"re((?i)^\s*(\d+\.?\d*)\s*(MB|GB|%)\s*$)re"); auto m = re.matchView(str); if (!m) { - return {ErrorCodes::Error{6007012}, "Unable to parse plan cache size string"}; + return {ErrorCodes::Error{6007012}, "Unable to parse memory size string"}; } double size = std::stod(std::string{m[1]}); std::string strUnit{m[2]}; @@ -65,7 +64,7 @@ StatusWith<PlanCacheSizeParameter> PlanCacheSizeParameter::parse(const std::stri return statusWithUnit.getStatus(); } - return PlanCacheSizeParameter{size, statusWithUnit.getValue()}; + return MemorySize{size, statusWithUnit.getValue()}; } -} // namespace mongo::plan_cache_util +} // namespace mongo::memory_util diff --git a/src/mongo/db/query/plan_cache_size_parameter.h b/src/mongo/util/memory_util.h index 322a1fff564..d1452dbfee9 100644 --- a/src/mongo/db/query/plan_cache_size_parameter.h +++ b/src/mongo/util/memory_util.h @@ -33,27 +33,27 @@ #include "mongo/base/status_with.h" -namespace mongo::plan_cache_util { +namespace mongo::memory_util { /** - * Defines units of planCacheSize parameter. + * Defines units of memory. */ -enum class PlanCacheSizeUnits { +enum class MemoryUnits { kPercent, kMB, kGB, }; -StatusWith<PlanCacheSizeUnits> parseUnitString(const std::string& strUnit); +StatusWith<MemoryUnits> parseUnitString(const std::string& strUnit); /** - * Represents parsed planCacheSize parameter. + * Represents parsed memory size parameter. */ -struct PlanCacheSizeParameter { - static StatusWith<PlanCacheSizeParameter> parse(const std::string& str); +struct MemorySize { + static StatusWith<MemorySize> parse(const std::string& str); const double size; - const PlanCacheSizeUnits units; + const MemoryUnits units; }; -} // namespace mongo::plan_cache_util +} // namespace mongo::memory_util diff --git a/src/mongo/util/memory_util_test.cpp b/src/mongo/util/memory_util_test.cpp new file mode 100644 index 00000000000..d19ca82e89a --- /dev/null +++ b/src/mongo/util/memory_util_test.cpp @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2021-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/util/memory_util.h" + +#include "mongo/unittest/unittest.h" + +namespace mongo::memory_util { + +bool operator==(const MemorySize& lhs, const MemorySize& rhs) { + constexpr double kEpsilon = 1e-10; + return std::abs(lhs.size - rhs.size) < kEpsilon && lhs.units == rhs.units; +} + +TEST(MemorySizeTest, ParseUnitStringPercent) { + ASSERT_TRUE(MemoryUnits::kPercent == parseUnitString("%")); +} + +TEST(MemorySizeTest, ParseUnitStringMB) { + ASSERT_TRUE(MemoryUnits::kMB == parseUnitString("MB")); + ASSERT_TRUE(MemoryUnits::kMB == parseUnitString("mb")); + ASSERT_TRUE(MemoryUnits::kMB == parseUnitString("mB")); + ASSERT_TRUE(MemoryUnits::kMB == parseUnitString("Mb")); +} + +TEST(MemorySizeTest, ParseUnitStringGB) { + ASSERT_TRUE(MemoryUnits::kGB == parseUnitString("GB")); + ASSERT_TRUE(MemoryUnits::kGB == parseUnitString("gb")); + ASSERT_TRUE(MemoryUnits::kGB == parseUnitString("gB")); + ASSERT_TRUE(MemoryUnits::kGB == parseUnitString("Gb")); +} + +TEST(MemorySizeTest, ParseUnitStringIncorrectValue) { + ASSERT_NOT_OK(parseUnitString("").getStatus()); + ASSERT_NOT_OK(parseUnitString(" ").getStatus()); + ASSERT_NOT_OK(parseUnitString("KB").getStatus()); +} + +TEST(MemorySizeTest, ParseMemorySize) { + ASSERT_TRUE((MemorySize{10.0, MemoryUnits::kPercent}) == MemorySize::parse("10%")); + ASSERT_TRUE((MemorySize{300.0, MemoryUnits::kMB}) == MemorySize::parse("300MB")); + ASSERT_TRUE((MemorySize{4.0, MemoryUnits::kGB}) == MemorySize::parse("4GB")); + ASSERT_TRUE((MemorySize{5.1, MemoryUnits::kPercent}) == MemorySize::parse(" 5.1%")); + ASSERT_TRUE((MemorySize{11.1, MemoryUnits::kMB}) == MemorySize::parse("11.1 mb")); + ASSERT_TRUE((MemorySize{12.1, MemoryUnits::kGB}) == MemorySize::parse(" 12.1 Gb ")); +} +} // namespace mongo::memory_util |