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

feat: support to modify configs without restart #682

Merged
merged 33 commits into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fee3882
fix
levy5307 Dec 3, 2020
d3a07c0
fix
levy5307 Dec 4, 2020
8df75be
fix
levy5307 Dec 7, 2020
4a3a2c3
fix
levy5307 Dec 7, 2020
6b8f82b
fix
levy5307 Dec 7, 2020
1396ec8
fix
levy5307 Dec 7, 2020
cc93bce
fix
levy5307 Dec 7, 2020
f6e0c2f
Merge branch 'master' into config-update
levy5307 Dec 7, 2020
40c9c8b
fix
levy5307 Dec 7, 2020
84d9fda
Merge branch 'config-update' of github.com:levy5307/rdsn into config-…
levy5307 Dec 7, 2020
02bac72
fix
levy5307 Dec 7, 2020
bfaa2fd
fix
levy5307 Dec 7, 2020
24cec31
fix
levy5307 Dec 7, 2020
1c6cbb6
fix
levy5307 Dec 9, 2020
101b734
fix
levy5307 Dec 9, 2020
406c65a
fix
levy5307 Dec 10, 2020
af2319d
fix
levy5307 Dec 10, 2020
39c015a
fix
levy5307 Dec 15, 2020
e5ab823
fix
levy5307 Dec 15, 2020
d29dcbf
Merge branch 'master' into config-update
acelyc111 Dec 15, 2020
52bfa45
Merge branch 'master' into config-update
levy5307 Dec 16, 2020
f41964d
fix
levy5307 Dec 16, 2020
10b7e93
Merge branch 'master' into config-update
levy5307 Dec 16, 2020
61bb5dc
Merge branch 'master' into config-update
levy5307 Dec 16, 2020
4f3718e
Merge branch 'master' into config-update
levy5307 Dec 16, 2020
3e47c7b
Merge branch 'master' into config-update
levy5307 Dec 17, 2020
e4e3c4e
Merge branch 'master' into config-update
levy5307 Dec 17, 2020
a0af437
Merge branch 'master' into config-update
levy5307 Dec 18, 2020
41d44b4
fix
levy5307 Dec 18, 2020
c87db04
fix
levy5307 Dec 18, 2020
b308b0b
fix
levy5307 Dec 18, 2020
8840fa2
fix
levy5307 Dec 21, 2020
a5fb193
fix
levy5307 Dec 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/dsn/utility/error_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,5 @@ DEFINE_ERR_CODE(ERR_KRB5_INTERNAL)
DEFINE_ERR_CODE(ERR_SASL_INTERNAL)
DEFINE_ERR_CODE(ERR_SASL_INCOMPLETE)
DEFINE_ERR_CODE(ERR_ACL_DENY)
DEFINE_ERR_CODE(ERR_NO_PERMISSION)
} // namespace dsn
58 changes: 42 additions & 16 deletions include/dsn/utility/flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string>
#include <cstdint>
#include <functional>
#include "errors.h"

// Example:
// DSN_DEFINE_string("core", filename, "my_file.txt", "The file to read");
Expand All @@ -23,24 +24,37 @@
#define DSN_DECLARE_bool(name) DSN_DECLARE_VARIABLE(bool, name)
#define DSN_DECLARE_string(name) DSN_DECLARE_VARIABLE(const char *, name)

#define DSN_DEFINE_VARIABLE(type, section, name, default_value, desc) \
#define DSN_DEFINE_VARIABLE(type, section, name, default_value, desc, value_mutable) \
type FLAGS_##name = default_value; \
static dsn::flag_registerer FLAGS_REG_##name(section, #name, desc, &FLAGS_##name)
static dsn::flag_registerer FLAGS_REG_##name(section, #name, desc, &FLAGS_##name, value_mutable)

#define DSN_DEFINE_int32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int32_t, section, name, val, desc)
DSN_DEFINE_VARIABLE(int32_t, section, name, val, desc, false)
#define DSN_DEFINE_uint32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint32_t, section, name, val, desc)
DSN_DEFINE_VARIABLE(uint32_t, section, name, val, desc, false)
#define DSN_DEFINE_int64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int64_t, section, name, val, desc)
DSN_DEFINE_VARIABLE(int64_t, section, name, val, desc, false)
#define DSN_DEFINE_uint64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint64_t, section, name, val, desc)
DSN_DEFINE_VARIABLE(uint64_t, section, name, val, desc, false)
#define DSN_DEFINE_double(section, name, val, desc) \
DSN_DEFINE_VARIABLE(double, section, name, val, desc)
DSN_DEFINE_VARIABLE(double, section, name, val, desc, false)
#define DSN_DEFINE_bool(section, name, val, desc) \
DSN_DEFINE_VARIABLE(bool, section, name, val, desc)
DSN_DEFINE_VARIABLE(bool, section, name, val, desc, false)
#define DSN_DEFINE_string(section, name, val, desc) \
DSN_DEFINE_VARIABLE(const char *, section, name, val, desc)
DSN_DEFINE_VARIABLE(const char *, section, name, val, desc, false)

#define DSN_DEFINE_MUTABLE_int32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int32_t, section, name, val, desc, true)
#define DSN_DEFINE_MUTABLE_uint32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint32_t, section, name, val, desc, true)
#define DSN_DEFINE_MUTABLE_int64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int64_t, section, name, val, desc, true)
#define DSN_DEFINE_MUTABLE_uint64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint64_t, section, name, val, desc, true)
#define DSN_DEFINE_MUTABLE_double(section, name, val, desc) \
DSN_DEFINE_VARIABLE(double, section, name, val, desc, true)
#define DSN_DEFINE_MUTABLE_bool(section, name, val, desc) \
DSN_DEFINE_VARIABLE(bool, section, name, val, desc, true)

// Convenience macro for the registration of a flag validator.
// `validator` must be a std::function<bool(FLAG_TYPE)> and receives the flag value as argument,
Expand All @@ -58,13 +72,23 @@ namespace dsn {
class flag_registerer
{
public:
flag_registerer(const char *section, const char *name, const char *desc, int32_t *val);
flag_registerer(const char *section, const char *name, const char *desc, uint32_t *val);
flag_registerer(const char *section, const char *name, const char *desc, int64_t *val);
flag_registerer(const char *section, const char *name, const char *desc, uint64_t *val);
flag_registerer(const char *section, const char *name, const char *desc, double *val);
flag_registerer(const char *section, const char *name, const char *desc, bool *val);
flag_registerer(const char *section, const char *name, const char *desc, const char **val);
flag_registerer(
const char *section, const char *name, const char *desc, int32_t *val, bool value_mutable);
flag_registerer(
const char *section, const char *name, const char *desc, uint32_t *val, bool value_mutable);
flag_registerer(
const char *section, const char *name, const char *desc, int64_t *val, bool value_mutable);
flag_registerer(
const char *section, const char *name, const char *desc, uint64_t *val, bool value_mutable);
flag_registerer(
const char *section, const char *name, const char *desc, double *val, bool value_mutable);
flag_registerer(
const char *section, const char *name, const char *desc, bool *val, bool value_mutable);
flag_registerer(const char *section,
const char *name,
const char *desc,
const char **val,
bool value_mutable);
};

// An utility class that registers a validator upon initialization.
Expand All @@ -77,4 +101,6 @@ class flag_validator
// Loads all the flags from configuration.
extern void flags_initialize();

extern error_s update_flag(const char *name, const char *val);
levy5307 marked this conversation as resolved.
Show resolved Hide resolved

} // namespace dsn
5 changes: 5 additions & 0 deletions include/dsn/utility/string_conv.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ inline bool buf2int64(string_view buf, int64_t &result)
return internal::buf2signed(buf, result);
}

inline bool buf2uint32(string_view buf, uint32_t &result)
{
return internal::buf2unsigned(buf, result);
}

inline bool buf2uint64(string_view buf, uint64_t &result)
{
return internal::buf2unsigned(buf, result);
Expand Down
5 changes: 5 additions & 0 deletions src/http/builtin_http_calls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ namespace dsn {
get_perf_counter_handler(req, resp);
})
.with_help("Gets the value of a perf counter");

register_http_call("updateConfig")
.with_callback(
[](const http_request &req, http_response &resp) { update_config(req, resp); })
.with_help("Updates the value of a config");
}

} // namespace dsn
2 changes: 2 additions & 0 deletions src/http/builtin_http_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ extern void get_help_handler(const http_request &req, http_response &resp);

extern void get_recent_start_time_handler(const http_request &req, http_response &resp);

extern void update_config(const http_request &req, http_response &resp);

} // namespace dsn
40 changes: 40 additions & 0 deletions src/http/config_http_service.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#include <dsn/http/http_server.h>
#include <dsn/utility/flags.h>
#include <dsn/utility/output_utils.h>

namespace dsn {
void update_config(const http_request &req, http_response &resp)
{
if (req.query_args.size() != 1) {
resp.status_code = http_status_code::bad_request;
return;
}

auto iter = req.query_args.begin();
auto res = update_flag(iter->first.c_str(), iter->second.c_str());

utils::table_printer tp;
tp.add_row_name_and_data("update_status", res.description());
std::ostringstream out;
tp.output(out, dsn::utils::table_printer::output_format::kJsonCompact);
resp.body = out.str();
resp.status_code = http_status_code::ok;
}
} // namespace dsn
68 changes: 64 additions & 4 deletions src/utils/flags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
#include <dsn/utility/flags.h>
#include <dsn/utility/config_api.h>
#include <dsn/utility/singleton.h>
#include <dsn/utility/errors.h>
#include <dsn/utility/string_conv.h>
#include <dsn/c/api_utilities.h>
#include <boost/optional/optional.hpp>
#include <fmt/format.h>

#include <map>

Expand Down Expand Up @@ -37,6 +40,19 @@ class flag_data
} \
break

#define FLAG_DATA_UPDATE_CASE(type, type_enum, suffix) \
case type_enum: \
type tmpval_##type_enum; \
if (!dsn::buf2##suffix(val, tmpval_##type_enum)) { \
return error_s::make(ERR_INVALID_PARAMETERS, fmt::format("{} in invalid", val)); \
} \
value<type>() = tmpval_##type_enum; \
break

#define FLAG_DATA_UPDATE_STRING() \
case FV_STRING: \
return error_s::make(ERR_NO_PERMISSION, "string modifications are not supported")
levy5307 marked this conversation as resolved.
Show resolved Hide resolved

void load()
{
switch (_type) {
Expand All @@ -50,11 +66,39 @@ class flag_data
}
}

flag_data(const char *section, const char *name, const char *desc, value_type type, void *val)
: _type(type), _val(val), _section(section), _name(name), _desc(desc)
flag_data(const char *section,
const char *name,
const char *desc,
value_type type,
void *val,
bool value_mutable)
: _type(type),
_val(val),
_section(section),
_name(name),
_desc(desc),
_value_mutable(value_mutable)
{
}

error_s update(const char *val)
{
if (!_value_mutable) {
return error_s::make(ERR_NO_PERMISSION, fmt::format("{} is not mutable", _name));
}

switch (_type) {
FLAG_DATA_UPDATE_CASE(int32_t, FV_INT32, int32);
FLAG_DATA_UPDATE_CASE(int64_t, FV_INT64, int64);
FLAG_DATA_UPDATE_CASE(uint32_t, FV_UINT32, uint32);
FLAG_DATA_UPDATE_CASE(uint64_t, FV_UINT64, uint64);
FLAG_DATA_UPDATE_CASE(bool, FV_BOOL, bool);
FLAG_DATA_UPDATE_CASE(double, FV_DOUBLE, double);
FLAG_DATA_UPDATE_STRING();
}
return error_s::make(ERR_OK);
}

void set_validator(validator_fn &validator) { _validator = std::move(validator); }
const validator_fn &validator() const { return _validator; }

Expand All @@ -71,6 +115,7 @@ class flag_data
const char *_section;
const char *_name;
const char *_desc;
const bool _value_mutable;
validator_fn _validator;
};

Expand All @@ -79,6 +124,15 @@ class flag_registry : public utils::singleton<flag_registry>
public:
void add_flag(const char *name, flag_data flag) { _flags.emplace(name, flag); }

error_s update_flag(const char *name, const char *val)
{
auto it = _flags.find(name);
if (it == _flags.end()) {
return error_s::make(ERR_OBJECT_NOT_FOUND, fmt::format("{} is not found", name));
}
return it->second.update(val);
}

void add_validator(const char *name, validator_fn &validator)
{
auto it = _flags.find(name);
Expand Down Expand Up @@ -107,9 +161,10 @@ class flag_registry : public utils::singleton<flag_registry>

#define FLAG_REG_CONSTRUCTOR(type, type_enum) \
flag_registerer::flag_registerer( \
const char *section, const char *name, const char *desc, type *val) \
const char *section, const char *name, const char *desc, type *val, bool value_mutable) \
{ \
flag_registry::instance().add_flag(name, flag_data(section, name, desc, type_enum, val)); \
flag_registry::instance().add_flag( \
name, flag_data(section, name, desc, type_enum, val, value_mutable)); \
}

FLAG_REG_CONSTRUCTOR(int32_t, FV_INT32);
Expand All @@ -127,4 +182,9 @@ flag_validator::flag_validator(const char *name, validator_fn validator)

/*extern*/ void flags_initialize() { flag_registry::instance().load_from_config(); }

/*extern*/ error_s update_flag(const char *name, const char *val)
{
return flag_registry::instance().update_flag(name, val);
}

} // namespace dsn
78 changes: 78 additions & 0 deletions src/utils/test/flag_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#include <gtest/gtest.h>
#include <dsn/utility/flags.h>

namespace dsn {
namespace utils {
class flag_test : public testing::Test
{
public:
void SetUp() override { flags_initialize(); }
};

TEST_F(flag_test, update_config)
{
DSN_DEFINE_MUTABLE_int32("flag_test", test_int32, 5, "");
auto res = update_flag("test_int32", "3");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_int32, 3);

DSN_DEFINE_MUTABLE_uint32("flag_test", test_uint32, 5, "");
res = update_flag("test_uint32", "3");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_uint32, 3);

DSN_DEFINE_MUTABLE_int64("flag_test", test_int64, 5, "");
res = update_flag("test_int64", "3");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_int64, 3);

DSN_DEFINE_MUTABLE_uint64("flag_test", test_uint64, 5, "");
res = update_flag("test_uint64", "3");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_uint64, 3);

DSN_DEFINE_MUTABLE_double("flag_test", test_double, 5.0, "");
res = update_flag("test_double", "3.0");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_double, 3.0);

DSN_DEFINE_MUTABLE_bool("flag_test", test_bool, true, "");
res = update_flag("test_bool", "false");
ASSERT_EQ(res.is_ok(), true);
ASSERT_EQ(FLAGS_test_bool, false);

// string modifications are not supported
DSN_DEFINE_string("flag_test", test_string_immutable, "immutable_string", "");
res = update_flag("test_string_immutable", "update_string");
ASSERT_EQ(res.code(), ERR_NO_PERMISSION);
ASSERT_EQ(FLAGS_test_string_immutable, "immutable_string");

// test config is not exist
res = update_flag("test_not_exist", "test_string");
ASSERT_EQ(res.code(), ERR_OBJECT_NOT_FOUND);

// test to update invalid value
DSN_DEFINE_MUTABLE_int32("flag_test", test_int32_invalid, 5, "");
res = update_flag("test_int32_invalid", "3ab");
ASSERT_EQ(res.code(), ERR_INVALID_PARAMETERS);
ASSERT_EQ(FLAGS_test_int32_invalid, 5);
}
} // namespace utils
} // namespace dsn
Loading