From d0dab501cbb587665d8dd97135df201a2da7c5b3 Mon Sep 17 00:00:00 2001 From: zhao liwei Date: Tue, 4 Feb 2020 10:59:04 +0800 Subject: [PATCH] feat: add check for app envs (#353) --- include/dsn/dist/replication/replica_envs.h | 59 +++++++ .../replication/common/replication_common.cpp | 28 +++ .../replication/common/replication_common.h | 8 - src/dist/replication/lib/replica_config.cpp | 1 + src/dist/replication/lib/replica_throttle.cpp | 1 + .../meta_server/app_env_validator.cpp | 162 ++++++++++++++++++ .../meta_server/app_env_validator.h | 54 ++++++ .../replication/meta_server/server_state.cpp | 24 +-- .../unit_test/meta_app_envs_test.cpp | 122 +++++++++++-- .../unit_test/meta_http_service_test.cpp | 4 +- .../test/meta_test/unit_test/meta_test_base.h | 8 +- .../meta_test/unit_test/server_state_test.cpp | 21 ++- 12 files changed, 441 insertions(+), 51 deletions(-) create mode 100644 include/dsn/dist/replication/replica_envs.h create mode 100644 src/dist/replication/meta_server/app_env_validator.cpp create mode 100644 src/dist/replication/meta_server/app_env_validator.h diff --git a/include/dsn/dist/replication/replica_envs.h b/include/dsn/dist/replication/replica_envs.h new file mode 100644 index 0000000000..464427ec45 --- /dev/null +++ b/include/dsn/dist/replication/replica_envs.h @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Microsoft Corporation + * + * -=- Robust Distributed System Nucleus (rDSN) -=- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include + +namespace dsn { +namespace replication { + +class replica_envs +{ +public: + static const std::string DENY_CLIENT_WRITE; + static const std::string WRITE_QPS_THROTTLING; + static const std::string WRITE_SIZE_THROTTLING; + static const uint64_t MIN_SLOW_QUERY_THRESHOLD_MS; + static const std::string SLOW_QUERY_THRESHOLD; + static const std::string TABLE_LEVEL_DEFAULT_TTL; + static const std::string ROCKSDB_USAGE_SCENARIO; + static const std::string ROCKSDB_CHECKPOINT_RESERVE_MIN_COUNT; + static const std::string ROCKSDB_CHECKPOINT_RESERVE_TIME_SECONDS; + static const std::string MANUAL_COMPACT_DISABLED; + static const std::string MANUAL_COMPACT_MAX_CONCURRENT_RUNNING_COUNT; + static const std::string MANUAL_COMPACT_ONCE_TRIGGER_TIME; + static const std::string MANUAL_COMPACT_ONCE_TARGET_LEVEL; + static const std::string MANUAL_COMPACT_ONCE_BOTTOMMOST_LEVEL_COMPACTION; + static const std::string MANUAL_COMPACT_PERIODIC_TRIGGER_TIME; + static const std::string MANUAL_COMPACT_PERIODIC_TARGET_LEVEL; + static const std::string MANUAL_COMPACT_PERIODIC_BOTTOMMOST_LEVEL_COMPACTION; + static const std::string BUSINESS_INFO; +}; + +} // namespace replication +} // namespace dsn diff --git a/src/dist/replication/common/replication_common.cpp b/src/dist/replication/common/replication_common.cpp index 82c260fbf8..369d70dd0b 100644 --- a/src/dist/replication/common/replication_common.cpp +++ b/src/dist/replication/common/replication_common.cpp @@ -27,6 +27,7 @@ #include "replication_common.h" #include #include +#include namespace dsn { namespace replication { @@ -600,6 +601,33 @@ const std::string backup_restore_constant::SKIP_BAD_PARTITION("restore.skip_bad_ const std::string replica_envs::DENY_CLIENT_WRITE("replica.deny_client_write"); const std::string replica_envs::WRITE_QPS_THROTTLING("replica.write_throttling"); const std::string replica_envs::WRITE_SIZE_THROTTLING("replica.write_throttling_by_size"); +const uint64_t replica_envs::MIN_SLOW_QUERY_THRESHOLD_MS = 20; +const std::string replica_envs::SLOW_QUERY_THRESHOLD("replica.slow_query_threshold"); +const std::string replica_envs::ROCKSDB_USAGE_SCENARIO("rocksdb.usage_scenario"); +const std::string replica_envs::TABLE_LEVEL_DEFAULT_TTL("default_ttl"); +const std::string MANUAL_COMPACT_PREFIX("manual_compact."); +const std::string replica_envs::MANUAL_COMPACT_DISABLED(MANUAL_COMPACT_PREFIX + "disabled"); +const std::string replica_envs::MANUAL_COMPACT_MAX_CONCURRENT_RUNNING_COUNT( + MANUAL_COMPACT_PREFIX + "max_concurrent_running_count"); +const std::string MANUAL_COMPACT_ONCE_PREFIX(MANUAL_COMPACT_PREFIX + "once."); +const std::string replica_envs::MANUAL_COMPACT_ONCE_TRIGGER_TIME(MANUAL_COMPACT_ONCE_PREFIX + + "trigger_time"); +const std::string replica_envs::MANUAL_COMPACT_ONCE_TARGET_LEVEL(MANUAL_COMPACT_ONCE_PREFIX + + "target_level"); +const std::string replica_envs::MANUAL_COMPACT_ONCE_BOTTOMMOST_LEVEL_COMPACTION( + MANUAL_COMPACT_ONCE_PREFIX + "bottommost_level_compaction"); +const std::string MANUAL_COMPACT_PERIODIC_PREFIX(MANUAL_COMPACT_PREFIX + "periodic."); +const std::string replica_envs::MANUAL_COMPACT_PERIODIC_TRIGGER_TIME( + MANUAL_COMPACT_PERIODIC_PREFIX + "trigger_time"); +const std::string replica_envs::MANUAL_COMPACT_PERIODIC_TARGET_LEVEL( + MANUAL_COMPACT_PERIODIC_PREFIX + "target_level"); +const std::string replica_envs::MANUAL_COMPACT_PERIODIC_BOTTOMMOST_LEVEL_COMPACTION( + MANUAL_COMPACT_PERIODIC_PREFIX + "bottommost_level_compaction"); +const std::string + replica_envs::ROCKSDB_CHECKPOINT_RESERVE_MIN_COUNT("rocksdb.checkpoint.reserve_min_count"); +const std::string replica_envs::ROCKSDB_CHECKPOINT_RESERVE_TIME_SECONDS( + "rocksdb.checkpoint.reserve_time_seconds"); +const std::string replica_envs::BUSINESS_INFO("business.info"); namespace cold_backup { std::string get_policy_path(const std::string &root, const std::string &policy_name) diff --git a/src/dist/replication/common/replication_common.h b/src/dist/replication/common/replication_common.h index 502f6c95c1..148a6f149f 100644 --- a/src/dist/replication/common/replication_common.h +++ b/src/dist/replication/common/replication_common.h @@ -149,14 +149,6 @@ class backup_restore_constant static const std::string SKIP_BAD_PARTITION; }; -class replica_envs -{ -public: - static const std::string DENY_CLIENT_WRITE; - static const std::string WRITE_QPS_THROTTLING; - static const std::string WRITE_SIZE_THROTTLING; -}; - namespace cold_backup { // // Attention: when compose the path on block service, we use appname_appid, because appname_appid diff --git a/src/dist/replication/lib/replica_config.cpp b/src/dist/replication/lib/replica_config.cpp index df1381daed..9e8b99a5ac 100644 --- a/src/dist/replication/lib/replica_config.cpp +++ b/src/dist/replication/lib/replica_config.cpp @@ -41,6 +41,7 @@ #include #include #include +#include namespace dsn { namespace replication { diff --git a/src/dist/replication/lib/replica_throttle.cpp b/src/dist/replication/lib/replica_throttle.cpp index 0ba6dc84e6..42da66af40 100644 --- a/src/dist/replication/lib/replica_throttle.cpp +++ b/src/dist/replication/lib/replica_throttle.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace dsn { namespace replication { diff --git a/src/dist/replication/meta_server/app_env_validator.cpp b/src/dist/replication/meta_server/app_env_validator.cpp new file mode 100644 index 0000000000..25e7174cfb --- /dev/null +++ b/src/dist/replication/meta_server/app_env_validator.cpp @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Microsoft Corporation + * + * -=- Robust Distributed System Nucleus (rDSN) -=- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "app_env_validator.h" + +namespace dsn { +namespace replication { + +bool validate_app_env(const std::string &env_name, + const std::string &env_value, + std::string &hint_message) +{ + return app_env_validator::instance().validate_app_env(env_name, env_value, hint_message); +} + +bool check_slow_query(const std::string &env_value, std::string &hint_message) +{ + uint64_t threshold = 0; + if (!dsn::buf2uint64(env_value, threshold) || + threshold < replica_envs::MIN_SLOW_QUERY_THRESHOLD_MS) { + hint_message = fmt::format("Slow query threshold must be >= {}ms", + replica_envs::MIN_SLOW_QUERY_THRESHOLD_MS); + return false; + } + return true; +} + +bool check_write_throttling(const std::string &env_value, std::string &hint_message) +{ + std::vector sargs; + utils::split_args(env_value.c_str(), sargs, ','); + if (sargs.empty()) { + hint_message = "The value shouldn't be empty"; + return false; + } + + // example for sarg: 100K*delay*100 / 100M*reject*100 + bool reject_parsed = false; + bool delay_parsed = false; + for (std::string &sarg : sargs) { + std::vector sub_sargs; + utils::split_args(sarg.c_str(), sub_sargs, '*', true); + if (sub_sargs.size() != 3) { + hint_message = fmt::format("The field count of {} should be 3", sarg); + return false; + } + + // check the first part, which is must be a positive number followed with 'K' or 'M' + int64_t units = 0; + if (!sub_sargs[0].empty() && + ('M' == *sub_sargs[0].rbegin() || 'K' == *sub_sargs[0].rbegin())) { + sub_sargs[0].pop_back(); + } + if (!buf2int64(sub_sargs[0], units) || units < 0) { + hint_message = fmt::format("{} should be non-negative int", sub_sargs[0]); + return false; + } + + // check the second part, which is must be "delay" or "reject" + if (sub_sargs[1] == "delay") { + if (delay_parsed) { + hint_message = "duplicate delay config"; + return false; + } + delay_parsed = true; + } else if (sub_sargs[1] == "reject") { + if (reject_parsed) { + hint_message = "duplicate reject config"; + return false; + } + reject_parsed = true; + } else { + hint_message = fmt::format("{} should be \"delay\" or \"reject\"", sub_sargs[1]); + return false; + } + + // check the third part, which is must be a positive number or 0 + int64_t delay_ms = 0; + if (!buf2int64(sub_sargs[2], delay_ms) || delay_ms < 0) { + hint_message = fmt::format("{} should be non-negative int", sub_sargs[2]); + return false; + } + } + + return true; +} + +bool app_env_validator::validate_app_env(const std::string &env_name, + const std::string &env_value, + std::string &hint_message) +{ + auto func_iter = _validator_funcs.find(env_name); + if (func_iter != _validator_funcs.end()) { + // check function == nullptr means no check + if (nullptr != func_iter->second && !func_iter->second(env_value, hint_message)) { + dwarn_f("{}={} is invalid.", env_name, env_value); + return false; + } + + return true; + } + + hint_message = fmt::format("app_env \"{}\" is not supported", env_name); + return false; +} + +void app_env_validator::register_all_validators() +{ + _validator_funcs = { + {replica_envs::SLOW_QUERY_THRESHOLD, + std::bind(&check_slow_query, std::placeholders::_1, std::placeholders::_2)}, + {replica_envs::WRITE_QPS_THROTTLING, + std::bind(&check_write_throttling, std::placeholders::_1, std::placeholders::_2)}, + {replica_envs::WRITE_SIZE_THROTTLING, + std::bind(&check_write_throttling, std::placeholders::_1, std::placeholders::_2)}, + // TODO(zhaoliwei): not implemented + {replica_envs::BUSINESS_INFO, nullptr}, + {replica_envs::DENY_CLIENT_WRITE, nullptr}, + {replica_envs::TABLE_LEVEL_DEFAULT_TTL, nullptr}, + {replica_envs::ROCKSDB_USAGE_SCENARIO, nullptr}, + {replica_envs::ROCKSDB_CHECKPOINT_RESERVE_MIN_COUNT, nullptr}, + {replica_envs::ROCKSDB_CHECKPOINT_RESERVE_TIME_SECONDS, nullptr}, + {replica_envs::MANUAL_COMPACT_DISABLED, nullptr}, + {replica_envs::MANUAL_COMPACT_MAX_CONCURRENT_RUNNING_COUNT, nullptr}, + {replica_envs::MANUAL_COMPACT_ONCE_TRIGGER_TIME, nullptr}, + {replica_envs::MANUAL_COMPACT_ONCE_TARGET_LEVEL, nullptr}, + {replica_envs::MANUAL_COMPACT_ONCE_BOTTOMMOST_LEVEL_COMPACTION, nullptr}, + {replica_envs::MANUAL_COMPACT_PERIODIC_TRIGGER_TIME, nullptr}, + {replica_envs::MANUAL_COMPACT_PERIODIC_TARGET_LEVEL, nullptr}, + {replica_envs::MANUAL_COMPACT_PERIODIC_BOTTOMMOST_LEVEL_COMPACTION, nullptr}}; +} + +} // namespace replication +} // namespace dsn diff --git a/src/dist/replication/meta_server/app_env_validator.h b/src/dist/replication/meta_server/app_env_validator.h new file mode 100644 index 0000000000..110575cd46 --- /dev/null +++ b/src/dist/replication/meta_server/app_env_validator.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Microsoft Corporation + * + * -=- Robust Distributed System Nucleus (rDSN) -=- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include + +namespace dsn { +namespace replication { + +bool validate_app_env(const std::string &env_name, + const std::string &env_value, + std::string &hint_message); + +class app_env_validator : public utils::singleton +{ +public: + app_env_validator() { register_all_validators(); } + bool validate_app_env(const std::string &env_name, + const std::string &env_value, + std::string &hint_message); + +private: + void register_all_validators(); + + using validator_func = std::function; + std::map _validator_funcs; +}; + +} // namespace replication +} // namespace dsn diff --git a/src/dist/replication/meta_server/server_state.cpp b/src/dist/replication/meta_server/server_state.cpp index 27436b9244..1786464b4b 100644 --- a/src/dist/replication/meta_server/server_state.cpp +++ b/src/dist/replication/meta_server/server_state.cpp @@ -46,8 +46,8 @@ #include "server_state.h" #include "server_load_balancer.h" - #include "dump_file.h" +#include "app_env_validator.h" using namespace dsn; @@ -56,10 +56,6 @@ namespace replication { static const char *lock_state = "lock"; static const char *unlock_state = "unlock"; -// env name of slow query -static const std::string ENV_SLOW_QUERY_THRESHOLD("replica.slow_query_threshold"); -// min value for slow query threshold, less than this value will be refused -static const uint64_t MIN_SLOW_QUERY_THRESHOLD_MS = 20; server_state::server_state() : _meta_svc(nullptr), @@ -2627,20 +2623,14 @@ void server_state::set_app_envs(const app_env_rpc &env_rpc) std::ostringstream os; for (int i = 0; i < keys.size(); i++) { - // check whether if slow query threshold is abnormal - if (0 == keys[i].compare(ENV_SLOW_QUERY_THRESHOLD)) { - uint64_t threshold = 0; - if (!dsn::buf2uint64(values[i], threshold) || threshold < MIN_SLOW_QUERY_THRESHOLD_MS) { - dwarn("{}={} is invalid.", keys[i].c_str(), threshold); - env_rpc.response().err = ERR_INVALID_PARAMETERS; - env_rpc.response().hint_message = fmt::format( - "slow query threshold must be >= {}ms", MIN_SLOW_QUERY_THRESHOLD_MS); - return; - } - } - if (i != 0) os << ", "; + + if (!validate_app_env(keys[i], values[i], env_rpc.response().hint_message)) { + env_rpc.response().err = ERR_INVALID_PARAMETERS; + return; + } + os << keys[i] << "=" << values[i]; } ddebug("set app envs for app(%s) from remote(%s): kvs = {%s}", diff --git a/src/dist/replication/test/meta_test/unit_test/meta_app_envs_test.cpp b/src/dist/replication/test/meta_test/unit_test/meta_app_envs_test.cpp index a235f733e3..57f0fe3f59 100644 --- a/src/dist/replication/test/meta_test/unit_test/meta_app_envs_test.cpp +++ b/src/dist/replication/test/meta_test/unit_test/meta_app_envs_test.cpp @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include "meta_test_base.h" namespace dsn { @@ -39,32 +40,123 @@ class meta_app_envs_test : public meta_test_base create_app(app_name); } + void TearDown() override { drop_app(app_name); } + const std::string app_name = "test_app_env"; - const std::string env_slow_query_threshold = "replica.slow_query_threshold"; }; -TEST_F(meta_app_envs_test, set_slow_query_threshold) +TEST_F(meta_app_envs_test, update_app_envs_test) { - auto app = find_app(app_name); - struct test_case { - error_code err; + std::string env_key; std::string env_value; - std::string expect_env_value; - } tests[] = {{ERR_OK, "30", "30"}, - {ERR_OK, "21", "21"}, - {ERR_OK, "20", "20"}, - {ERR_INVALID_PARAMETERS, "19", "20"}, - {ERR_INVALID_PARAMETERS, "10", "20"}, - {ERR_INVALID_PARAMETERS, "0", "20"}}; + error_code err; + std::string hint; + std::string expect_value; + } tests[] = { + {replica_envs::WRITE_QPS_THROTTLING, "100*delay*100", ERR_OK, "", "100*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, "20K*delay*100", ERR_OK, "", "20K*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, "20M*delay*100", ERR_OK, "", "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "20A*delay*100", + ERR_INVALID_PARAMETERS, + "20A should be non-negative int", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "-20*delay*100", + ERR_INVALID_PARAMETERS, + "-20 should be non-negative int", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "", + ERR_INVALID_PARAMETERS, + "The value shouldn't be empty", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "20A*delay", + ERR_INVALID_PARAMETERS, + "The field count of 20A*delay should be 3", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "20K*pass*100", + ERR_INVALID_PARAMETERS, + "pass should be \"delay\" or \"reject\"", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "20K*delay*-100", + ERR_INVALID_PARAMETERS, + "-100 should be non-negative int", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "2K**delay*100", + ERR_INVALID_PARAMETERS, + "The field count of 2K**delay*100 should be 3", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "2K*delay**100", + ERR_INVALID_PARAMETERS, + "The field count of 2K*delay**100 should be 3", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "2K*delay*100,3K*delay*100", + ERR_INVALID_PARAMETERS, + "duplicate delay config", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, + "2K*reject*100,3K*reject*100", + ERR_INVALID_PARAMETERS, + "duplicate reject config", + "20M*delay*100"}, + {replica_envs::WRITE_QPS_THROTTLING, "20M*reject*100", ERR_OK, "", "20M*reject*100"}, + {replica_envs::WRITE_SIZE_THROTTLING, "300*delay*100", ERR_OK, "", "300*delay*100"}, + {replica_envs::SLOW_QUERY_THRESHOLD, "30", ERR_OK, "", "30"}, + {replica_envs::SLOW_QUERY_THRESHOLD, "20", ERR_OK, "", "20"}, + {replica_envs::SLOW_QUERY_THRESHOLD, + "19", + ERR_INVALID_PARAMETERS, + "Slow query threshold must be >= 20ms", + "20"}, + {replica_envs::SLOW_QUERY_THRESHOLD, + "0", + ERR_INVALID_PARAMETERS, + "Slow query threshold must be >= 20ms", + "20"}, + {replica_envs::TABLE_LEVEL_DEFAULT_TTL, "10", ERR_OK, "", "10"}, + {replica_envs::ROCKSDB_USAGE_SCENARIO, "20", ERR_OK, "", "20"}, + {replica_envs::ROCKSDB_CHECKPOINT_RESERVE_MIN_COUNT, "30", ERR_OK, "", "30"}, + {replica_envs::ROCKSDB_CHECKPOINT_RESERVE_TIME_SECONDS, "40", ERR_OK, "", "40"}, + {replica_envs::MANUAL_COMPACT_DISABLED, "50", ERR_OK, "", "50"}, + {replica_envs::MANUAL_COMPACT_MAX_CONCURRENT_RUNNING_COUNT, "60", ERR_OK, "", "60"}, + {replica_envs::MANUAL_COMPACT_ONCE_TRIGGER_TIME, "70", ERR_OK, "", "70"}, + {replica_envs::MANUAL_COMPACT_ONCE_TARGET_LEVEL, "80", ERR_OK, "", "80"}, + {replica_envs::MANUAL_COMPACT_PERIODIC_TRIGGER_TIME, "90", ERR_OK, "", "90"}, + {replica_envs::MANUAL_COMPACT_PERIODIC_TARGET_LEVEL, "100", ERR_OK, "", "100"}, + {replica_envs::MANUAL_COMPACT_PERIODIC_BOTTOMMOST_LEVEL_COMPACTION, + "200", + ERR_OK, + "", + "200"}, + {replica_envs::BUSINESS_INFO, "300", ERR_OK, "", "300"}, + {replica_envs::DENY_CLIENT_WRITE, "400", ERR_OK, "", "400"}, + {"not_exist_env", + "500", + ERR_INVALID_PARAMETERS, + "app_env \"not_exist_env\" is not supported", + ""}}; + auto app = find_app(app_name); for (auto test : tests) { - error_code err = update_app_envs(app_name, {env_slow_query_threshold}, {test.env_value}); + configuration_update_app_env_response response = + update_app_envs(app_name, {test.env_key}, {test.env_value}); - ASSERT_EQ(err, test.err); - ASSERT_EQ(app->envs.at(env_slow_query_threshold), test.expect_env_value); + ASSERT_EQ(response.err, test.err); + ASSERT_EQ(response.hint_message, test.hint); + if (app->envs.find(test.env_key) != app->envs.end()) { + ASSERT_EQ(app->envs.at(test.env_key), test.expect_value); + } } } + } // namespace replication } // namespace dsn diff --git a/src/dist/replication/test/meta_test/unit_test/meta_http_service_test.cpp b/src/dist/replication/test/meta_test/unit_test/meta_http_service_test.cpp index 2c46e9fd3f..d81427d3d8 100644 --- a/src/dist/replication/test/meta_test/unit_test/meta_http_service_test.cpp +++ b/src/dist/replication/test/meta_test/unit_test/meta_http_service_test.cpp @@ -41,8 +41,8 @@ class meta_http_service_test : public meta_test_base void test_get_app_envs() { // set app env - std::string env_key = "test_env"; - std::string env_value = "test_value"; + std::string env_key = "replica.slow_query_threshold"; + std::string env_value = "100"; update_app_envs(test_app, {env_key}, {env_value}); // http get app envs diff --git a/src/dist/replication/test/meta_test/unit_test/meta_test_base.h b/src/dist/replication/test/meta_test/unit_test/meta_test_base.h index 9145fe104d..0fc9ccecc2 100644 --- a/src/dist/replication/test/meta_test/unit_test/meta_test_base.h +++ b/src/dist/replication/test/meta_test/unit_test/meta_test_base.h @@ -103,9 +103,9 @@ class meta_test_base : public testing::Test ASSERT_TRUE(_ss->spin_wait_staging(30)); } - error_code update_app_envs(const std::string &app_name, - const std::vector &env_keys, - const std::vector &env_vals) + configuration_update_app_env_response update_app_envs(const std::string &app_name, + const std::vector &env_keys, + const std::vector &env_vals) { auto req = make_unique(); req->__set_app_name(std::move(app_name)); @@ -116,7 +116,7 @@ class meta_test_base : public testing::Test app_env_rpc rpc(std::move(req), RPC_CM_UPDATE_APP_ENV); // don't need reply _ss->set_app_envs(rpc); _ss->wait_all_task(); - return rpc.response().err; + return rpc.response(); } std::shared_ptr find_app(const std::string &name) { return _ss->get_app(name); } diff --git a/src/dist/replication/test/meta_test/unit_test/server_state_test.cpp b/src/dist/replication/test/meta_test/unit_test/server_state_test.cpp index 8c7f69b892..fedf284804 100644 --- a/src/dist/replication/test/meta_test/unit_test/server_state_test.cpp +++ b/src/dist/replication/test/meta_test/unit_test/server_state_test.cpp @@ -9,15 +9,26 @@ namespace dsn { namespace replication { -static const std::vector keys = { - "p1.k1", "p1.k2", "p1.k3", "p2.k1", "p2.k2", "p2.k3", "p3.k1", "p3.k2", "p3.k3"}; +static const std::vector keys = {"manual_compact.once.trigger_time", + "manual_compact.once.target_level", + "manual_compact.once.bottommost_level_compaction", + "manual_compact.periodic.trigger_time", + "manual_compact.periodic.target_level", + "manual_compact.periodic.bottommost_level_compaction", + "rocksdb.usage_scenario", + "rocksdb.checkpoint.reserve_min_count", + "rocksdb.checkpoint.reserve_time_seconds"}; static const std::vector values = { "p1v1", "p1v2", "p1v3", "p2v1", "p2v2", "p2v3", "p3v1", "p3v2", "p3v3"}; -static const std::vector del_keys = {"p1.k1", "p2.k1", "p3.k1"}; -static const std::set del_keys_set = {"p1.k1", "p2.k1", "p3.k1"}; +static const std::vector del_keys = {"manual_compact.once.trigger_time", + "manual_compact.periodic.trigger_time", + "rocksdb.usage_scenario"}; +static const std::set del_keys_set = {"manual_compact.once.trigger_time", + "manual_compact.periodic.trigger_time", + "rocksdb.usage_scenario"}; -static const std::string clear_prefix = "p1"; +static const std::string clear_prefix = "rocksdb"; // if str = "prefix.xxx" then return prefix // else return ""