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

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
levy5307 committed Dec 9, 2020
1 parent 24cec31 commit 1c6cbb6
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 69 deletions.
71 changes: 32 additions & 39 deletions include/dsn/utility/flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include <cstdint>
#include <functional>
#include "errors.h"
#include "utils.h"

enum class flag_tag
{
FT_MUTABLE = 0,
};

// Example:
// DSN_DEFINE_string("core", filename, "my_file.txt", "The file to read");
Expand All @@ -24,37 +30,24 @@
#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, value_mutable) \
#define DSN_DEFINE_VARIABLE(type, section, name, default_value, desc) \
type FLAGS_##name = default_value; \
static dsn::flag_registerer FLAGS_REG_##name(section, #name, desc, &FLAGS_##name, value_mutable)
static dsn::flag_registerer FLAGS_REG_##name(section, #name, desc, &FLAGS_##name)

#define DSN_DEFINE_int32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int32_t, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(int32_t, section, name, val, desc)
#define DSN_DEFINE_uint32(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint32_t, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(uint32_t, section, name, val, desc)
#define DSN_DEFINE_int64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(int64_t, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(int64_t, section, name, val, desc)
#define DSN_DEFINE_uint64(section, name, val, desc) \
DSN_DEFINE_VARIABLE(uint64_t, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(uint64_t, section, name, val, desc)
#define DSN_DEFINE_double(section, name, val, desc) \
DSN_DEFINE_VARIABLE(double, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(double, section, name, val, desc)
#define DSN_DEFINE_bool(section, name, val, desc) \
DSN_DEFINE_VARIABLE(bool, section, name, val, desc, false)
DSN_DEFINE_VARIABLE(bool, section, name, val, desc)
#define DSN_DEFINE_string(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)
DSN_DEFINE_VARIABLE(const char *, section, name, val, desc)

// 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 @@ -66,29 +59,23 @@
dassert(FLAGS_VALIDATOR_FN_##name(FLAGS_##name), "validation failed: %s", #name); \
})

#define DSN_TAG_FLAG(name, tag) \
COMPILE_ASSERT(sizeof(decltype(FLAGS_##name)), exist_##name##_##tag); \
static dsn::flag_tagger FLAGS_TAGGER_##name##_##tag(#name, flag_tag::tag)

namespace dsn {

// An utility class that registers a flag upon initialization.
class flag_registerer
{
public:
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);
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);
};

// An utility class that registers a validator upon initialization.
Expand All @@ -98,6 +85,12 @@ class flag_validator
flag_validator(const char *name, std::function<void()>);
};

class flag_tagger
{
public:
flag_tagger(const char *name, const flag_tag &tag);
};

// Loads all the flags from configuration.
extern void flags_initialize();

Expand Down
24 changes: 22 additions & 2 deletions include/dsn/utility/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@

#define TIME_MS_MAX 0xffffffff

// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
//
// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
// content_type_names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
//
// The second argument to the macro is the name of the variable. If
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.
struct CompileAssert
{
};

#define COMPILE_ASSERT(expr, msg) static const CompileAssert msg[bool(expr) ? 1 : -1]

namespace dsn {
namespace utils {

Expand Down Expand Up @@ -88,5 +108,5 @@ bool hostname(const dsn::rpc_address &address, std::string *hostname_result);
// valid_ip_network_order -> return TRUE && hostname_result=hostname |
// invalid_ip_network_order -> return FALSE
bool hostname_from_ip(uint32_t ip, std::string *hostname_result);
}
}
} // namespace utils
} // namespace dsn
42 changes: 25 additions & 17 deletions src/utils/flags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <fmt/format.h>

#include <map>
#include <dsn/dist/fmt_logging.h>

namespace dsn {

Expand Down Expand Up @@ -66,24 +67,14 @@ class flag_data
}
}

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)
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)
{
}

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

Expand All @@ -102,6 +93,9 @@ class flag_data
void set_validator(validator_fn &validator) { _validator = std::move(validator); }
const validator_fn &validator() const { return _validator; }

bool has_tag(const flag_tag &tag) const { return _tags.find(tag) != _tags.end(); }
bool add_tag(const flag_tag &tag) { return _tags.insert(tag).second; }

private:
template <typename T>
T &value()
Expand All @@ -115,8 +109,8 @@ class flag_data
const char *_section;
const char *_name;
const char *_desc;
const bool _value_mutable;
validator_fn _validator;
std::unordered_set<flag_tag> _tags;
};

class flag_registry : public utils::singleton<flag_registry>
Expand Down Expand Up @@ -151,6 +145,16 @@ class flag_registry : public utils::singleton<flag_registry>
}
}

void add_tag(const char *name, const flag_tag &tag)
{
auto it = _flags.find(name);
dassert(it != _flags.end(), "flag \"%s\" does not exist", name);
if (!it->second.add_tag(tag)) {
// TODO(zlw): enum to string
/// ddebug_f("{} was tagged more than once with the tag {}", name, tag);
}
}

private:
friend class utils::singleton<flag_registry>;
flag_registry() = default;
Expand All @@ -161,10 +165,9 @@ 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, bool value_mutable) \
const char *section, const char *name, const char *desc, type *val) \
{ \
flag_registry::instance().add_flag( \
name, flag_data(section, name, desc, type_enum, val, value_mutable)); \
flag_registry::instance().add_flag(name, flag_data(section, name, desc, type_enum, val)); \
}

FLAG_REG_CONSTRUCTOR(int32_t, FV_INT32);
Expand All @@ -180,6 +183,11 @@ flag_validator::flag_validator(const char *name, validator_fn validator)
flag_registry::instance().add_validator(name, validator);
}

flag_tagger::flag_tagger(const char *name, const flag_tag &tag)
{
flag_registry::instance().add_tag(name, tag);
}

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

/*extern*/ error_s update_flag(const char *name, const char *val)
Expand Down
34 changes: 23 additions & 11 deletions src/utils/test/flag_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,53 +26,65 @@ class flag_test : public testing::Test
void SetUp() override { flags_initialize(); }
};

DSN_DEFINE_int32("flag_test", test_int32, 5, "");
DSN_TAG_FLAG(test_int32, FT_MUTABLE);

DSN_DEFINE_uint32("flag_test", test_uint32, 5, "");
DSN_TAG_FLAG(test_uint32, FT_MUTABLE);

DSN_DEFINE_int64("flag_test", test_int64, 5, "");
DSN_TAG_FLAG(test_int64, FT_MUTABLE);

DSN_DEFINE_uint64("flag_test", test_uint64, 5, "");
DSN_TAG_FLAG(test_uint64, FT_MUTABLE);

DSN_DEFINE_double("flag_test", test_double, 5.0, "");
DSN_TAG_FLAG(test_double, FT_MUTABLE);

DSN_DEFINE_bool("flag_test", test_bool, true, "");
DSN_TAG_FLAG(test_bool, FT_MUTABLE);

DSN_DEFINE_string("flag_test", test_string_immutable, "immutable_string", "");

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");
ASSERT_EQ(strcmp(FLAGS_test_string_immutable, "immutable_string"), 0);

// 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");
res = update_flag("test_int32", "3ab");
ASSERT_EQ(res.code(), ERR_INVALID_PARAMETERS);
ASSERT_EQ(FLAGS_test_int32_invalid, 5);
ASSERT_EQ(FLAGS_test_int32, 3);
}
} // namespace utils
} // namespace dsn

0 comments on commit 1c6cbb6

Please sign in to comment.