Skip to content

Commit 68310cb

Browse files
authored
refactor: extract and encapsulate the aggregation process of single-table statistics for reuse (#2318)
Both shell and HTTP interfaces now support displaying a table's statistics in multiple sections. Since the logic for this was largely duplicated, a lot of redundant code existed. This PR extracts the common logic and introduces an `add_app_info` interface to encapsulate it, allowing a table’s statistics to be added to a `multi_printer` in multiple sections for later output. Additionally, a `resolve` interface is introduced for `host_port` itself, replacing `replication_ddl_client::node_name`.
1 parent e56cccb commit 68310cb

10 files changed

Lines changed: 256 additions & 254 deletions

src/client/replication_ddl_client.cpp

Lines changed: 19 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#include <fstream>
3636
#include <iomanip>
3737
#include <iostream>
38-
#include <type_traits>
3938

4039
#include "backup_types.h"
4140
#include "common//duplication_common.h"
@@ -531,15 +530,6 @@ struct list_nodes_helper
531530
}
532531
};
533532

534-
std::string replication_ddl_client::node_name(const host_port &hp, bool resolve_ip)
535-
{
536-
if (!resolve_ip) {
537-
return hp.to_string();
538-
}
539-
540-
return dns_resolver::instance().resolve_address(hp).to_string();
541-
}
542-
543533
dsn::error_code replication_ddl_client::cluster_name(int64_t timeout_ms, std::string &cluster_name)
544534
{
545535
auto req = std::make_shared<configuration_cluster_info_request>();
@@ -614,123 +604,35 @@ replication_ddl_client::cluster_info(const std::string &file_name, bool resolve_
614604
dsn::error_code replication_ddl_client::list_app(const std::string &app_name,
615605
bool detailed,
616606
bool json,
617-
const std::string &file_name,
607+
const std::string &output_file,
618608
bool resolve_ip)
619609
{
620-
dsn::utils::multi_table_printer mtp;
621-
dsn::utils::table_printer tp_params("parameters");
622-
if (!(app_name.empty() && file_name.empty())) {
623-
if (!app_name.empty())
624-
tp_params.add_row_name_and_data("app_name", app_name);
625-
if (!file_name.empty())
626-
tp_params.add_row_name_and_data("out_file", file_name);
627-
}
628-
tp_params.add_row_name_and_data("detailed", detailed);
629-
mtp.add(std::move(tp_params));
630-
int32_t app_id = 0;
631-
int32_t partition_count = 0;
632-
int32_t max_replica_count = 0;
610+
utils::table_printer params_printer("parameters");
611+
if (!app_name.empty()) {
612+
params_printer.add_row_name_and_data("app_name", app_name);
613+
}
614+
if (!output_file.empty()) {
615+
params_printer.add_row_name_and_data("out_file", output_file);
616+
}
617+
618+
params_printer.add_row_name_and_data("detailed", detailed);
619+
620+
utils::multi_table_printer multi_printer;
621+
multi_printer.add(std::move(params_printer));
622+
623+
int32_t app_id{0};
624+
int32_t partition_count{0};
633625
std::vector<partition_configuration> pcs;
634-
dsn::error_code err = list_app(app_name, app_id, partition_count, pcs);
626+
const auto err = list_app(app_name, app_id, partition_count, pcs);
635627
if (err != dsn::ERR_OK) {
636628
return err;
637629
}
638-
if (!pcs.empty()) {
639-
max_replica_count = pcs[0].max_replica_count;
640-
}
641630

642-
// print query_cfg_response
643-
std::streambuf *buf;
644-
std::ofstream of;
631+
add_app_info(app_name, app_id, partition_count, pcs, detailed, resolve_ip, "", multi_printer);
645632

646-
if (!file_name.empty()) {
647-
of.open(file_name);
648-
buf = of.rdbuf();
649-
} else {
650-
buf = std::cout.rdbuf();
651-
}
652-
std::ostream out(buf);
633+
utils::output(output_file, json, multi_printer);
653634

654-
dsn::utils::table_printer tp_general("general");
655-
tp_general.add_row_name_and_data("app_name", app_name);
656-
tp_general.add_row_name_and_data("app_id", app_id);
657-
tp_general.add_row_name_and_data("partition_count", partition_count);
658-
tp_general.add_row_name_and_data("max_replica_count", max_replica_count);
659-
mtp.add(std::move(tp_general));
660-
661-
if (detailed) {
662-
dsn::utils::table_printer tp_details("replicas");
663-
tp_details.add_title("pidx");
664-
tp_details.add_column("ballot");
665-
tp_details.add_column("replica_count");
666-
tp_details.add_column("primary");
667-
tp_details.add_column("secondaries");
668-
std::map<host_port, std::pair<int, int>> node_stat;
669-
670-
int total_prim_count = 0;
671-
int total_sec_count = 0;
672-
int fully_healthy = 0;
673-
int write_unhealthy = 0;
674-
int read_unhealthy = 0;
675-
for (const auto &pc : pcs) {
676-
int replica_count = 0;
677-
if (pc.hp_primary) {
678-
replica_count++;
679-
node_stat[pc.hp_primary].first++;
680-
total_prim_count++;
681-
}
682-
replica_count += pc.hp_secondaries.size();
683-
total_sec_count += pc.hp_secondaries.size();
684-
if (pc.hp_primary) {
685-
if (replica_count >= pc.max_replica_count) {
686-
fully_healthy++;
687-
} else if (replica_count < 2) {
688-
write_unhealthy++;
689-
}
690-
} else {
691-
write_unhealthy++;
692-
read_unhealthy++;
693-
}
694-
for (const auto &secondary : pc.hp_secondaries) {
695-
node_stat[secondary].second++;
696-
}
697-
tp_details.add_row(pc.pid.get_partition_index());
698-
tp_details.append_data(pc.ballot);
699-
tp_details.append_data(fmt::format("{}/{}", replica_count, pc.max_replica_count));
700-
tp_details.append_data(pc.hp_primary ? pc.hp_primary.to_string() : "-");
701-
tp_details.append_data(fmt::format("[{}]", fmt::join(pc.hp_secondaries, ",")));
702-
}
703-
mtp.add(std::move(tp_details));
704-
705-
// 'node' section.
706-
dsn::utils::table_printer tp_nodes("nodes");
707-
tp_nodes.add_title("node");
708-
tp_nodes.add_column("primary");
709-
tp_nodes.add_column("secondary");
710-
tp_nodes.add_column("total");
711-
for (const auto &[hp, pri_and_sec_rep_cnts] : node_stat) {
712-
tp_nodes.add_row(node_name(hp, resolve_ip));
713-
tp_nodes.append_data(pri_and_sec_rep_cnts.first);
714-
tp_nodes.append_data(pri_and_sec_rep_cnts.second);
715-
tp_nodes.append_data(pri_and_sec_rep_cnts.first + pri_and_sec_rep_cnts.second);
716-
}
717-
tp_nodes.add_row("");
718-
tp_nodes.append_data(total_prim_count);
719-
tp_nodes.append_data(total_sec_count);
720-
tp_nodes.append_data(total_prim_count + total_sec_count);
721-
mtp.add(std::move(tp_nodes));
722-
723-
// healthy partition count section.
724-
dsn::utils::table_printer tp_hpc("healthy");
725-
tp_hpc.add_row_name_and_data("fully_healthy_partition_count", fully_healthy);
726-
tp_hpc.add_row_name_and_data("unhealthy_partition_count", partition_count - fully_healthy);
727-
tp_hpc.add_row_name_and_data("write_unhealthy_partition_count", write_unhealthy);
728-
tp_hpc.add_row_name_and_data("read_unhealthy_partition_count", read_unhealthy);
729-
mtp.add(std::move(tp_hpc));
730-
}
731-
mtp.output(out, json ? tp_output_format::kJsonPretty : tp_output_format::kTabular);
732635
return dsn::ERR_OK;
733-
#undef RESOLVE
734636
}
735637

736638
dsn::error_code replication_ddl_client::list_app(const std::string &app_name,

src/client/replication_ddl_client.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ class replication_ddl_client
156156
dsn::error_code list_app(const std::string &app_name,
157157
bool detailed,
158158
bool json,
159-
const std::string &file_name,
160-
bool resolve_ip = false);
159+
const std::string &output_file,
160+
bool resolve_ip);
161161

162162
dsn::error_code list_app(const std::string &app_name,
163163
int32_t &app_id,
@@ -317,10 +317,12 @@ class replication_ddl_client
317317
void set_max_wait_app_ready_secs(uint32_t max_wait_secs) { _max_wait_secs = max_wait_secs; }
318318
void set_meta_servers_leader();
319319

320-
static error_s validate_app_name(const std::string &app_name, bool allow_empty_name = false);
320+
static error_s validate_app_name(const std::string &app_name, bool allow_empty_name);
321321

322-
// Resolve the host:port 'hp' to ip:port if 'resolve_ip' is true.
323-
static std::string node_name(const host_port &hp, bool resolve_ip);
322+
static error_s validate_app_name(const std::string &app_name)
323+
{
324+
return validate_app_name(app_name, false);
325+
}
324326

325327
private:
326328
void end_meta_request(const rpc_response_task_ptr &callback,
@@ -528,7 +530,6 @@ class replication_ddl_client
528530
}
529531
}
530532

531-
private:
532533
dsn::host_port _meta_server;
533534
dsn::task_tracker _tracker;
534535
uint32_t _max_wait_secs = 3600; // Wait at most 1 hour by default.

src/common/replication_common.cpp

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,26 @@
2626

2727
#include "common/replication_common.h"
2828

29-
#include <string.h>
29+
#include <cstring>
3030
#include <fstream>
31+
#include <map>
3132
#include <memory>
33+
#include <type_traits>
34+
#include <utility>
3235

3336
#include "common/gpid.h"
3437
#include "common/replication_other_types.h"
3538
#include "dsn.layer2_types.h"
3639
#include "fmt/core.h"
40+
#include "fmt/format.h"
3741
#include "rpc/dns_resolver.h" // IWYU pragma: keep
3842
#include "rpc/rpc_address.h"
3943
#include "runtime/service_app.h"
4044
#include "utils/config_api.h"
4145
#include "utils/filesystem.h"
4246
#include "utils/flags.h"
4347
#include "utils/fmt_logging.h"
48+
#include "utils/output_utils.h"
4449
#include "utils/strings.h"
4550
#include "utils/utils.h"
4651

@@ -112,8 +117,8 @@ DSN_DEFINE_string(meta_server,
112117
"",
113118
"Comma-separated list of MetaServers in the Pegasus cluster");
114119

115-
namespace dsn {
116-
namespace replication {
120+
namespace dsn::replication {
121+
117122
const std::string replication_options::kRepsDir = "reps";
118123
const std::string replication_options::kReplicaAppType = "replica";
119124

@@ -333,5 +338,113 @@ replication_options::check_if_in_black_list(const std::vector<std::string> &blac
333338
return false;
334339
}
335340

336-
} // namespace replication
337-
} // namespace dsn
341+
void add_app_info(const std::string &app_name,
342+
int32_t app_id,
343+
int32_t partition_count,
344+
const std::vector<partition_configuration> &pcs,
345+
bool detailed,
346+
bool resolve_ip,
347+
std::string_view total_row_name,
348+
utils::multi_table_printer &multi_printer)
349+
{
350+
// "general" section.
351+
utils::table_printer general_printer("general");
352+
general_printer.add_row_name_and_data("app_name", app_name);
353+
general_printer.add_row_name_and_data("app_id", app_id);
354+
general_printer.add_row_name_and_data("partition_count", partition_count);
355+
general_printer.add_row_name_and_data("max_replica_count",
356+
pcs.empty() ? 0 : pcs[0].max_replica_count);
357+
358+
multi_printer.add(std::move(general_printer));
359+
360+
if (!detailed) {
361+
return;
362+
}
363+
364+
// "replicas" section.
365+
utils::table_printer partitions_printer("replicas");
366+
partitions_printer.add_title("pidx");
367+
partitions_printer.add_column("ballot");
368+
partitions_printer.add_column("replica_count");
369+
partitions_printer.add_column("primary");
370+
partitions_printer.add_column("secondaries");
371+
372+
struct node_stat
373+
{
374+
int primary_count{0};
375+
int secondary_count{0};
376+
};
377+
std::map<host_port, node_stat> node_stats;
378+
379+
int total_prim_count = 0;
380+
int total_sec_count = 0;
381+
int fully_healthy = 0;
382+
int write_unhealthy = 0;
383+
int read_unhealthy = 0;
384+
for (const auto &pc : pcs) {
385+
int replica_count = 0;
386+
if (pc.hp_primary) {
387+
++replica_count;
388+
++node_stats[pc.hp_primary].primary_count;
389+
++total_prim_count;
390+
}
391+
replica_count += static_cast<int>(pc.hp_secondaries.size());
392+
total_sec_count += static_cast<int>(pc.hp_secondaries.size());
393+
394+
if (pc.hp_primary) {
395+
if (replica_count >= pc.max_replica_count) {
396+
++fully_healthy;
397+
} else if (replica_count < 2) {
398+
++write_unhealthy;
399+
}
400+
} else {
401+
++write_unhealthy;
402+
++read_unhealthy;
403+
}
404+
405+
partitions_printer.add_row(pc.pid.get_partition_index());
406+
partitions_printer.append_data(pc.ballot);
407+
partitions_printer.append_data(fmt::format("{}/{}", replica_count, pc.max_replica_count));
408+
partitions_printer.append_data(pc.hp_primary ? pc.hp_primary.to_string() : "-");
409+
partitions_printer.append_data(fmt::format("[{}]", fmt::join(pc.hp_secondaries, ",")));
410+
411+
for (const auto &secondary : pc.hp_secondaries) {
412+
++node_stats[secondary].secondary_count;
413+
}
414+
}
415+
416+
multi_printer.add(std::move(partitions_printer));
417+
418+
// "nodes" section.
419+
utils::table_printer nodes_printer("nodes");
420+
nodes_printer.add_title("node");
421+
nodes_printer.add_column("primary");
422+
nodes_printer.add_column("secondary");
423+
nodes_printer.add_column("total");
424+
425+
for (const auto &[addr, stat] : node_stats) {
426+
nodes_printer.add_row(addr.resolve(resolve_ip));
427+
nodes_printer.append_data(stat.primary_count);
428+
nodes_printer.append_data(stat.secondary_count);
429+
nodes_printer.append_data(stat.primary_count + stat.secondary_count);
430+
}
431+
432+
nodes_printer.add_row(total_row_name);
433+
nodes_printer.append_data(total_prim_count);
434+
nodes_printer.append_data(total_sec_count);
435+
nodes_printer.append_data(total_prim_count + total_sec_count);
436+
437+
multi_printer.add(std::move(nodes_printer));
438+
439+
// "healthy" partition count section.
440+
utils::table_printer healthy_printer("healthy");
441+
healthy_printer.add_row_name_and_data("fully_healthy_partition_count", fully_healthy);
442+
healthy_printer.add_row_name_and_data("unhealthy_partition_count",
443+
partition_count - fully_healthy);
444+
healthy_printer.add_row_name_and_data("write_unhealthy_partition_count", write_unhealthy);
445+
healthy_printer.add_row_name_and_data("read_unhealthy_partition_count", read_unhealthy);
446+
447+
multi_printer.add(std::move(healthy_printer));
448+
}
449+
450+
} // namespace dsn::replication

0 commit comments

Comments
 (0)