src/shell/commands/detect_hotkey.cpp (133 lines of code) (raw):
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <fmt/core.h>
#include <stdio.h>
#include <memory>
#include <set>
#include <string>
#include "client/replication_ddl_client.h"
#include "common/gpid.h"
#include "replica_admin_types.h"
#include "rpc/rpc_host_port.h"
#include "shell/argh.h"
#include "shell/command_executor.h"
#include "shell/command_utils.h"
#include "shell/commands.h"
#include "utils/error_code.h"
#include "utils/errors.h"
#include "utils/string_conv.h"
#include "utils/strings.h"
bool generate_hotkey_request(dsn::replication::detect_hotkey_request &req,
const std::string &hotkey_action,
const std::string &hotkey_type,
int app_id,
int partition_index,
std::string &err_info)
{
if (dsn::utils::iequals(hotkey_type, "read")) {
req.type = dsn::replication::hotkey_type::type::READ;
} else if (dsn::utils::iequals(hotkey_type, "write")) {
req.type = dsn::replication::hotkey_type::type::WRITE;
} else {
err_info = fmt::format("\"{}\" is an invalid hotkey type (should be 'read' or 'write')\n",
hotkey_type);
return false;
}
if (dsn::utils::iequals(hotkey_action, "start")) {
req.action = dsn::replication::detect_action::START;
} else if (dsn::utils::iequals(hotkey_action, "stop")) {
req.action = dsn::replication::detect_action::STOP;
} else if (dsn::utils::iequals(hotkey_action, "query")) {
req.action = dsn::replication::detect_action::QUERY;
} else {
err_info =
fmt::format("\"{}\" is an invalid hotkey detect action (should be 'start' or 'stop')\n",
hotkey_action);
return false;
}
req.pid = dsn::gpid(app_id, partition_index);
return true;
}
// TODO: (Tangyanzhao) merge hotspot_partition_calculator::send_detect_hotkey_request
bool detect_hotkey(command_executor *e, shell_context *sc, arguments args)
{
// detect_hotkey
// <-a|--app_id str><-p|--partition_index num><-t|--hotkey_type read|write>
// <-c|--detect_action start|stop|query><-d|--address str>
static const std::set<std::string> params = {"a",
"app_id",
"p",
"partition_index",
"c",
"hotkey_action",
"t",
"hotkey_type",
"d",
"address"};
static const std::set<std::string> flags = {};
argh::parser cmd(args.argc, args.argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
const auto &check = validate_cmd(cmd, params, flags, 0);
if (!check) {
// TODO(wangdan): use SHELL_PRINT* macros instead.
fmt::print(stderr, "{}\n", check.description());
return false;
}
int app_id;
if (!dsn::buf2int32(cmd({"-a", "--app_id"}).str(), app_id)) {
fmt::print(stderr, "\"{}\" is an invalid num\n", cmd({"-a", "--app_id"}).str());
return false;
}
int partition_index;
if (!dsn::buf2int32(cmd({"-p", "--partition_index"}).str(), partition_index)) {
fmt::print(stderr, "\"{}\" is an invalid num\n", cmd({"-p", "--partition_index"}).str());
return false;
}
dsn::host_port target_hp;
std::string err_info;
const auto &target_hp_str = cmd({"-d", "--address"}).str();
if (!validate_ip(sc, target_hp_str, target_hp, err_info)) {
fmt::print(stderr, "{}\n", err_info);
return false;
}
std::string hotkey_action = cmd({"-c", "--hotkey_action"}).str();
std::string hotkey_type = cmd({"-t", "--hotkey_type"}).str();
dsn::replication::detect_hotkey_request req;
if (!generate_hotkey_request(
req, hotkey_action, hotkey_type, app_id, partition_index, err_info)) {
fmt::print(stderr, err_info);
return false;
}
detect_hotkey_response resp;
auto err = sc->ddl_client->detect_hotkey(target_hp, req, resp);
if (err != dsn::ERR_OK) {
fmt::print(stderr,
"Hotkey detection rpc sending failed, in {}.{}, error_hint:{}\n",
app_id,
partition_index,
err.to_string());
return true;
}
if (resp.err != dsn::ERR_OK) {
fmt::print(stderr,
"Hotkey detection performed failed, in {}.{}, error_hint:{} {}\n",
app_id,
partition_index,
resp.err,
resp.err_hint);
return true;
}
switch (req.action) {
case dsn::replication::detect_action::START:
fmt::print("Hotkey detection is starting, using 'detect_hotkey -a {} -p {} -t {} -c "
"query -d {}' to get the result later\n",
app_id,
partition_index,
hotkey_type,
target_hp_str);
break;
case dsn::replication::detect_action::STOP:
fmt::print("Hotkey detection is stopped now\n");
break;
case dsn::replication::detect_action::QUERY:
fmt::print("Find {} hotkey in {}.{} result:{}\n",
hotkey_type,
app_id,
partition_index,
resp.hotkey_result);
break;
}
return true;
}