in src/shell/commands/table_management.cpp [178:467]
bool app_disk(command_executor *e, shell_context *sc, arguments args)
{
if (args.argc <= 1)
return false;
static struct option long_options[] = {{"resolve_ip", no_argument, 0, 'r'},
{"detailed", no_argument, 0, 'd'},
{"json", no_argument, 0, 'j'},
{"output", required_argument, 0, 'o'},
{0, 0, 0, 0}};
std::string app_name = args.argv[1];
std::string out_file;
bool detailed = false;
bool json = false;
bool resolve_ip = false;
optind = 0;
while (true) {
int option_index = 0;
int c;
c = getopt_long(args.argc, args.argv, "drjo:", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
detailed = true;
break;
case 'r':
resolve_ip = true;
break;
case 'j':
json = true;
break;
case 'o':
out_file = optarg;
break;
default:
return false;
}
}
if (app_name.empty()) {
std::cout << "ERROR: null app name" << std::endl;
return false;
}
std::streambuf *buf;
std::ofstream of;
if (!out_file.empty()) {
of.open(out_file);
buf = of.rdbuf();
} else {
buf = std::cout.rdbuf();
}
std::ostream out(buf);
dsn::utils::multi_table_printer mtp;
dsn::utils::table_printer tp_params("parameters");
if (!(app_name.empty() && out_file.empty())) {
if (!app_name.empty())
tp_params.add_row_name_and_data("app_name", app_name);
if (!out_file.empty())
tp_params.add_row_name_and_data("out_file", out_file);
}
tp_params.add_row_name_and_data("detailed", detailed);
mtp.add(std::move(tp_params));
int32_t app_id = 0;
int32_t partition_count = 0;
int32_t max_replica_count = 0;
std::vector<dsn::partition_configuration> partitions;
dsn::error_code err = sc->ddl_client->list_app(app_name, app_id, partition_count, partitions);
if (err != ::dsn::ERR_OK) {
std::cout << "ERROR: list app " << app_name << " failed, error=" << err.to_string()
<< std::endl;
return true;
}
if (!partitions.empty()) {
max_replica_count = partitions[0].max_replica_count;
}
std::vector<node_desc> nodes;
if (!fill_nodes(sc, "replica-server", nodes)) {
std::cout << "ERROR: get replica server node list failed" << std::endl;
return true;
}
std::vector<std::pair<bool, std::string>> results = call_remote_command(
sc,
nodes,
"perf-counters-by-prefix",
{fmt::format("replica*app.pegasus*disk.storage.sst(MB)@{}.", app_id),
fmt::format("replica*app.pegasus*disk.storage.sst.count@{}.", app_id)});
std::map<dsn::rpc_address, std::map<int32_t, double>> disk_map;
std::map<dsn::rpc_address, std::map<int32_t, double>> count_map;
for (int i = 0; i < nodes.size(); ++i) {
if (!results[i].first) {
std::cout << "ERROR: query perf counter from node " << nodes[i].address.to_string()
<< " failed" << std::endl;
return true;
}
dsn::perf_counter_info info;
dsn::blob bb(results[i].second.data(), 0, results[i].second.size());
if (!dsn::json::json_forwarder<dsn::perf_counter_info>::decode(bb, info)) {
std::cout << "ERROR: decode perf counter info from node "
<< nodes[i].address.to_string() << " failed, result = " << results[i].second
<< std::endl;
return true;
}
if (info.result != "OK") {
std::cout << "ERROR: query perf counter info from node " << nodes[i].address.to_string()
<< " returns error, error = " << info.result << std::endl;
return true;
}
for (dsn::perf_counter_metric &m : info.counters) {
int32_t app_id_x, partition_index_x;
std::string counter_name;
bool parse_ret = parse_app_pegasus_perf_counter_name(
m.name, app_id_x, partition_index_x, counter_name);
CHECK(parse_ret, "name = {}", m.name);
if (m.name.find("sst(MB)") != std::string::npos) {
disk_map[nodes[i].address][partition_index_x] = m.value;
} else if (m.name.find("sst.count") != std::string::npos) {
count_map[nodes[i].address][partition_index_x] = m.value;
}
}
}
::dsn::utils::table_printer tp_general("result");
tp_general.add_row_name_and_data("app_name", app_name);
tp_general.add_row_name_and_data("app_id", app_id);
tp_general.add_row_name_and_data("partition_count", partition_count);
tp_general.add_row_name_and_data("max_replica_count", max_replica_count);
::dsn::utils::table_printer tp_details("details");
if (detailed) {
tp_details.add_title("pidx");
tp_details.add_column("ballot");
tp_details.add_column("replica_count");
tp_details.add_column("primary");
tp_details.add_column("secondaries");
}
double disk_used_for_primary_replicas = 0;
int primary_replicas_count = 0;
double disk_used_for_all_replicas = 0;
int all_replicas_count = 0;
for (int i = 0; i < partitions.size(); i++) {
const dsn::partition_configuration &p = partitions[i];
int replica_count = 0;
if (!p.primary.is_invalid()) {
replica_count++;
}
replica_count += p.secondaries.size();
std::string replica_count_str;
{
std::stringstream oss;
oss << replica_count << "/" << p.max_replica_count;
replica_count_str = oss.str();
}
std::string primary_str("-");
if (!p.primary.is_invalid()) {
bool disk_found = false;
double disk_value = 0;
auto f1 = disk_map.find(p.primary);
if (f1 != disk_map.end()) {
auto &sub_map = f1->second;
auto f2 = sub_map.find(p.pid.get_partition_index());
if (f2 != sub_map.end()) {
disk_found = true;
disk_value = f2->second;
disk_used_for_primary_replicas += disk_value;
primary_replicas_count++;
disk_used_for_all_replicas += disk_value;
all_replicas_count++;
}
}
bool count_found = false;
double count_value = 0;
auto f3 = count_map.find(p.primary);
if (f3 != count_map.end()) {
auto &sub_map = f3->second;
auto f3 = sub_map.find(p.pid.get_partition_index());
if (f3 != sub_map.end()) {
count_found = true;
count_value = f3->second;
}
}
std::stringstream oss;
std::string hostname;
std::string ip = p.primary.to_string();
if (resolve_ip && dsn::utils::hostname_from_ip_port(ip.c_str(), &hostname)) {
oss << hostname << "(";
} else {
oss << p.primary.to_string() << "(";
};
if (disk_found)
oss << disk_value;
else
oss << "-";
oss << ",";
if (count_found)
oss << "#" << count_value;
else
oss << "-";
oss << ")";
primary_str = oss.str();
}
std::string secondary_str;
{
std::stringstream oss;
oss << "[";
for (int j = 0; j < p.secondaries.size(); j++) {
if (j != 0)
oss << ",";
bool found = false;
double value = 0;
auto f1 = disk_map.find(p.secondaries[j]);
if (f1 != disk_map.end()) {
auto &sub_map = f1->second;
auto f2 = sub_map.find(p.pid.get_partition_index());
if (f2 != sub_map.end()) {
found = true;
value = f2->second;
disk_used_for_all_replicas += value;
all_replicas_count++;
}
}
bool count_found = false;
double count_value = 0;
auto f3 = count_map.find(p.secondaries[j]);
if (f3 != count_map.end()) {
auto &sub_map = f3->second;
auto f3 = sub_map.find(p.pid.get_partition_index());
if (f3 != sub_map.end()) {
count_found = true;
count_value = f3->second;
}
}
std::string hostname;
std::string ip = p.secondaries[j].to_string();
if (resolve_ip && dsn::utils::hostname_from_ip_port(ip.c_str(), &hostname)) {
oss << hostname << "(";
} else {
oss << p.secondaries[j].to_string() << "(";
};
if (found)
oss << value;
else
oss << "-";
oss << ",";
if (count_found)
oss << "#" << count_value;
else
oss << "-";
oss << ")";
}
oss << "]";
secondary_str = oss.str();
}
if (detailed) {
tp_details.add_row(std::to_string(p.pid.get_partition_index()));
tp_details.append_data(p.ballot);
tp_details.append_data(replica_count_str);
tp_details.append_data(primary_str);
tp_details.append_data(secondary_str);
}
}
tp_general.add_row_name_and_data("disk_used_for_primary_replicas(MB)",
disk_used_for_primary_replicas);
tp_general.add_row_name_and_data("disk_used_for_all_replicas(MB)", disk_used_for_all_replicas);
tp_general.add_row_name_and_data("partitions not counted",
std::to_string(partition_count - primary_replicas_count) +
"/" + std::to_string(partition_count));
tp_general.add_row_name_and_data(
"replicas not counted",
std::to_string(partition_count * max_replica_count - all_replicas_count) + "/" +
std::to_string(partition_count * max_replica_count));
mtp.add(std::move(tp_general));
if (detailed) {
mtp.add(std::move(tp_details));
}
mtp.output(out, json ? tp_output_format::kJsonPretty : tp_output_format::kTabular);
return true;
}