This is an automated email from the ASF dual-hosted git repository.
laiyingchun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus.git
The following commit(s) were added to refs/heads/master by this push:
new af3677e3f feat(logging): Move the logger remote_command handler to
command_manager (#2087)
af3677e3f is described below
commit af3677e3f4f183895e5aa7692b156da7d7c2cef3
Author: Yingchun Lai <[email protected]>
AuthorDate: Wed Aug 7 14:06:06 2024 +0800
feat(logging): Move the logger remote_command handler to command_manager
(#2087)
---
src/utils/command_manager.cpp | 112 ++++++++++++++++++++++--------------------
src/utils/command_manager.h | 20 ++++----
src/utils/logging_provider.h | 3 --
src/utils/simple_logger.cpp | 66 +++++++++++++------------
src/utils/test/logger.cpp | 17 +------
5 files changed, 105 insertions(+), 113 deletions(-)
diff --git a/src/utils/command_manager.cpp b/src/utils/command_manager.cpp
index 35b678b81..b5d56e2af 100644
--- a/src/utils/command_manager.cpp
+++ b/src/utils/command_manager.cpp
@@ -29,13 +29,17 @@
#include <fmt/format.h>
// IWYU pragma: no_include <ext/alloc_traits.h>
#include <stdlib.h>
+#include <algorithm>
#include <chrono>
#include <limits>
#include <sstream> // IWYU pragma: keep
#include <thread>
+#include <type_traits>
#include <unordered_set>
#include <utility>
+#include "gutil/map_util.h"
+
namespace dsn {
std::unique_ptr<command_deregister>
@@ -44,19 +48,19 @@ command_manager::register_command(const
std::vector<std::string> &commands,
const std::string &args,
command_handler handler)
{
- auto *c = new command_instance();
- c->commands = commands;
- c->help = help;
- c->args = args;
- c->handler = std::move(handler);
+ auto ch = std::make_shared<commands_handler>();
+ ch->commands = commands;
+ ch->help = help;
+ ch->args = args;
+ ch->handler = std::move(handler);
utils::auto_write_lock l(_lock);
for (const auto &cmd : commands) {
CHECK(!cmd.empty(), "should not register empty command");
- CHECK(_handlers.emplace(cmd, c).second, "command '{}' already
registered", cmd);
+ gutil::InsertOrDie(&_handler_by_cmd, cmd, ch);
}
- return
std::make_unique<command_deregister>(reinterpret_cast<uintptr_t>(c));
+ return
std::make_unique<command_deregister>(reinterpret_cast<uintptr_t>(ch.get()));
}
std::unique_ptr<command_deregister> command_manager::register_bool_command(
@@ -94,35 +98,39 @@ command_manager::register_multiple_commands(const
std::vector<std::string> &comm
handler);
}
-void command_manager::deregister_command(uintptr_t handle)
+void command_manager::deregister_command(uintptr_t cmd_id)
{
- auto c = reinterpret_cast<command_instance *>(handle);
- CHECK_NOTNULL(c, "cannot deregister a null handle");
+ const auto ch = reinterpret_cast<commands_handler *>(cmd_id);
+ CHECK_NOTNULL(ch, "cannot deregister a null command id");
utils::auto_write_lock l(_lock);
- for (const std::string &cmd : c->commands) {
- _handlers.erase(cmd);
+ for (const auto &cmd : ch->commands) {
+ _handler_by_cmd.erase(cmd);
}
}
+void command_manager::add_global_cmd(std::unique_ptr<command_deregister> cmd)
+{
+ utils::auto_write_lock l(_lock);
+ _cmds.push_back(std::move(cmd));
+}
+
bool command_manager::run_command(const std::string &cmd,
const std::vector<std::string> &args,
/*out*/ std::string &output)
{
- command_instance *h = nullptr;
+ std::shared_ptr<commands_handler> ch;
{
utils::auto_read_lock l(_lock);
- auto it = _handlers.find(cmd);
- if (it != _handlers.end())
- h = it->second;
+ ch = gutil::FindPtrOrNull(_handler_by_cmd, cmd);
}
- if (h == nullptr) {
- output = std::string("unknown command '") + cmd + "'";
+ if (!ch) {
+ output = fmt::format("unknown command '{}'", cmd);
return false;
- } else {
- output = h->handler(args);
- return true;
}
+
+ output = ch->handler(args);
+ return true;
}
std::string command_manager::set_bool(bool &value,
@@ -159,36 +167,34 @@ std::string command_manager::set_bool(bool &value,
command_manager::command_manager()
{
- _cmds.emplace_back(
- register_multiple_commands({"help", "h", "H", "Help"},
- "Display help information",
- "[command]",
- [this](const std::vector<std::string>
&args) {
- std::stringstream ss;
- if (args.empty()) {
- std::unordered_set<command_instance
*> cmds;
- utils::auto_read_lock l(_lock);
- for (const auto &c :
this->_handlers) {
- // Multiple commands with the
same handler are print
- // only once.
- if
(cmds.insert(c.second.get()).second) {
- ss << c.second->help <<
std::endl;
- }
- }
- } else {
- utils::auto_read_lock l(_lock);
- auto it = _handlers.find(args[0]);
- if (it == _handlers.end()) {
- ss << "cannot find command '"
<< args[0] << "'";
- } else {
- ss.width(6);
- ss << std::left <<
it->second->help << std::endl
- << it->second->args <<
std::endl;
- }
- }
-
- return ss.str();
- }));
+ _cmds.emplace_back(register_multiple_commands(
+ {"help", "h", "H", "Help"},
+ "Display help information",
+ "[command]",
+ [this](const std::vector<std::string> &args) {
+ std::stringstream ss;
+ if (args.empty()) {
+ std::unordered_set<commands_handler *> chs;
+ utils::auto_read_lock l(_lock);
+ for (const auto &[_, ch] : _handler_by_cmd) {
+ // Multiple commands with the same handler are print only
once.
+ if (gutil::InsertIfNotPresent(&chs, ch.get())) {
+ ss << ch->help << std::endl;
+ }
+ }
+ } else {
+ utils::auto_read_lock l(_lock);
+ const auto ch = gutil::FindPtrOrNull(_handler_by_cmd, args[0]);
+ if (!ch) {
+ ss << "cannot find command '" << args[0] << "'";
+ } else {
+ ss.width(6);
+ ss << std::left << ch->help << std::endl << ch->args <<
std::endl;
+ }
+ }
+
+ return ss.str();
+ }));
_cmds.emplace_back(register_multiple_commands(
{"repeat", "r", "R", "Repeat"},
@@ -241,10 +247,10 @@ command_manager::command_manager()
command_manager::~command_manager()
{
_cmds.clear();
- CHECK(_handlers.empty(),
+ CHECK(_handler_by_cmd.empty(),
"All commands must be deregistered before command_manager is
destroyed, however '{}' is "
"still registered",
- _handlers.begin()->first);
+ _handler_by_cmd.begin()->first);
}
} // namespace dsn
diff --git a/src/utils/command_manager.h b/src/utils/command_manager.h
index 0a34dd4c1..b971522d0 100644
--- a/src/utils/command_manager.h
+++ b/src/utils/command_manager.h
@@ -28,17 +28,16 @@
#include <fmt/core.h>
#include <fmt/format.h>
+#include <nlohmann/json.hpp>
+#include <nlohmann/json_fwd.hpp>
// IWYU pragma: no_include <ext/alloc_traits.h>
#include <stdint.h>
#include <functional>
#include <map>
#include <memory>
-#include <nlohmann/json.hpp>
-#include <nlohmann/json_fwd.hpp>
#include <string>
#include <vector>
-#include "utils/autoref_ptr.h"
#include "utils/fmt_logging.h"
#include "utils/ports.h"
#include "utils/singleton.h"
@@ -47,7 +46,6 @@
#include "utils/synchronize.h"
namespace dsn {
-
class command_deregister;
class command_manager : public ::dsn::utils::singleton<command_manager>
@@ -85,7 +83,7 @@ public:
});
}
- // Register a single 'command' with the 'help' description, its arguments
are describe in
+ // Register a single 'command' with the 'help' description, its arguments
are described in
// 'args'.
std::unique_ptr<command_deregister>
register_single_command(const std::string &command,
@@ -93,7 +91,7 @@ public:
const std::string &args,
command_handler handler) WARN_UNUSED_RESULT;
- // Register multiple 'commands' with the 'help' description, their
arguments are describe in
+ // Register multiple 'commands' with the 'help' description, their
arguments are described in
// 'args'.
std::unique_ptr<command_deregister>
register_multiple_commands(const std::vector<std::string> &commands,
@@ -101,6 +99,9 @@ public:
const std::string &args,
command_handler handler) WARN_UNUSED_RESULT;
+ // Register a global command which is not associated with any objects.
+ void add_global_cmd(std::unique_ptr<command_deregister> cmd);
+
bool run_command(const std::string &cmd,
const std::vector<std::string> &args,
/*out*/ std::string &output);
@@ -112,7 +113,7 @@ private:
command_manager();
~command_manager();
- struct command_instance : public ref_counter
+ struct commands_handler
{
std::vector<std::string> commands;
std::string help;
@@ -126,7 +127,7 @@ private:
const std::string &args,
command_handler handler) WARN_UNUSED_RESULT;
- void deregister_command(uintptr_t handle);
+ void deregister_command(uintptr_t cmd_id);
static std::string
set_bool(bool &value, const std::string &name, const
std::vector<std::string> &args);
@@ -177,9 +178,8 @@ private:
return msg.dump(2);
}
- typedef ref_ptr<command_instance> command_instance_ptr;
utils::rw_lock_nr _lock;
- std::map<std::string, command_instance_ptr> _handlers;
+ std::map<std::string, std::shared_ptr<commands_handler>> _handler_by_cmd;
std::vector<std::unique_ptr<command_deregister>> _cmds;
};
diff --git a/src/utils/logging_provider.h b/src/utils/logging_provider.h
index ec6bec53d..264d721ce 100644
--- a/src/utils/logging_provider.h
+++ b/src/utils/logging_provider.h
@@ -64,8 +64,6 @@ public:
virtual void flush() = 0;
- void deregister_commands() { _cmds.clear(); }
-
protected:
static std::unique_ptr<logging_provider> _logger;
@@ -73,7 +71,6 @@ protected:
logging_provider(log_level_t stderr_start_level) :
_stderr_start_level(stderr_start_level) {}
- std::vector<std::unique_ptr<command_deregister>> _cmds;
const log_level_t _stderr_start_level;
};
diff --git a/src/utils/simple_logger.cpp b/src/utils/simple_logger.cpp
index 6e56cbbca..f67132408 100644
--- a/src/utils/simple_logger.cpp
+++ b/src/utils/simple_logger.cpp
@@ -36,7 +36,7 @@
#include <cstdint>
#include <ctime>
#include <functional>
-#include <memory>
+#include <mutex>
#include <type_traits>
#include <utility>
#include <vector>
@@ -234,37 +234,39 @@ simple_logger::simple_logger(const char *log_dir, const
char *role_name)
create_log_file();
- // TODO(yingchun): simple_logger is destroyed after command_manager, so
will cause crash like
- // "assertion expression: [_handlers.empty()] All commands must be
deregistered before
- // command_manager is destroyed, however 'flush-log' is still registered".
- // We need to fix it.
-
_cmds.emplace_back(::dsn::command_manager::instance().register_single_command(
- "flush-log",
- "Flush log to stderr or file",
- "",
- [this](const std::vector<std::string> &args) {
- this->flush();
- return "Flush done.";
- }));
-
-
_cmds.emplace_back(::dsn::command_manager::instance().register_single_command(
- "reset-log-start-level",
- "Reset the log start level",
- "[DEBUG | INFO | WARNING | ERROR | FATAL]",
- [](const std::vector<std::string> &args) {
- log_level_t start_level;
- if (args.size() == 0) {
- start_level = enum_from_string(FLAGS_logging_start_level,
LOG_LEVEL_INVALID);
- } else {
- std::string level_str = "LOG_LEVEL_" + args[0];
- start_level = enum_from_string(level_str.c_str(),
LOG_LEVEL_INVALID);
- if (start_level == LOG_LEVEL_INVALID) {
- return "ERROR: invalid level '" + args[0] + "'";
- }
- }
- set_log_start_level(start_level);
- return std::string("OK, current level is ") +
enum_to_string(start_level);
- }));
+ static std::once_flag flag;
+ std::call_once(flag, [&]() {
+ ::dsn::command_manager::instance().add_global_cmd(
+ ::dsn::command_manager::instance().register_single_command(
+ "flush-log",
+ "Flush log to stderr or file",
+ "",
+ [this](const std::vector<std::string> &args) {
+ this->flush();
+ return "Flush done.";
+ }));
+
+ ::dsn::command_manager::instance().add_global_cmd(
+ ::dsn::command_manager::instance().register_single_command(
+ "reset-log-start-level",
+ "Reset the log start level",
+ "[DEBUG | INFO | WARNING | ERROR | FATAL]",
+ [](const std::vector<std::string> &args) {
+ log_level_t start_level;
+ if (args.size() == 0) {
+ start_level =
+ enum_from_string(FLAGS_logging_start_level,
LOG_LEVEL_INVALID);
+ } else {
+ std::string level_str = "LOG_LEVEL_" + args[0];
+ start_level = enum_from_string(level_str.c_str(),
LOG_LEVEL_INVALID);
+ if (start_level == LOG_LEVEL_INVALID) {
+ return "ERROR: invalid level '" + args[0] + "'";
+ }
+ }
+ set_log_start_level(start_level);
+ return std::string("OK, current level is ") +
enum_to_string(start_level);
+ }));
+ });
}
void simple_logger::create_log_file()
diff --git a/src/utils/test/logger.cpp b/src/utils/test/logger.cpp
index e60e8fe5d..a06d85ef1 100644
--- a/src/utils/test/logger.cpp
+++ b/src/utils/test/logger.cpp
@@ -38,7 +38,6 @@
#include "utils/api_utilities.h"
#include "utils/filesystem.h"
#include "utils/flags.h"
-#include "utils/logging_provider.h"
#include "utils/simple_logger.h"
#include "utils/test_macros.h"
@@ -51,23 +50,11 @@ class logger_test : public testing::Test
public:
void SetUp() override
{
- // Deregister commands to avoid re-register error.
- dsn::logging_provider::instance()->deregister_commands();
- }
-};
-
-class simple_logger_test : public logger_test
-{
-public:
- void SetUp() override
- {
- logger_test::SetUp();
-
std::string cwd;
ASSERT_TRUE(dsn::utils::filesystem::get_current_directory(cwd));
// NOTE: Don't name the dir with "test", otherwise the whole utils
test dir would be
// removed.
- test_dir = dsn::utils::filesystem::path_combine(cwd,
"simple_logger_test");
+ test_dir = dsn::utils::filesystem::path_combine(cwd, "logger_test");
NO_FATALS(prepare_test_dir());
std::set<std::string> files;
@@ -154,7 +141,7 @@ TEST_F(logger_test, screen_logger_test)
logger->flush();
}
-TEST_F(simple_logger_test, redundant_log_test)
+TEST_F(logger_test, redundant_log_test)
{
// Create redundant log files to test if their number could be restricted.
for (unsigned int i = 0; i < FLAGS_max_number_of_log_files_on_disk + 10;
++i) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]