/* * HotRangeCommand.actor.cpp * * This source file is part of the FoundationDB open source project * * Copyright 2013-2024 Apple Inc. and the FoundationDB project authors * * Licensed 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 #include "fdbcli/fdbcli.actor.h" #include "fdbclient/FDBOptions.g.h" #include "fdbclient/IClientApi.h" #include "fdbclient/StorageServerInterface.h" #include "fdbclient/json_spirit/json_spirit_value.h" #include "flow/Arena.h" #include "flow/FastRef.h" #include "flow/NetworkAddress.h" #include "flow/ThreadHelper.actor.h" #include "flow/actorcompiler.h" // This must be the last #include. namespace { ReadHotSubRangeRequest::SplitType parseSplitType(const std::string& typeStr) { auto type = ReadHotSubRangeRequest::SplitType::BYTES; if (typeStr == "bytes") { type = ReadHotSubRangeRequest::BYTES; } else if (typeStr == "readBytes") { type = ReadHotSubRangeRequest::READ_BYTES; } else if (typeStr == "readOps") { type = ReadHotSubRangeRequest::READ_OPS; } else { fmt::print("Error: {} is not a valid split type. Will use bytes as the default split type\n", typeStr); } return type; } } // namespace namespace fdb_cli { ACTOR Future hotRangeCommandActor(Database localdb, Reference db, std::vector tokens, std::map* storage_interface) { if (tokens.size() == 1) { // initialize storage interfaces storage_interface->clear(); wait(getStorageServerInterfaces(db, storage_interface)); fmt::print("\nThe following {} storage servers can be queried:\n", storage_interface->size()); for (const auto& [addr, _] : *storage_interface) { fmt::print("{}\n", addr); } fmt::print("\n"); } else if (tokens.size() == 6) { if (storage_interface->size() == 0) { fprintf(stderr, "ERROR: no storage processes to query. You must run the `hotrange’ command first.\n"); return false; } state Key address = tokens[1]; // At present we only support one process(IP:Port) at a time if (!storage_interface->count(address.toString())) { fprintf(stderr, "ERROR: storage process `%s' not recognized.\n", printable(address).c_str()); return false; } state int splitCount; try { splitCount = boost::lexical_cast(tokens[5].toString()); } catch (...) { fmt::print("Error: splitCount value: '{}', cannot be parsed to an Integer\n", tokens[5].toString()); return false; } ReadHotSubRangeRequest::SplitType splitType = parseSplitType(tokens[2].toString()); KeyRangeRef range(tokens[3], tokens[4]); // TODO: refactor this to support multiversion fdbcli in the future Standalone> metrics = wait(localdb->getHotRangeMetrics((*storage_interface)[address.toString()], range, splitType, splitCount)); // next parse the result and form a json array for each object json_spirit::mArray resultArray; for (const auto& metric : metrics) { json_spirit::mObject metricObj; metricObj["begin"] = metric.keys.begin.toString(); metricObj["end"] = metric.keys.end.toString(); metricObj["readBytesPerSec"] = metric.readBandwidthSec; metricObj["readOpsPerSec"] = metric.readOpsSec; metricObj["bytes"] = metric.bytes; resultArray.push_back(metricObj); } // print out the json array const std::string result = json_spirit::write_string(json_spirit::mValue(resultArray), json_spirit::pretty_print); fmt::print("\n{}\n", result); } else { printUsage(tokens[0]); return false; } return true; } CommandFactory hotRangeFactory( "hotrange", CommandHelp( "hotrange ", "Fetch read metrics from a given storage server to detect hot range", "If no arguments are specified, populates the list of storage processes that can be queried. " " specify the range you are interested in, " " is the metric used to divide ranges, " "splitCount is the number of returned ranges divided by the given metric. " "The command will return an array of json object for each range with their metrics." "Notice: the three metrics are sampled by a different way, so their values are not perfectly matched.\n")); } // namespace fdb_cli