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

Commit

Permalink
utils: use flags to define configuration item
Browse files Browse the repository at this point in the history
  • Loading branch information
neverchanje committed Jan 29, 2020
1 parent 766edef commit 068be55
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 68 deletions.
78 changes: 78 additions & 0 deletions include/dsn/utility/flags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#pragma once

#include <string>
#include <cstdint>
#include <functional>

// Example:
// DSN_DEFINE_string("core", filename, "my_file.txt", "The file to read")
// DSN_DEFINE_validator(filename, [](const char *fname){ return is_file(fname); });

#define DSN_DECLARE_VARIABLE(type, name) extern type FLAGS_##name

#define DSN_DECLARE_int32(name) DSN_DECLARE_VARIABLE(int32_t, name)
#define DSN_DECLARE_uint32(name) DSN_DECLARE_VARIABLE(uint32_t, name)
#define DSN_DECLARE_int64(name) DSN_DECLARE_VARIABLE(int64_t, name)
#define DSN_DECLARE_uint64(name) DSN_DECLARE_VARIABLE(uint64_t, name)
#define DSN_DECLARE_double(name) DSN_DECLARE_VARIABLE(double, name)
#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) \
type FLAGS_##name = default_value; \
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)
#define DSN_DEFINE_uint32(section, name, val, desc) \
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)
#define DSN_DEFINE_uint64(section, name, val, desc) \
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)
#define DSN_DEFINE_bool(section, name, val, desc) \
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)

// 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,
// returns true if validation passed.
#define DSN_DEFINE_validator(name, validator) \
static auto FLAGS_VALIDATOR_FN_##name = validator; \
static const dsn::flag_validator FLAGS_VALIDATOR_##name(#name, []() { \
dassert(FLAGS_VALIDATOR_FN_##name(FLAGS_##name), "validation failed: %s", #name); \
})

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);
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.
class flag_validator
{
public:
flag_validator(const char *name, std::function<void()>);
};

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

} // namespace dsn
127 changes: 127 additions & 0 deletions src/core/core/flags.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <dsn/utility/flags.h>
#include <dsn/utility/config_api.h>
#include <dsn/utility/singleton.h>
#include <dsn/c/api_utilities.h>
#include <boost/optional/optional.hpp>

#include <map>

namespace dsn {

enum value_type
{
FV_BOOL = 0,
FV_INT32 = 1,
FV_UINT32 = 2,
FV_INT64 = 3,
FV_UINT64 = 4,
FV_DOUBLE = 5,
FV_STRING = 6,
FV_MAX_INDEX = 6,
};

using validator_fn = std::function<void()>;

class flag_data
{
public:
#define FLAG_DATA_LOAD_CASE(type, type_enum, suffix) \
case type_enum: \
value<type>() = dsn_config_get_value_##suffix(_section, _name, value<type>(), _desc); \
if (_validator) { \
_validator(); \
} \
break

void load()
{
switch (_type) {
FLAG_DATA_LOAD_CASE(int32_t, FV_INT32, int64);
FLAG_DATA_LOAD_CASE(int64_t, FV_INT64, int64);
FLAG_DATA_LOAD_CASE(uint32_t, FV_UINT32, uint64);
FLAG_DATA_LOAD_CASE(uint64_t, FV_UINT64, uint64);
FLAG_DATA_LOAD_CASE(bool, FV_BOOL, bool);
FLAG_DATA_LOAD_CASE(double, FV_DOUBLE, double);
FLAG_DATA_LOAD_CASE(const char *, FV_STRING, string);
}
}

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

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

private:
template <typename T>
T &value()
{
return *reinterpret_cast<T *>(_val);
}

private:
const value_type _type;
void *const _val;
const char *_section;
const char *_name;
const char *_desc;
validator_fn _validator;
};

class flag_registry : public utils::singleton<flag_registry>
{
public:
flag_registry() {}

void add_flag(const char *name, flag_data flag) { _flags.emplace(name, flag); }

void add_validator(const char *name, validator_fn &validator)
{
auto it = _flags.find(name);
dassert(it != _flags.end(), "flag \"%s\" does not exist", name);
flag_data &flag = it->second;
dassert(!flag.validator(), "\"%s\" validator already registered", name);
flag.set_validator(validator);
}

void load_from_config()
{
for (auto &kv : _flags) {
flag_data &flag = kv.second;
flag.load();
}
}

private:
std::map<std::string, flag_data> _flags;
};

#define FLAG_REG_CONSTRUCTOR(type, type_enum) \
flag_registerer::flag_registerer( \
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)); \
}

FLAG_REG_CONSTRUCTOR(int32_t, FV_INT32);
FLAG_REG_CONSTRUCTOR(uint32_t, FV_UINT32);
FLAG_REG_CONSTRUCTOR(int64_t, FV_INT64);
FLAG_REG_CONSTRUCTOR(uint64_t, FV_UINT64);
FLAG_REG_CONSTRUCTOR(bool, FV_BOOL);
FLAG_REG_CONSTRUCTOR(double, FV_DOUBLE);
FLAG_REG_CONSTRUCTOR(const char *, FV_STRING);

flag_validator::flag_validator(const char *name, validator_fn validator)
{
flag_registry::instance().add_validator(name, validator);
}

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

} // namespace dsn
37 changes: 12 additions & 25 deletions src/core/core/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,21 @@
* THE SOFTWARE.
*/

/*
* Description:
* Description:
* What is this file about?
*
* Revision history:
* xxxx-xx-xx, author, first version
* xxxx-xx-xx, author, fix bug about xxx
*/

#include <dsn/service_api_c.h>
#include <dsn/tool-api/command_manager.h>
#include <dsn/tool-api/logging_provider.h>
#include <dsn/tool_api.h>
#include "service_engine.h"
#include <dsn/tool-api/auto_codes.h>
#include <dsn/utility/flags.h>

DSN_API dsn_log_level_t dsn_log_start_level = dsn_log_level_t::LOG_LEVEL_INFORMATION;
DSN_DEFINE_string("core",
logging_start_level,
"LOG_LEVEL_INFORMATION",
"logs with level below this will not be logged");

DSN_DEFINE_bool("core", logging_flush_on_exit, true, "flush log when exit system");

static void log_on_sys_exit(::dsn::sys_exit_type)
{
Expand All @@ -53,20 +50,14 @@ static void log_on_sys_exit(::dsn::sys_exit_type)

void dsn_log_init()
{
dsn_log_start_level = enum_from_string(
dsn_config_get_value_string("core",
"logging_start_level",
enum_to_string(dsn_log_start_level),
"logs with level below this will not be logged"),
dsn_log_level_t::LOG_LEVEL_INVALID);
dsn_log_start_level =
enum_from_string(FLAGS_logging_start_level, dsn_log_level_t::LOG_LEVEL_INVALID);

dassert(dsn_log_start_level != dsn_log_level_t::LOG_LEVEL_INVALID,
"invalid [core] logging_start_level specified");

// register log flush on exit
bool logging_flush_on_exit = dsn_config_get_value_bool(
"core", "logging_flush_on_exit", true, "flush log when exit system");
if (logging_flush_on_exit) {
if (FLAGS_logging_flush_on_exit) {
::dsn::tools::sys_exit.put_back(log_on_sys_exit, "log.flush");
}

Expand All @@ -89,12 +80,8 @@ void dsn_log_init()
[](const std::vector<std::string> &args) {
dsn_log_level_t start_level;
if (args.size() == 0) {
start_level = enum_from_string(
dsn_config_get_value_string("core",
"logging_start_level",
enum_to_string(dsn_log_start_level),
"logs with level below this will not be logged"),
dsn_log_level_t::LOG_LEVEL_INVALID);
start_level =
enum_from_string(FLAGS_logging_start_level, dsn_log_level_t::LOG_LEVEL_INVALID);
} else {
std::string level_str = "LOG_LEVEL_" + args[0];
start_level =
Expand Down
3 changes: 3 additions & 0 deletions src/core/core/service_api_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <dsn/cpp/serialization.h>
#include <dsn/utility/filesystem.h>
#include <dsn/utility/process_utils.h>
#include <dsn/utility/flags.h>
#include <dsn/tool-api/command_manager.h>
#include <fstream>
#ifdef DSN_ENABLE_GPERF
Expand Down Expand Up @@ -318,6 +319,8 @@ bool run(const char *config_file,
return false;
}

dsn::flags_initialize();

// pause when necessary
if (dsn_config_get_value_bool("core",
"pause_on_start",
Expand Down
Loading

0 comments on commit 068be55

Please sign in to comment.