diff --git a/core/src/value/ValueType.cpp b/core/src/value/ValueType.cpp index 9923c2f83f..3d1c7065b6 100644 --- a/core/src/value/ValueType.cpp +++ b/core/src/value/ValueType.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -26,6 +28,13 @@ std::unordered_map BYTE_UNITS = { {"g", 1024 * 1024 * 1024}, }; +std::map TIME_UNITS = { + // {"seconds", 1ll}, + // {"minutes", 1ll * 60}, + {"hours", 1ll * 60 * 60}, + {"days", 1ll * 60 * 60 * 24}, +}; + bool is_integer(const std::string& s) { if (not s.empty() && (std::isdigit(s[0]) || s[0] == '-')) { @@ -111,7 +120,7 @@ parse_bytes(const std::string& str, std::string& err) { } else { std::stringstream ss; ss << "The specified value for memory (" << str << ") should specify the units." - << "The postfix should be one of the `b` `k` `m` `g` characters"; + << " The postfix should be one of the `b` `k` `m` `g` characters."; err = ss.str(); } } catch (...) { @@ -120,6 +129,31 @@ parse_bytes(const std::string& str, std::string& err) { return 0; } +int64_t +parse_time(const std::string& str, std::string& err) { + try { + const std::regex regex(R"(\s*([0-9]+)\s*(seconds|minutes|hours|days)\s*)"); + std::smatch base_match; + auto& units = TIME_UNITS; + if (std::regex_match(str, base_match, regex) && base_match.size() == 3 && + units.find(base_match[2].str()) != units.end()) { + return stoll(base_match[1].str()) * units[base_match[2].str()]; + } else { + std::stringstream ss; + ss << "The specified value for time (" << str << ") should specify the units." + << " The postfix should be one of the "; + for (auto& pair : units) { + ss << "`" << pair.first << "` "; + } + ss << "words."; + err = ss.str(); + } + } catch (...) { + err = "Unknown error happened on parse time."; + } + return 0; +} + } // namespace // Use (void) to silent unused warnings. @@ -487,4 +521,75 @@ SizeValue::Get() { } } +TimeValue::TimeValue(const char* name, const char* alias, bool modifiable, int64_t lower_bound, int64_t upper_bound, + Value& config, int64_t default_value, + std::function is_valid_fn) + : BaseValue(name, alias, modifiable), + config_(config), + lower_bound_(lower_bound), + upper_bound_(upper_bound), + default_value_(default_value), + is_valid_fn_(std::move(is_valid_fn)) { +} + +void +TimeValue::Init() { + BaseValue::Init(); + config_ = default_value_; +} + +void +TimeValue::Set(const std::string& val, bool update) { + assertm(inited_, "uninitialized"); + try { + /* Check modifiable */ + if (update and not modifiable_) { + throw Immutable(name_, val); + } + + /* Parse from string */ + std::string err; + int64_t value = parse_time(val, err); + if (not err.empty()) { + throw Invalid(name_, val, err); + } + + /* Boundary check */ + if (not boundary_check(value, lower_bound_, upper_bound_)) { + throw OutOfRange(name_, val, lower_bound_, upper_bound_); + } + + /* Validate */ + if (is_valid_fn_ && not is_valid_fn_(value, err)) { + throw Invalid(name_, val, err); + } + + /* Set value */ + config_ = value; + } catch (ValueError& e) { + throw; + } catch (...) { + throw Unexpected(name_, val); + } +} + +std::string +TimeValue::Get() { + assertm(inited_, "uninitialized"); + auto val = config_(); + const int64_t second = 1ll; + const int64_t minute = second * 60; + const int64_t hour = minute * 60; + const int64_t day = hour * 24; + if (val % day == 0) { + return std::to_string(val / day) + "days"; + } else if (val % hour == 0) { + return std::to_string(val / hour) + "hours"; + } else if (val % minute == 0) { + return std::to_string(val / minute) + "minutes"; + } else { + return std::to_string(val) + "seconds"; + } +} + } // namespace milvus diff --git a/core/src/value/ValueType.h b/core/src/value/ValueType.h index 8afcf06b22..2683a40e76 100644 --- a/core/src/value/ValueType.h +++ b/core/src/value/ValueType.h @@ -270,6 +270,30 @@ class SizeValue : public BaseValue { Get() override; }; +class TimeValue : public BaseValue { + public: + TimeValue(const char* name, const char* alias, bool modifiable, int64_t lower_bound, int64_t upper_bound, + Value& config, int64_t default_value, + std::function is_valid_fn = nullptr); + + private: + Value& config_; + int64_t lower_bound_; + int64_t upper_bound_; + const int64_t default_value_; + std::function is_valid_fn_; + + public: + void + Init() override; + + void + Set(const std::string& value, bool update) override; + + std::string + Get() override; +}; + /* create config with {is_valid} function */ #define CreateBoolValue(name, modifiable, config_addr, default, is_valid) \ @@ -292,4 +316,7 @@ class SizeValue : public BaseValue { #define CreateSizeValue(name, modifiable, lower_bound, upper_bound, config_addr, default, is_valid) \ std::make_shared(name, nullptr, modifiable, lower_bound, upper_bound, config_addr, (default), is_valid) +#define CreateTimeValue(name, modifiable, lower_bound, upper_bound, config_addr, default, is_valid) \ + std::make_shared(name, nullptr, modifiable, lower_bound, upper_bound, config_addr, (default), is_valid) + } // namespace milvus diff --git a/core/src/value/config/ConfigInit.cpp b/core/src/value/config/ConfigInit.cpp index 2d9f8d0e57..bcb7bc8459 100644 --- a/core/src/value/config/ConfigInit.cpp +++ b/core/src/value/config/ConfigInit.cpp @@ -19,6 +19,8 @@ #define _IMMUTABLE (false) const int64_t MB = (1024ll * 1024); const int64_t GB = (1024ll * 1024 * 1024); +const int64_t HOURS = (3600ll); +const int64_t DAYS = (HOURS * 24); namespace milvus { @@ -101,6 +103,8 @@ is_cachesize_valid(int64_t size, std::string& err) { { #name, CreateFloatingValue(#name, modifiable, lower_bound, upper_bound, config.name, default, is_valid) } #define Size_(name, modifiable, lower_bound, upper_bound, default, is_valid) \ { #name, CreateSizeValue(#name, modifiable, lower_bound, upper_bound, config.name, default, is_valid) } +#define Time_(name, modifiable, lower_bound, upper_bound, default, is_valid) \ + { #name, CreateTimeValue(#name, modifiable, lower_bound, upper_bound, config.name, default, is_valid) } #define Bool(name, default) Bool_(name, true, default, nullptr) #define String(name, default) String_(name, true, default, nullptr) @@ -110,6 +114,7 @@ is_cachesize_valid(int64_t size, std::string& err) { #define Floating(name, lower_bound, upper_bound, default) \ Floating_(name, true, lower_bound, upper_bound, default, nullptr) #define Size(name, lower_bound, upper_bound, default) Size_(name, true, lower_bound, upper_bound, default, nullptr) +#define Time(name, lower_bound, upper_bound, default) Time_(name, true, lower_bound, upper_bound, default, nullptr) std::unordered_map InitConfig() { @@ -170,6 +175,7 @@ InitConfig() { Bool(logs.log_to_file, true), String(log.min_messages, "warning"), + // Time(log.rotation_age, 0, 16384ll * HOURS, 24ll * HOURS), /* tracing */ String(tracing.json_config_path, ""), diff --git a/core/src/value/config/ServerConfig.h b/core/src/value/config/ServerConfig.h index ba20abae86..2492ec4086 100644 --- a/core/src/value/config/ServerConfig.h +++ b/core/src/value/config/ServerConfig.h @@ -146,6 +146,7 @@ struct ServerConfig { struct Log { String min_messages; + // Integer rotation_age; } log; struct System {