diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc index b47b63b79df..9741e825d1d 100644 --- a/src/commands/cmd_server.cc +++ b/src/commands/cmd_server.cc @@ -18,6 +18,9 @@ * */ +#include +#include + #include "command_parser.h" #include "commander.h" #include "commands/scan_base.h" @@ -1123,6 +1126,65 @@ class CommandRdb : public Commander { uint32_t db_index_ = 0; }; +class CommandAnalyze : public Commander { + public: + Status Parse(const std::vector &args) { + if (args.size() <= 1) return {Status::RedisExecErr, errInvalidSyntax}; + for (int i = 1; i < args.size(); ++i) { + true_args_.push_back(args[i]); + } + return Status::OK(); + } + Status Execute(Server *srv, Connection *conn, std::string *output) { + auto commands = redis::CommandTable::Get(); + auto cmd_iter = commands->find(util::ToLower(true_args_[0])); + if (cmd_iter == commands->end()) { + // unsupported redis command + return {Status::RedisExecErr, errInvalidSyntax}; + } + auto redis_cmd = cmd_iter->second; + auto cmd = redis_cmd->factory(); + cmd->SetAttributes(redis_cmd); + cmd->SetArgs(true_args_); + + auto s = cmd->Parse(true_args_); + if (!s.IsOK()) { + return s; + } + + auto prev_perf_level = rocksdb::GetPerfLevel(); + rocksdb::SetPerfLevel(rocksdb::PerfLevel::kEnableTimeExceptForMutex); + rocksdb::get_perf_context()->Reset(); + rocksdb::get_iostats_context()->Reset(); + + std::string command_output; + s = cmd->Execute(srv, conn, &command_output); + if (!s.IsOK()) { + return s; + } + + if (command_output[0] == '-') { + *output = command_output; + return s; + } + + std::string perf_context = rocksdb::get_perf_context()->ToString(true); + std::string iostats_context = rocksdb::get_iostats_context()->ToString(true); + rocksdb::get_perf_context()->Reset(); + rocksdb::get_iostats_context()->Reset(); + rocksdb::SetPerfLevel(prev_perf_level); + + *output = redis::MultiLen(3); // command output + perf context + iostats context + *output += std::move(command_output); + *output += redis::BulkString(perf_context); + *output += redis::BulkString(iostats_context); + return Status::OK(); + } + + private: + std::vector true_args_; +}; + REDIS_REGISTER_COMMANDS(MakeCmdAttr("auth", 2, "read-only ok-loading", 0, 0, 0), MakeCmdAttr("ping", -1, "read-only", 0, 0, 0), MakeCmdAttr("select", 2, "read-only", 0, 0, 0), @@ -1157,6 +1219,7 @@ REDIS_REGISTER_COMMANDS(MakeCmdAttr("auth", 2, "read-only ok-loadin MakeCmdAttr("flushbackup", 1, "read-only no-script", 0, 0, 0), MakeCmdAttr("slaveof", 3, "read-only exclusive no-script", 0, 0, 0), MakeCmdAttr("stats", 1, "read-only", 0, 0, 0), - MakeCmdAttr("rdb", -3, "write exclusive", 0, 0, 0), ) + MakeCmdAttr("rdb", -3, "write exclusive", 0, 0, 0), + MakeCmdAttr("analyze", -1, "", 0, 0, 0), ) } // namespace redis