Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

Commit

Permalink
feat: add check for app envs (#353)
Browse files Browse the repository at this point in the history
  • Loading branch information
levy5307 authored Feb 4, 2020
1 parent 766edef commit d0dab50
Show file tree
Hide file tree
Showing 12 changed files with 441 additions and 51 deletions.
59 changes: 59 additions & 0 deletions include/dsn/dist/replication/replica_envs.h
Original file line number Diff line number Diff line change
@@ -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 <cstdint>
#include <string>

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
28 changes: 28 additions & 0 deletions src/dist/replication/common/replication_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "replication_common.h"
#include <dsn/utility/filesystem.h>
#include <fstream>
#include <dsn/dist/replication/replica_envs.h>

namespace dsn {
namespace replication {
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 0 additions & 8 deletions src/dist/replication/common/replication_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/dist/replication/lib/replica_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <dsn/dist/fmt_logging.h>
#include <dsn/dist/replication/replication_app_base.h>
#include <dsn/utility/string_conv.h>
#include <dsn/dist/replication/replica_envs.h>

namespace dsn {
namespace replication {
Expand Down
1 change: 1 addition & 0 deletions src/dist/replication/lib/replica_throttle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <dsn/dist/replication/replication_app_base.h>
#include <dsn/dist/fmt_logging.h>
#include <dsn/dist/replication/replica_envs.h>

namespace dsn {
namespace replication {
Expand Down
162 changes: 162 additions & 0 deletions src/dist/replication/meta_server/app_env_validator.cpp
Original file line number Diff line number Diff line change
@@ -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 <dist/replication/common/replication_common.h>
#include <fmt/format.h>
#include <dsn/utility/string_conv.h>
#include <dsn/dist/fmt_logging.h>
#include <dsn/dist/replication/replica_envs.h>
#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<std::string> 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<std::string> 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
54 changes: 54 additions & 0 deletions src/dist/replication/meta_server/app_env_validator.h
Original file line number Diff line number Diff line change
@@ -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 <dsn/utility/singleton.h>

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<app_env_validator>
{
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<bool(const std::string &, std::string &)>;
std::map<const std::string, validator_func> _validator_funcs;
};

} // namespace replication
} // namespace dsn
24 changes: 7 additions & 17 deletions src/dist/replication/meta_server/server_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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),
Expand Down Expand Up @@ -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}",
Expand Down
Loading

0 comments on commit d0dab50

Please sign in to comment.