This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 5055f570 chore(server): return InfoEntries instead of string in
Get..Info() (#2778)
5055f570 is described below
commit 5055f570a3d2653f884a71afe4a2d0115a8dd903
Author: Twice <[email protected]>
AuthorDate: Sun Feb 9 10:54:39 2025 +0800
chore(server): return InfoEntries instead of string in Get..Info() (#2778)
---
src/commands/cmd_server.cc | 4 +-
src/common/string_util.h | 5 +
src/server/server.cc | 382 ++++++++++++++++++++++-----------------------
src/server/server.h | 39 +++--
4 files changed, 220 insertions(+), 210 deletions(-)
diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc
index a91c1e13..49197f58 100644
--- a/src/commands/cmd_server.cc
+++ b/src/commands/cmd_server.cc
@@ -237,7 +237,7 @@ class CommandInfo : public Commander {
Status Execute([[maybe_unused]] engine::Context &ctx, Server *srv,
Connection *conn, std::string *output) override {
std::vector<std::string> sections;
for (size_t i = 1; i < args_.size(); ++i) {
- sections.push_back(util::ToLower(args_[i]));
+ sections.push_back(args_[i]);
}
auto info = srv->GetInfo(conn->GetNamespace(), sections);
*output = conn->VerbatimString("txt", info);
@@ -282,7 +282,7 @@ class CommandRole : public Commander {
public:
Status Execute([[maybe_unused]] engine::Context &ctx, Server *srv,
[[maybe_unused]] Connection *conn,
std::string *output) override {
- srv->GetRoleInfo(output);
+ *output = srv->GetRoleInfo();
return Status::OK();
}
};
diff --git a/src/common/string_util.h b/src/common/string_util.h
index b8d57ef7..fe66be5a 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -42,6 +42,11 @@ std::vector<std::string> Split(std::string_view in,
std::string_view delim);
std::vector<std::string> Split2KV(const std::string &in, const std::string
&delim);
bool HasPrefix(const std::string &str, const std::string &prefix);
+template <typename Iter>
+Iter FindICase(Iter begin, Iter end, std::string_view expected) {
+ return std::find_if(begin, end, [expected](const auto &v) { return
EqualICase(v, expected); });
+}
+
Status ValidateGlob(std::string_view glob);
bool StringMatch(std::string_view glob, std::string_view str, bool ignore_case
= false);
std::pair<std::string, std::string> SplitGlob(std::string_view glob);
diff --git a/src/server/server.cc b/src/server/server.cc
index 653e3c6e..9f21b04c 100644
--- a/src/server/server.cc
+++ b/src/server/server.cc
@@ -853,10 +853,10 @@ void Server::cron() {
}
}
-std::string Server::GetRocksDBInfo() {
- if (is_loading_) return "";
+Server::InfoEntries Server::GetRocksDBInfo() {
+ InfoEntries entries;
+ if (is_loading_) return entries;
- std::ostringstream string_stream;
rocksdb::DB *db = storage->GetDB();
uint64_t memtable_sizes = 0, cur_memtable_sizes = 0, num_snapshots = 0,
num_running_flushes = 0;
@@ -872,18 +872,15 @@ std::string Server::GetRocksDBInfo() {
db->GetAggregatedIntProperty("rocksdb.compaction-pending",
&compaction_pending);
db->GetAggregatedIntProperty("rocksdb.num-live-versions",
&num_live_versions);
- string_stream << "# RocksDB\r\n";
-
{
// All column families share the same block cache, so it's good to count a
single one.
uint64_t block_cache_usage = 0;
uint64_t block_cache_pinned_usage = 0;
auto subkey_cf_handle =
storage->GetCFHandle(ColumnFamilyID::PrimarySubkey);
db->GetIntProperty(subkey_cf_handle,
rocksdb::DB::Properties::kBlockCacheUsage, &block_cache_usage);
- string_stream << "block_cache_usage:" << block_cache_usage << "\r\n";
+ entries.emplace_back("block_cache_usage", block_cache_usage);
db->GetIntProperty(subkey_cf_handle,
rocksdb::DB::Properties::kBlockCachePinnedUsage, &block_cache_pinned_usage);
- string_stream << "block_cache_pinned_usage[" <<
subkey_cf_handle->GetName() << "]:" << block_cache_pinned_usage
- << "\r\n";
+ entries.emplace_back("block_cache_pinned_usage[" +
subkey_cf_handle->GetName() + "]", block_cache_pinned_usage);
// All column faimilies share the same property of the DB, so it's good to
count a single one.
db->GetIntProperty(subkey_cf_handle,
rocksdb::DB::Properties::kNumSnapshots, &num_snapshots);
@@ -896,27 +893,26 @@ std::string Server::GetRocksDBInfo() {
uint64_t index_and_filter_cache_usage = 0;
std::map<std::string, std::string> cf_stats_map;
db->GetIntProperty(cf_handle, rocksdb::DB::Properties::kEstimateNumKeys,
&estimate_keys);
- string_stream << "estimate_keys[" << cf_handle->GetName() << "]:" <<
estimate_keys << "\r\n";
+ entries.emplace_back("estimate_keys[" + cf_handle->GetName() + "]",
estimate_keys);
db->GetIntProperty(cf_handle,
rocksdb::DB::Properties::kEstimateTableReadersMem,
&index_and_filter_cache_usage);
- string_stream << "index_and_filter_cache_usage[" << cf_handle->GetName()
<< "]:" << index_and_filter_cache_usage
- << "\r\n";
+ entries.emplace_back("index_and_filter_cache_usage[" +
cf_handle->GetName() + "]", index_and_filter_cache_usage);
db->GetMapProperty(cf_handle, rocksdb::DB::Properties::kCFStats,
&cf_stats_map);
- string_stream << "level0_file_limit_slowdown[" << cf_handle->GetName()
- << "]:" << cf_stats_map["l0-file-count-limit-delays"] <<
"\r\n";
- string_stream << "level0_file_limit_stop[" << cf_handle->GetName()
- << "]:" << cf_stats_map["l0-file-count-limit-stops"] <<
"\r\n";
- string_stream << "pending_compaction_bytes_slowdown[" <<
cf_handle->GetName()
- << "]:" << cf_stats_map["pending-compaction-bytes-delays"]
<< "\r\n";
- string_stream << "pending_compaction_bytes_stop[" << cf_handle->GetName()
- << "]:" << cf_stats_map["pending-compaction-bytes-stops"] <<
"\r\n";
- string_stream << "level0_file_limit_stop_with_ongoing_compaction[" <<
cf_handle->GetName()
- << "]:" <<
cf_stats_map["cf-l0-file-count-limit-stops-with-ongoing-compaction"] << "\r\n";
- string_stream << "level0_file_limit_slowdown_with_ongoing_compaction[" <<
cf_handle->GetName()
- << "]:" <<
cf_stats_map["cf-l0-file-count-limit-delays-with-ongoing-compaction"] << "\r\n";
- string_stream << "memtable_count_limit_slowdown[" << cf_handle->GetName()
- << "]:" << cf_stats_map["memtable-limit-delays"] << "\r\n";
- string_stream << "memtable_count_limit_stop[" << cf_handle->GetName()
- << "]:" << cf_stats_map["memtable-limit-stops"] << "\r\n";
+ entries.emplace_back("level0_file_limit_slowdown[" + cf_handle->GetName()
+ "]",
+ cf_stats_map["l0-file-count-limit-delays"]);
+ entries.emplace_back("level0_file_limit_stop[" + cf_handle->GetName() +
"]",
+ cf_stats_map["l0-file-count-limit-stops"]);
+ entries.emplace_back("pending_compaction_bytes_slowdown[" +
cf_handle->GetName() + "]",
+ cf_stats_map["pending-compaction-bytes-delays"]);
+ entries.emplace_back("pending_compaction_bytes_stop[" +
cf_handle->GetName() + "]",
+ cf_stats_map["pending-compaction-bytes-stops"]);
+ entries.emplace_back("level0_file_limit_stop_with_ongoing_compaction[" +
cf_handle->GetName() + "]",
+
cf_stats_map["cf-l0-file-count-limit-stops-with-ongoing-compaction"]);
+ entries.emplace_back("level0_file_limit_slowdown_with_ongoing_compaction["
+ cf_handle->GetName() + "]",
+
cf_stats_map["cf-l0-file-count-limit-delays-with-ongoing-compaction"]);
+ entries.emplace_back("memtable_count_limit_slowdown[" +
cf_handle->GetName() + "]",
+ cf_stats_map["memtable-limit-delays"]);
+ entries.emplace_back("memtable_count_limit_stop[" + cf_handle->GetName() +
"]",
+ cf_stats_map["memtable-limit-stops"]);
}
auto rocksdb_stats = storage->GetDB()->GetDBOptions().statistics;
@@ -932,41 +928,39 @@ std::string Server::GetRocksDBInfo() {
{"block_cache_data_miss", rocksdb::Tickers::BLOCK_CACHE_DATA_MISS},
};
for (const auto &iter : block_cache_stats) {
- string_stream << iter.first << ":" <<
rocksdb_stats->getTickerCount(iter.second) << "\r\n";
+ entries.emplace_back(iter.first,
rocksdb_stats->getTickerCount(iter.second));
}
}
- string_stream << "all_mem_tables:" << memtable_sizes << "\r\n";
- string_stream << "cur_mem_tables:" << cur_memtable_sizes << "\r\n";
- string_stream << "snapshots:" << num_snapshots << "\r\n";
- string_stream << "num_immutable_tables:" << num_immutable_tables << "\r\n";
- string_stream << "num_running_flushes:" << num_running_flushes << "\r\n";
- string_stream << "memtable_flush_pending:" << memtable_flush_pending <<
"\r\n";
- string_stream << "compaction_pending:" << compaction_pending << "\r\n";
- string_stream << "num_running_compactions:" << num_running_compaction <<
"\r\n";
- string_stream << "num_live_versions:" << num_live_versions << "\r\n";
- string_stream << "num_super_version:" << num_super_version << "\r\n";
- string_stream << "num_background_errors:" << num_background_errors << "\r\n";
+ entries.emplace_back("all_mem_tables", memtable_sizes);
+ entries.emplace_back("cur_mem_tables", cur_memtable_sizes);
+ entries.emplace_back("snapshots", num_snapshots);
+ entries.emplace_back("num_immutable_tables", num_immutable_tables);
+ entries.emplace_back("num_running_flushes", num_running_flushes);
+ entries.emplace_back("memtable_flush_pending", memtable_flush_pending);
+ entries.emplace_back("compaction_pending", compaction_pending);
+ entries.emplace_back("num_running_compactions", num_running_compaction);
+ entries.emplace_back("num_live_versions", num_live_versions);
+ entries.emplace_back("num_super_version", num_super_version);
+ entries.emplace_back("num_background_errors", num_background_errors);
auto db_stats = storage->GetDBStats();
- string_stream << "flush_count:" << db_stats->flush_count << "\r\n";
- string_stream << "compaction_count:" << db_stats->compaction_count << "\r\n";
- string_stream << "put_per_sec:" <<
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_PUT) << "\r\n";
- string_stream << "get_per_sec:"
- << stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_GET) +
-
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_MULTIGET)
- << "\r\n";
- string_stream << "seek_per_sec:" <<
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_SEEK) << "\r\n";
- string_stream << "next_per_sec:" <<
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_NEXT) << "\r\n";
- string_stream << "prev_per_sec:" <<
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_PREV) << "\r\n";
+ entries.emplace_back("flush_count", db_stats->flush_count.load());
+ entries.emplace_back("compaction_count", db_stats->compaction_count.load());
+ entries.emplace_back("put_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_PUT));
+ entries.emplace_back("get_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_GET) +
+
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_MULTIGET));
+ entries.emplace_back("seek_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_SEEK));
+ entries.emplace_back("next_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_NEXT));
+ entries.emplace_back("prev_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_ROCKSDB_PREV));
db_job_mu_.lock();
- string_stream << "is_bgsaving:" << (is_bgsave_in_progress_ ? "yes" : "no")
<< "\r\n";
- string_stream << "is_compacting:" << (db_compacting_ ? "yes" : "no") <<
"\r\n";
+ entries.emplace_back("is_bgsaving", (is_bgsave_in_progress_ ? "yes" : "no"));
+ entries.emplace_back("is_compacting", (db_compacting_ ? "yes" : "no"));
db_job_mu_.unlock();
- return string_stream.str();
+ return entries;
}
-std::string Server::GetServerInfo() {
+Server::InfoEntries Server::GetServerInfo() {
static int call_uname = 1;
static utsname name;
if (call_uname) {
@@ -975,43 +969,41 @@ std::string Server::GetServerInfo() {
call_uname = 0;
}
- std::ostringstream string_stream;
- string_stream << "# Server\r\n";
- string_stream << "version:" << VERSION << "\r\n";
- string_stream << "kvrocks_version:" << VERSION << "\r\n";
- string_stream << "redis_version:" << REDIS_VERSION << "\r\n";
- string_stream << "git_sha1:" << GIT_COMMIT << "\r\n";
- string_stream << "kvrocks_git_sha1:" << GIT_COMMIT << "\r\n";
- string_stream << "redis_mode:" << (config_->cluster_enabled ? "cluster" :
"standalone") << "\r\n";
- string_stream << "kvrocks_mode:" << (config_->cluster_enabled ? "cluster" :
"standalone") << "\r\n";
- string_stream << "os:" << name.sysname << " " << name.release << " " <<
name.machine << "\r\n";
-#ifdef __GNUC__
- string_stream << "gcc_version:" << __GNUC__ << "." << __GNUC_MINOR__ << "."
<< __GNUC_PATCHLEVEL__ << "\r\n";
+ Server::InfoEntries entries;
+ entries.emplace_back("version", VERSION);
+ entries.emplace_back("kvrocks_version", VERSION);
+ entries.emplace_back("redis_version", REDIS_VERSION);
+ entries.emplace_back("git_sha1", GIT_COMMIT);
+ entries.emplace_back("kvrocks_git_sha1", GIT_COMMIT);
+ entries.emplace_back("redis_mode", (config_->cluster_enabled ? "cluster" :
"standalone"));
+ entries.emplace_back("kvrocks_mode", (config_->cluster_enabled ? "cluster" :
"standalone"));
+ entries.emplace_back("os", fmt::format("{} {} {}", name.sysname,
name.release, name.machine));
+#if defined(__GNUC__) && !defined(__clang__)
+ entries.emplace_back("gcc_version", fmt::format("{}.{}.{}", __GNUC__,
__GNUC_MINOR__, __GNUC_PATCHLEVEL__));
#endif
#ifdef __clang__
- string_stream << "clang_version:" << __clang_major__ << "." <<
__clang_minor__ << "." << __clang_patchlevel__
- << "\r\n";
+ entries.emplace_back("clang_version",
+ fmt::format("{}.{}.{}", __clang_major__,
__clang_minor__, __clang_patchlevel__));
#endif
- string_stream << "arch_bits:" << sizeof(void *) * 8 << "\r\n";
- string_stream << "process_id:" << getpid() << "\r\n";
- string_stream << "tcp_port:" << config_->port << "\r\n";
+ entries.emplace_back("arch_bits", sizeof(void *) * 8);
+ entries.emplace_back("process_id", getpid());
+ entries.emplace_back("tcp_port", config_->port);
int64_t now_secs = util::GetTimeStamp<std::chrono::seconds>();
- string_stream << "uptime_in_seconds:" << now_secs - start_time_secs_ <<
"\r\n";
- string_stream << "uptime_in_days:" << (now_secs - start_time_secs_) / 86400
<< "\r\n";
- return string_stream.str();
+ entries.emplace_back("uptime_in_seconds", now_secs - start_time_secs_);
+ entries.emplace_back("uptime_in_days", (now_secs - start_time_secs_) /
86400);
+ return entries;
}
-std::string Server::GetClientsInfo() {
- std::ostringstream string_stream;
- string_stream << "# Clients\r\n";
- string_stream << "maxclients:" << config_->maxclients << "\r\n";
- string_stream << "connected_clients:" << connected_clients_ << "\r\n";
- string_stream << "monitor_clients:" << monitor_clients_ << "\r\n";
- string_stream << "blocked_clients:" << blocked_clients_ << "\r\n";
- return string_stream.str();
+Server::InfoEntries Server::GetClientsInfo() {
+ InfoEntries entries;
+ entries.emplace_back("maxclients", config_->maxclients);
+ entries.emplace_back("connected_clients", connected_clients_.load());
+ entries.emplace_back("monitor_clients", monitor_clients_.load());
+ entries.emplace_back("blocked_clients", blocked_clients_.load());
+ return entries;
}
-std::string Server::GetMemoryInfo() {
+Server::InfoEntries Server::GetMemoryInfo() {
int64_t rss = Stats::GetMemoryRSS();
int64_t memory_lua = 0;
for (auto &wt : worker_threads_) {
@@ -1020,57 +1012,55 @@ std::string Server::GetMemoryInfo() {
std::string used_memory_rss_human = util::BytesToHuman(rss);
std::string used_memory_lua_human = util::BytesToHuman(memory_lua);
- std::ostringstream string_stream;
- string_stream << "# Memory\r\n";
- string_stream << "used_memory_rss:" << rss << "\r\n";
- string_stream << "used_memory_rss_human:" << used_memory_rss_human << "\r\n";
- string_stream << "used_memory_lua:" << memory_lua << "\r\n";
- string_stream << "used_memory_lua_human:" << used_memory_lua_human << "\r\n";
- string_stream << "used_memory_startup:" <<
memory_startup_use_.load(std::memory_order_relaxed) << "\r\n";
- return string_stream.str();
+ InfoEntries entries;
+ entries.emplace_back("used_memory_rss", rss);
+ entries.emplace_back("used_memory_rss_human", used_memory_rss_human);
+ entries.emplace_back("used_memory_lua", memory_lua);
+ entries.emplace_back("used_memory_lua_human", used_memory_lua_human);
+ entries.emplace_back("used_memory_startup",
memory_startup_use_.load(std::memory_order_relaxed));
+ return entries;
}
-std::string Server::GetReplicationInfo() {
- if (is_loading_) return "";
+Server::InfoEntries Server::GetReplicationInfo() {
+ InfoEntries entries;
+ if (is_loading_) return entries;
- std::ostringstream string_stream;
- string_stream << "# Replication\r\n";
- string_stream << "role:" << (IsSlave() ? "slave" : "master") << "\r\n";
+ entries.emplace_back("role", (IsSlave() ? "slave" : "master"));
if (IsSlave()) {
int64_t now_secs = util::GetTimeStamp<std::chrono::seconds>();
- string_stream << "master_host:" << master_host_ << "\r\n";
- string_stream << "master_port:" << master_port_ << "\r\n";
+ entries.emplace_back("master_host", master_host_);
+ entries.emplace_back("master_port", master_port_);
ReplState state = GetReplicationState();
- string_stream << "master_link_status:" << (state == kReplConnected ? "up"
: "down") << "\r\n";
- string_stream << "master_sync_unrecoverable_error:" << (state ==
kReplError ? "yes" : "no") << "\r\n";
- string_stream << "master_sync_in_progress:" << (state == kReplFetchMeta ||
state == kReplFetchSST) << "\r\n";
- string_stream << "master_last_io_seconds_ago:" << now_secs -
replication_thread_->LastIOTimeSecs() << "\r\n";
- string_stream << "slave_repl_offset:" << storage->LatestSeqNumber() <<
"\r\n";
- string_stream << "slave_priority:" << config_->slave_priority << "\r\n";
+ entries.emplace_back("master_link_status", (state == kReplConnected ? "up"
: "down"));
+ entries.emplace_back("master_sync_unrecoverable_error", (state ==
kReplError ? "yes" : "no"));
+ entries.emplace_back("master_sync_in_progress", (state == kReplFetchMeta
|| state == kReplFetchSST));
+ entries.emplace_back("master_last_io_seconds_ago", now_secs -
replication_thread_->LastIOTimeSecs());
+ entries.emplace_back("slave_repl_offset", storage->LatestSeqNumber());
+ entries.emplace_back("slave_priority", config_->slave_priority);
}
int idx = 0;
rocksdb::SequenceNumber latest_seq = storage->LatestSeqNumber();
slave_threads_mu_.lock();
- string_stream << "connected_slaves:" << slave_threads_.size() << "\r\n";
+ entries.emplace_back("connected_slaves", slave_threads_.size());
for (const auto &slave : slave_threads_) {
if (slave->IsStopped()) continue;
- string_stream << "slave" << std::to_string(idx) << ":";
- string_stream << "ip=" << slave->GetConn()->GetAnnounceIP() << ",port=" <<
slave->GetConn()->GetAnnouncePort()
- << ",offset=" << slave->GetCurrentReplSeq() << ",lag=" <<
latest_seq - slave->GetCurrentReplSeq()
- << "\r\n";
+ entries.emplace_back("slave" + std::to_string(idx),
+ fmt::format("ip={},port={},offset={},lag={}",
slave->GetConn()->GetAnnounceIP(),
+ slave->GetConn()->GetAnnouncePort(),
slave->GetCurrentReplSeq(),
+ latest_seq - slave->GetCurrentReplSeq()));
++idx;
}
slave_threads_mu_.unlock();
- string_stream << "master_repl_offset:" << latest_seq << "\r\n";
+ entries.emplace_back("master_repl_offset", latest_seq);
- return string_stream.str();
+ return entries;
}
-void Server::GetRoleInfo(std::string *info) {
+std::string Server::GetRoleInfo() {
if (IsSlave()) {
std::vector<std::string> roles;
roles.emplace_back("slave");
@@ -1086,7 +1076,7 @@ void Server::GetRoleInfo(std::string *info) {
roles.emplace_back("connecting");
}
roles.emplace_back(std::to_string(storage->LatestSeqNumber()));
- *info = redis::ArrayOfBulkStrings(roles);
+ return redis::ArrayOfBulkStrings(roles);
} else {
std::vector<std::string> list;
@@ -1106,12 +1096,14 @@ void Server::GetRoleInfo(std::string *info) {
if (list.size() > 0) {
multi_len = 3;
}
- info->append(redis::MultiLen(multi_len));
- info->append(redis::BulkString("master"));
-
info->append(redis::BulkString(std::to_string(storage->LatestSeqNumber())));
+ std::string info;
+ info.append(redis::MultiLen(multi_len));
+ info.append(redis::BulkString("master"));
+ info.append(redis::BulkString(std::to_string(storage->LatestSeqNumber())));
if (list.size() > 0) {
- info->append(redis::Array(list));
+ info.append(redis::Array(list));
}
+ return info;
}
}
@@ -1139,46 +1131,45 @@ int64_t Server::GetLastBgsaveTime() {
return last_bgsave_timestamp_secs_ == -1 ? start_time_secs_ :
last_bgsave_timestamp_secs_;
}
-std::string Server::GetStatsInfo() {
- std::ostringstream string_stream;
- string_stream << "# Stats\r\n";
- string_stream << "total_connections_received:" << total_clients_ << "\r\n";
- string_stream << "total_commands_processed:" << stats.total_calls << "\r\n";
- string_stream << "instantaneous_ops_per_sec:" <<
stats.GetInstantaneousMetric(STATS_METRIC_COMMAND) << "\r\n";
- string_stream << "total_net_input_bytes:" << stats.in_bytes << "\r\n";
- string_stream << "total_net_output_bytes:" << stats.out_bytes << "\r\n";
- string_stream << "instantaneous_input_kbps:"
- <<
static_cast<float>(stats.GetInstantaneousMetric(STATS_METRIC_NET_INPUT) / 1024)
<< "\r\n";
- string_stream << "instantaneous_output_kbps:"
- <<
static_cast<float>(stats.GetInstantaneousMetric(STATS_METRIC_NET_OUTPUT) /
1024) << "\r\n";
- string_stream << "sync_full:" << stats.fullsync_count << "\r\n";
- string_stream << "sync_partial_ok:" << stats.psync_ok_count << "\r\n";
- string_stream << "sync_partial_err:" << stats.psync_err_count << "\r\n";
+Server::InfoEntries Server::GetStatsInfo() {
+ Server::InfoEntries entries;
+ entries.emplace_back("total_connections_received", total_clients_.load());
+ entries.emplace_back("total_commands_processed", stats.total_calls.load());
+ entries.emplace_back("instantaneous_ops_per_sec",
stats.GetInstantaneousMetric(STATS_METRIC_COMMAND));
+ entries.emplace_back("total_net_input_bytes", stats.in_bytes.load());
+ entries.emplace_back("total_net_output_bytes", stats.out_bytes.load());
+ entries.emplace_back("instantaneous_input_kbps",
+
static_cast<float>(stats.GetInstantaneousMetric(STATS_METRIC_NET_INPUT) /
1024));
+ entries.emplace_back("instantaneous_output_kbps",
+
static_cast<float>(stats.GetInstantaneousMetric(STATS_METRIC_NET_OUTPUT) /
1024));
+ entries.emplace_back("sync_full", stats.fullsync_count.load());
+ entries.emplace_back("sync_partial_ok", stats.psync_ok_count.load());
+ entries.emplace_back("sync_partial_err", stats.psync_err_count.load());
auto db_stats = storage->GetDBStats();
- string_stream << "keyspace_hits:" << db_stats->keyspace_hits << "\r\n";
- string_stream << "keyspace_misses:" << db_stats->keyspace_misses << "\r\n";
+ entries.emplace_back("keyspace_hits", db_stats->keyspace_hits.load());
+ entries.emplace_back("keyspace_misses", db_stats->keyspace_misses.load());
{
std::lock_guard<std::mutex> lg(pubsub_channels_mu_);
- string_stream << "pubsub_channels:" << pubsub_channels_.size() << "\r\n";
- string_stream << "pubsub_patterns:" << pubsub_patterns_.size() << "\r\n";
+ entries.emplace_back("pubsub_channels", pubsub_channels_.size());
+ entries.emplace_back("pubsub_patterns", pubsub_patterns_.size());
}
- return string_stream.str();
+ return entries;
}
-std::string Server::GetCommandsStatsInfo() {
- std::ostringstream string_stream;
- string_stream << "# Commandstats\r\n";
+Server::InfoEntries Server::GetCommandsStatsInfo() {
+ InfoEntries entries;
for (const auto &cmd_stat : stats.commands_stats) {
auto calls = cmd_stat.second.calls.load();
if (calls == 0) continue;
auto latency = cmd_stat.second.latency.load();
- string_stream << "cmdstat_" << cmd_stat.first << ":calls=" << calls <<
",usec=" << latency
- << ",usec_per_call=" << static_cast<float>(latency / calls)
<< "\r\n";
+ entries.emplace_back("cmdstat_" + cmd_stat.first,
+ fmt::format("calls={},usec={},usec_per_call={}",
calls, latency,
+ static_cast<double>(latency) /
static_cast<double>(calls)));
}
for (const auto &cmd_hist : stats.commands_histogram) {
@@ -1187,7 +1178,7 @@ std::string Server::GetCommandsStatsInfo() {
if (calls == 0) continue;
auto sum = stats.commands_histogram[command_name].sum.load();
- string_stream << "cmdstathist_" << command_name << ":";
+ std::string result;
for (std::size_t i{0}; i <
stats.commands_histogram[command_name].buckets.size(); ++i) {
auto bucket_value =
stats.commands_histogram[command_name].buckets[i]->load();
auto bucket_bound = std::numeric_limits<double>::infinity();
@@ -1195,87 +1186,82 @@ std::string Server::GetCommandsStatsInfo() {
bucket_bound = stats.bucket_boundaries[i];
}
- string_stream << bucket_bound << "=" << bucket_value << ",";
+ result.append(fmt::format("{}={},", bucket_bound, bucket_value));
}
- string_stream << "sum=" << sum << ",count=" << calls << "\r\n";
+ result.append(fmt::format("sum={},count={}", sum, calls));
+
+ entries.emplace_back("cmdstathist_" + command_name, result);
}
- return string_stream.str();
+ return entries;
}
-std::string Server::GetClusterInfo() {
- std::ostringstream string_stream;
+Server::InfoEntries Server::GetClusterInfo() {
+ InfoEntries entries;
- string_stream << "# Cluster\r\n";
- string_stream << "cluster_enabled:" << config_->cluster_enabled << "\r\n";
+ entries.emplace_back("cluster_enabled", config_->cluster_enabled);
- return string_stream.str();
+ return entries;
}
-std::string Server::GetPersistenceInfo() {
- std::ostringstream string_stream;
+Server::InfoEntries Server::GetPersistenceInfo() {
+ InfoEntries entries;
- string_stream << "# Persistence\r\n";
- string_stream << "loading:" << is_loading_ << "\r\n";
+ entries.emplace_back("loading", is_loading_.load());
std::lock_guard<std::mutex> lg(db_job_mu_);
- string_stream << "bgsave_in_progress:" << (is_bgsave_in_progress_ ? 1 : 0)
<< "\r\n";
- string_stream << "last_bgsave_time:"
- << (last_bgsave_timestamp_secs_ == -1 ? start_time_secs_ :
last_bgsave_timestamp_secs_) << "\r\n";
- string_stream << "last_bgsave_status:" << last_bgsave_status_ << "\r\n";
- string_stream << "last_bgsave_time_sec:" << last_bgsave_duration_secs_ <<
"\r\n";
+ entries.emplace_back("bgsave_in_progress", is_bgsave_in_progress_);
+ entries.emplace_back("last_bgsave_time",
+ (last_bgsave_timestamp_secs_ == -1 ? start_time_secs_ :
last_bgsave_timestamp_secs_));
+ entries.emplace_back("last_bgsave_status", last_bgsave_status_);
+ entries.emplace_back("last_bgsave_time_sec", last_bgsave_duration_secs_);
- return string_stream.str();
+ return entries;
}
-std::string Server::GetCpuInfo() { //
NOLINT(readability-convert-member-functions-to-static)
- std::ostringstream string_stream;
+Server::InfoEntries Server::GetCpuInfo() { //
NOLINT(readability-convert-member-functions-to-static)
+ InfoEntries entries;
rusage self_ru;
getrusage(RUSAGE_SELF, &self_ru);
- string_stream << "# CPU\r\n";
- string_stream << "used_cpu_sys:"
- << static_cast<float>(self_ru.ru_stime.tv_sec) +
static_cast<float>(self_ru.ru_stime.tv_usec / 1000000)
- << "\r\n";
- string_stream << "used_cpu_user:"
- << static_cast<float>(self_ru.ru_utime.tv_sec) +
static_cast<float>(self_ru.ru_utime.tv_usec / 1000000)
- << "\r\n";
+ entries.emplace_back("used_cpu_sys",
static_cast<float>(self_ru.ru_stime.tv_sec) +
+
static_cast<float>(self_ru.ru_stime.tv_usec / 1000000));
+ entries.emplace_back("used_cpu_user",
static_cast<float>(self_ru.ru_utime.tv_sec) +
+
static_cast<float>(self_ru.ru_utime.tv_usec / 1000000));
- return string_stream.str();
+ return entries;
}
-std::string Server::GetKeyspaceInfo(const std::string &ns) {
- if (is_loading_) return "";
-
- std::ostringstream string_stream;
+Server::InfoEntries Server::GetKeyspaceInfo(const std::string &ns) {
+ InfoEntries entries;
+ if (is_loading_) return entries;
KeyNumStats stats;
GetLatestKeyNumStats(ns, &stats);
auto last_dbsize_scan_timestamp = static_cast<time_t>(GetLastScanTime(ns));
- string_stream << "# Keyspace\r\n";
- string_stream << "last_dbsize_scan_timestamp:" << last_dbsize_scan_timestamp
<< "\r\n";
- string_stream << "db0:keys=" << stats.n_key << ",expires=" <<
stats.n_expires << ",avg_ttl=" << stats.avg_ttl
- << ",expired=" << stats.n_expired << "\r\n";
- string_stream << "sequence:" << storage->GetDB()->GetLatestSequenceNumber()
<< "\r\n";
- string_stream << "used_db_size:" << storage->GetTotalSize(ns) << "\r\n";
- string_stream << "max_db_size:" << config_->max_db_size * GiB << "\r\n";
+ entries.emplace_back("last_dbsize_scan_timestamp",
last_dbsize_scan_timestamp);
+ entries.emplace_back("db0",
fmt::format("keys={},expires={},avg_ttl={},expired={}", stats.n_key,
stats.n_expires,
+ stats.avg_ttl, stats.n_expired));
+ entries.emplace_back("sequence",
storage->GetDB()->GetLatestSequenceNumber());
+ entries.emplace_back("used_db_size", storage->GetTotalSize(ns));
+ entries.emplace_back("max_db_size", config_->max_db_size * GiB);
double used_percent = config_->max_db_size ?
static_cast<double>(storage->GetTotalSize() * 100) /
static_cast<double>(config_->max_db_size * GiB)
: 0;
- string_stream << "used_percent: " << used_percent << "%\r\n";
+ entries.emplace_back("used_percent", fmt::format("{}%", used_percent));
struct statvfs stat;
if (statvfs(config_->db_dir.c_str(), &stat) == 0) {
auto disk_capacity = stat.f_blocks * stat.f_frsize;
auto used_disk_size = (stat.f_blocks - stat.f_bavail) * stat.f_frsize;
- string_stream << "disk_capacity:" << disk_capacity << "\r\n";
- string_stream << "used_disk_size:" << used_disk_size << "\r\n";
+ entries.emplace_back("disk_capacity", disk_capacity);
+ entries.emplace_back("used_disk_size", used_disk_size);
double used_disk_percent = static_cast<double>(used_disk_size * 100) /
static_cast<double>(disk_capacity);
- string_stream << "used_disk_percent: " << used_disk_percent << "%\r\n";
+ entries.emplace_back("used_disk_percent", fmt::format("{}%",
used_disk_percent));
}
- return string_stream.str();
+ return entries;
}
// WARNING: we must not access DB(i.e. RocksDB) when server is loading since
@@ -1283,28 +1269,32 @@ std::string Server::GetKeyspaceInfo(const std::string
&ns) {
// If you add new fields which access DB into INFO command output, make sure
// this section can't be shown when loading(i.e. !is_loading_).
std::string Server::GetInfo(const std::string &ns, const
std::vector<std::string> §ions) {
- std::vector<std::pair<std::string, std::function<std::string(Server *)>>>
info_funcs = {
- {"server", &Server::GetServerInfo}, {"clients",
&Server::GetClientsInfo},
- {"memory", &Server::GetMemoryInfo}, {"persistence",
&Server::GetPersistenceInfo},
- {"stats", &Server::GetStatsInfo}, {"replication",
&Server::GetReplicationInfo},
- {"cpu", &Server::GetCpuInfo}, {"commandstats",
&Server::GetCommandsStatsInfo},
- {"cluster", &Server::GetClusterInfo}, {"keyspace", [&ns](Server *srv) {
return srv->GetKeyspaceInfo(ns); }},
- {"rocksdb", &Server::GetRocksDBInfo},
+ std::vector<std::pair<std::string, std::function<InfoEntries(Server *)>>>
info_funcs = {
+ {"Server", &Server::GetServerInfo}, {"Clients",
&Server::GetClientsInfo},
+ {"Memory", &Server::GetMemoryInfo}, {"Persistence",
&Server::GetPersistenceInfo},
+ {"Stats", &Server::GetStatsInfo}, {"Replication",
&Server::GetReplicationInfo},
+ {"CPU", &Server::GetCpuInfo}, {"CommandStats",
&Server::GetCommandsStatsInfo},
+ {"Cluster", &Server::GetClusterInfo}, {"Keyspace", [&ns](Server *srv) {
return srv->GetKeyspaceInfo(ns); }},
+ {"RocksDB", &Server::GetRocksDBInfo},
};
std::string info_str;
- bool all = sections.empty() || std::find(sections.begin(), sections.end(),
"all") != sections.end();
+ bool all = sections.empty() || util::FindICase(sections.begin(),
sections.end(), "all") != sections.end();
bool first = true;
for (const auto &[sec, fn] : info_funcs) {
- if (all || std::find(sections.begin(), sections.end(), sec) !=
sections.end()) {
+ if (all || util::FindICase(sections.begin(), sections.end(), sec) !=
sections.end()) {
if (first)
first = false;
else
info_str.append("\r\n");
- info_str.append(fn(this));
+ info_str.append("# " + sec + "\r\n");
+
+ for (const auto &entry : fn(this)) {
+ info_str.append(fmt::format("{}:{}\r\n", entry.name, entry.val));
+ }
}
}
diff --git a/src/server/server.h b/src/server/server.h
index e5365066..b8c31429 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -33,6 +33,7 @@
#include <set>
#include <shared_mutex>
#include <string>
+#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -232,18 +233,32 @@ class Server {
static int64_t GetCachedUnixTime();
int64_t GetLastBgsaveTime();
- void GetRoleInfo(std::string *info);
- std::string GetStatsInfo();
- std::string GetServerInfo();
- std::string GetMemoryInfo();
- std::string GetRocksDBInfo();
- std::string GetClientsInfo();
- std::string GetReplicationInfo();
- std::string GetCommandsStatsInfo();
- std::string GetClusterInfo();
- std::string GetPersistenceInfo();
- std::string GetCpuInfo();
- std::string GetKeyspaceInfo(const std::string &ns);
+ std::string GetRoleInfo();
+
+ struct InfoEntry {
+ std::string name;
+ std::string val;
+
+ InfoEntry(std::string name, std::string val) : name(std::move(name)),
val(std::move(val)) {}
+ InfoEntry(std::string name, std::string_view val) : name(std::move(name)),
val(val.begin(), val.end()) {}
+ InfoEntry(std::string name, const char *val) : name(std::move(name)),
val(val) {}
+ template <typename T, std::enable_if_t<std::is_integral_v<T> ||
std::is_floating_point_v<T>, int> = 0>
+ InfoEntry(std::string name, T v) : name(std::move(name)),
val(std::to_string(v)) {}
+ };
+ using InfoEntries = std::vector<InfoEntry>;
+
+ InfoEntries GetStatsInfo();
+ InfoEntries GetServerInfo();
+ InfoEntries GetMemoryInfo();
+ InfoEntries GetRocksDBInfo();
+ InfoEntries GetClientsInfo();
+ InfoEntries GetReplicationInfo();
+ InfoEntries GetCommandsStatsInfo();
+ InfoEntries GetClusterInfo();
+ InfoEntries GetPersistenceInfo();
+ InfoEntries GetCpuInfo();
+ InfoEntries GetKeyspaceInfo(const std::string &ns);
+
std::string GetInfo(const std::string &ns, const std::vector<std::string>
§ions);
std::string GetRocksDBStatsJson() const;
ReplState GetReplicationState();