diff --git a/include/knowhere/config.h b/include/knowhere/config.h index caee206f6..3b46ca100 100644 --- a/include/knowhere/config.h +++ b/include/knowhere/config.h @@ -262,10 +262,10 @@ class EntryAccess { class Config { public: static Status - FormatAndCheck(const Config& cfg, Json& json); + FormatAndCheck(const Config& cfg, Json& json, std::string* const err_msg = nullptr); static Status - Load(Config& cfg, const Json& json, PARAM_TYPE type) { + Load(Config& cfg, const Json& json, PARAM_TYPE type, std::string* const err_msg = nullptr) { for (const auto& it : cfg.__DICT__) { const auto& var = it.second; @@ -278,6 +278,9 @@ class Config { continue; } LOG_KNOWHERE_ERROR_ << "Invalid param [" << it.first << "] in json."; + if (err_msg) { + *err_msg = std::string("invalid param ") + it.first; + } return Status::invalid_param_in_json; } if (json.find(it.first) == json.end()) { @@ -286,12 +289,18 @@ class Config { } if (!json[it.first].is_number_integer()) { LOG_KNOWHERE_ERROR_ << "Type conflict in json: param [" << it.first << "] should be integer."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be integer"; + } return Status::type_conflict_in_json; } if (ptr->range.has_value()) { if (json[it.first].get() > std::numeric_limits::max()) { LOG_KNOWHERE_ERROR_ << "Arithmetic overflow: param [" << it.first << "] should be at most " << std::numeric_limits::max(); + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be at most 2147483647"; + } return Status::arithmetic_overflow; } CFG_INT::value_type v = json[it.first]; @@ -300,6 +309,11 @@ class Config { } else { LOG_KNOWHERE_ERROR_ << "Out of range in json: param [" << it.first << "] should be in [" << ptr->range.value().first << ", " << ptr->range.value().second << "]."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " out of range " + "[ " + + std::to_string(ptr->range.value().first) + "," + + std::to_string(ptr->range.value().second) + " ]"; + } return Status::out_of_range_in_json; } } else { @@ -316,6 +330,10 @@ class Config { continue; } LOG_KNOWHERE_ERROR_ << "Invalid param [" << it.first << "] in json."; + if (err_msg) { + *err_msg = std::string("invalid param ") + it.first; + } + return Status::invalid_param_in_json; } if (json.find(it.first) == json.end()) { @@ -324,12 +342,20 @@ class Config { } if (!json[it.first].is_number()) { LOG_KNOWHERE_ERROR_ << "Type conflict in json: param [" << it.first << "] should be a number."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be a number"; + } + return Status::type_conflict_in_json; } if (ptr->range.has_value()) { if (json[it.first].get() > std::numeric_limits::max()) { LOG_KNOWHERE_ERROR_ << "Arithmetic overflow: param [" << it.first << "] should be at most " << std::numeric_limits::max(); + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be at most 3.402823e+38"; + } + return Status::arithmetic_overflow; } CFG_FLOAT::value_type v = json[it.first]; @@ -338,6 +364,12 @@ class Config { } else { LOG_KNOWHERE_ERROR_ << "Out of range in json: param [" << it.first << "] should be in [" << ptr->range.value().first << ", " << ptr->range.value().second << "]."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " out of range " + "[ " + + std::to_string(ptr->range.value().first) + "," + + std::to_string(ptr->range.value().second) + " ]"; + } + return Status::out_of_range_in_json; } } else { @@ -354,6 +386,9 @@ class Config { continue; } LOG_KNOWHERE_ERROR_ << "Invalid param [" << it.first << "] in json."; + if (err_msg) { + *err_msg = std::string("invalid param ") + it.first; + } return Status::invalid_param_in_json; } if (json.find(it.first) == json.end()) { @@ -362,6 +397,9 @@ class Config { } if (!json[it.first].is_string()) { LOG_KNOWHERE_ERROR_ << "Type conflict in json: param [" << it.first << "] should be a string."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be a string"; + } return Status::type_conflict_in_json; } *ptr->val = json[it.first]; @@ -376,6 +414,10 @@ class Config { continue; } LOG_KNOWHERE_ERROR_ << "Invalid param [" << it.first << "] in json."; + if (err_msg) { + *err_msg = std::string("invalid param ") + it.first; + } + return Status::invalid_param_in_json; } if (json.find(it.first) == json.end()) { @@ -384,6 +426,10 @@ class Config { } if (!json[it.first].is_array()) { LOG_KNOWHERE_ERROR_ << "Type conflict in json: param [" << it.first << "] should be an array."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be an array"; + } + return Status::type_conflict_in_json; } *ptr->val = CFG_LIST(); @@ -401,6 +447,10 @@ class Config { continue; } LOG_KNOWHERE_ERROR_ << "Invalid param [" << it.first << "] in json."; + if (err_msg) { + *err_msg = std::string("invalid param ") + it.first; + } + return Status::invalid_param_in_json; } if (json.find(it.first) == json.end()) { @@ -409,6 +459,10 @@ class Config { } if (!json[it.first].is_boolean()) { LOG_KNOWHERE_ERROR_ << "Type conflict in json: param [" << it.first << "] should be a boolean."; + if (err_msg) { + *err_msg = std::string("param ") + it.first + " should be a boolean"; + } + return Status::type_conflict_in_json; } *ptr->val = json[it.first]; diff --git a/include/knowhere/expected.h b/include/knowhere/expected.h index 6bd657aad..55f7082e0 100644 --- a/include/knowhere/expected.h +++ b/include/knowhere/expected.h @@ -83,6 +83,16 @@ class expected { return val.value(); } + const std::string& + what() const { + return msg; + } + + void + operator<<(const std::string& msg) { + this->msg += msg; + } + expected& operator=(const Status& err) { assert(err != Status::success); @@ -93,6 +103,7 @@ class expected { private: std::optional val = std::nullopt; std::optional err = std::nullopt; + std::string msg; }; // Evaluates expr that returns a Status. Does nothing if the returned Status is diff --git a/src/common/config.cc b/src/common/config.cc index 3bcece65d..210c4df6a 100644 --- a/src/common/config.cc +++ b/src/common/config.cc @@ -50,27 +50,32 @@ static const std::unordered_set ext_legal_json_keys = {"metric_type "for_tuning"}; Status -Config::FormatAndCheck(const Config& cfg, Json& json) { - for (auto& it : json.items()) { - bool status = true; - { - auto it_ = cfg.__DICT__.find(it.key()); - if (it_ == cfg.__DICT__.end()) { - status = false; +Config::FormatAndCheck(const Config& cfg, Json& json, std::string* const err_msg) { + try { + for (auto& it : json.items()) { + bool status = true; + { + auto it_ = cfg.__DICT__.find(it.key()); + if (it_ == cfg.__DICT__.end()) { + status = false; + } } - } - { - auto it_ = ext_legal_json_keys.find(it.key()); - if (it_ == ext_legal_json_keys.end()) { - status |= false; - } else { - status |= true; + { + auto it_ = ext_legal_json_keys.find(it.key()); + if (it_ != ext_legal_json_keys.end()) { + status |= true; + } + } + if (!status) { + throw KnowhereException(std::string("invalid json key ") + it.key()); } } - if (!status) { - LOG_KNOWHERE_ERROR_ << "invalid json key: " << it.key(); - return Status::invalid_param_in_json; + } catch (std::exception& e) { + LOG_KNOWHERE_ERROR_ << e.what(); + if (err_msg) { + *err_msg = e.what(); } + return Status::invalid_param_in_json; } try { @@ -82,7 +87,7 @@ Config::FormatAndCheck(const Config& cfg, Json& json) { auto value_str = json[it.first].get(); CFG_INT::value_type v = std::stoi(value_str.c_str(), &sz); if (sz < value_str.length()) { - throw KnowhereException("wrong data type in json"); + throw KnowhereException(std::string("wrong data type in json ") + value_str); } json[it.first] = v; } @@ -102,7 +107,10 @@ Config::FormatAndCheck(const Config& cfg, Json& json) { } } } catch (std::exception& e) { - LOG_KNOWHERE_ERROR_ << "Invalid value in json: " << e.what(); + LOG_KNOWHERE_ERROR_ << e.what(); + if (err_msg) { + *err_msg = e.what(); + } return Status::invalid_value_in_json; } return Status::success;