add fdbcli support to list recommended tags
This commit is contained in:
parent
bc6e42c634
commit
0945959a35
|
@ -2541,6 +2541,16 @@ void throttleGenerator(const char* text, const char *line, std::vector<std::stri
|
||||||
const char* opts[] = { "auto", nullptr };
|
const char* opts[] = { "auto", nullptr };
|
||||||
arrayGenerator(text, line, opts, lc);
|
arrayGenerator(text, line, opts, lc);
|
||||||
}
|
}
|
||||||
|
else if(tokens.size() >= 2 && tokencmp(tokens[1], "list")) {
|
||||||
|
if(tokens.size() == 2) {
|
||||||
|
const char* opts[] = { "throttled", "recommended", "all", nullptr };
|
||||||
|
arrayGenerator(text, line, opts, lc);
|
||||||
|
}
|
||||||
|
else if(tokens.size() == 3) {
|
||||||
|
const char* opts[] = {"LIMITS", nullptr};
|
||||||
|
arrayGenerator(text, line, opts, lc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fdbcliCompCmd(std::string const& text, std::vector<std::string>& lc) {
|
void fdbcliCompCmd(std::string const& text, std::vector<std::string>& lc) {
|
||||||
|
@ -2661,6 +2671,9 @@ std::vector<const char*> throttleHintGenerator(std::vector<StringRef> const& tok
|
||||||
else if((tokencmp(tokens[1], "enable") || tokencmp(tokens[1], "disable")) && tokens.size() == 2) {
|
else if((tokencmp(tokens[1], "enable") || tokencmp(tokens[1], "disable")) && tokens.size() == 2) {
|
||||||
return { "auto" };
|
return { "auto" };
|
||||||
}
|
}
|
||||||
|
else if(tokens.size() == 2 && tokencmp(tokens[1], "list")) {
|
||||||
|
return {"[throttled|recommended|all]", "[LIMITS]"};
|
||||||
|
}
|
||||||
else if(tokens.size() == 2 && inArgument) {
|
else if(tokens.size() == 2 && inArgument) {
|
||||||
return { "[ARGS]" };
|
return { "[ARGS]" };
|
||||||
}
|
}
|
||||||
|
@ -4077,8 +4090,8 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(tokencmp(tokens[1], "list")) {
|
else if(tokencmp(tokens[1], "list")) {
|
||||||
if(tokens.size() > 3) {
|
if(tokens.size() > 4) {
|
||||||
printf("Usage: throttle list [LIMIT]\n");
|
printf("Usage: throttle list [throttled|recommended|all] [LIMIT]\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Lists tags that are currently throttled.\n");
|
printf("Lists tags that are currently throttled.\n");
|
||||||
printf("The default LIMIT is 100 tags.\n");
|
printf("The default LIMIT is 100 tags.\n");
|
||||||
|
@ -4086,36 +4099,72 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
state int throttleListLimit = 100;
|
state bool reportThrottled = true;
|
||||||
|
state bool reportRecommended = false;
|
||||||
if(tokens.size() >= 3) {
|
if(tokens.size() >= 3) {
|
||||||
|
if(tokencmp(tokens[2], "recommended")) {
|
||||||
|
reportThrottled = false; reportRecommended = true;
|
||||||
|
}
|
||||||
|
else if(tokencmp(tokens[2], "all")){
|
||||||
|
reportThrottled = true; reportRecommended = true;
|
||||||
|
}
|
||||||
|
else if(!tokencmp(tokens[2], "throttled")){
|
||||||
|
printf("ERROR: failed to parse `%s'.\n", printable(tokens[2]).c_str());
|
||||||
|
is_error = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state int throttleListLimit = 100;
|
||||||
|
if(tokens.size() >= 4) {
|
||||||
char *end;
|
char *end;
|
||||||
throttleListLimit = std::strtol((const char*)tokens[2].begin(), &end, 10);
|
throttleListLimit = std::strtol((const char*)tokens[2].begin(), &end, 10);
|
||||||
if ((tokens.size() > 3 && !std::isspace(*end)) || (tokens.size() == 3 && *end != '\0')) {
|
if ((tokens.size() > 4 && !std::isspace(*end)) || (tokens.size() == 3 && *end != '\0')) {
|
||||||
printf("ERROR: failed to parse limit `%s'.\n", printable(tokens[2]).c_str());
|
printf("ERROR: failed to parse limit `%s'.\n", printable(tokens[3]).c_str());
|
||||||
is_error = true;
|
is_error = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TagThrottleInfo> tags = wait(ThrottleApi::getThrottledTags(db, throttleListLimit));
|
state std::vector<TagThrottleInfo> tags; // = wait(ThrottleApi::getThrottledTags(db, throttleListLimit));
|
||||||
|
if(reportThrottled && reportRecommended) {
|
||||||
|
wait(store(tags, ThrottleApi::getThrottledTags(db, throttleListLimit, true)));
|
||||||
|
}
|
||||||
|
else if(reportThrottled) {
|
||||||
|
wait(store(tags, ThrottleApi::getThrottledTags(db, throttleListLimit)));
|
||||||
|
}
|
||||||
|
else if(reportRecommended) {
|
||||||
|
wait(store(tags, ThrottleApi::getRecommendedTags(db, throttleListLimit)));
|
||||||
|
}
|
||||||
|
|
||||||
bool anyLogged = false;
|
bool anyLogged = false;
|
||||||
for(auto itr = tags.begin(); itr != tags.end(); ++itr) {
|
for(auto itr = tags.begin(); itr != tags.end(); ++itr) {
|
||||||
if(itr->expirationTime > now()) {
|
if(itr->expirationTime > now()) {
|
||||||
if(!anyLogged) {
|
if(!anyLogged) {
|
||||||
printf("Throttled tags:\n\n");
|
printf("Throttled tags:\n\n");
|
||||||
printf(" Rate (txn/s) | Expiration (s) | Priority | Type | Tag\n");
|
printf(" Rate (txn/s) | Expiration (s) | Priority | Type | Reason |Tag\n");
|
||||||
printf(" --------------+----------------+-----------+--------+------------------\n");
|
printf(" --------------+----------------+-----------+--------+------------+------\n");
|
||||||
|
|
||||||
anyLogged = true;
|
anyLogged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" %12d | %13ds | %9s | %6s | %s\n",
|
std::string reasonStr = "unset";
|
||||||
(int)(itr->tpsRate),
|
if(itr->reason == TagThrottledReason::MANUAL){
|
||||||
std::min((int)(itr->expirationTime-now()), (int)(itr->initialDuration)),
|
reasonStr = "manual";
|
||||||
transactionPriorityToString(itr->priority, false),
|
}
|
||||||
itr->throttleType == TagThrottleType::AUTO ? "auto" : "manual",
|
else if(itr->reason == TagThrottledReason::BUSY_WRITE) {
|
||||||
itr->tag.toString().c_str());
|
reasonStr = "busy write";
|
||||||
|
}
|
||||||
|
else if(itr->reason == TagThrottledReason::BUSY_READ) {
|
||||||
|
reasonStr = "busy read";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" %12d | %13ds | %9s | %6s | %10s |%s\n", (int)(itr->tpsRate),
|
||||||
|
std::min((int)(itr->expirationTime - now()), (int)(itr->initialDuration)),
|
||||||
|
transactionPriorityToString(itr->priority, false),
|
||||||
|
itr->throttleType == TagThrottleType::AUTO ? "auto" : "manual",
|
||||||
|
reasonStr.c_str(),
|
||||||
|
itr->tag.toString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4124,7 +4173,7 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
|
||||||
printf("Usage: throttle list [LIMIT]\n");
|
printf("Usage: throttle list [LIMIT]\n");
|
||||||
}
|
}
|
||||||
if(!anyLogged) {
|
if(!anyLogged) {
|
||||||
printf("There are no throttled tags\n");
|
printf("There are no %s tags\n", reportThrottled ? "throttled" : "recommended");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(tokencmp(tokens[1], "on")) {
|
else if(tokencmp(tokens[1], "on")) {
|
||||||
|
|
|
@ -216,13 +216,18 @@ namespace ThrottleApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTOR Future<Void> throttleTags(Database db, TagSet tags, double tpsRate, double initialDuration,
|
ACTOR Future<Void> throttleTags(Database db, TagSet tags, double tpsRate, double initialDuration,
|
||||||
TagThrottleType throttleType, TransactionPriority priority, Optional<double> expirationTime) {
|
TagThrottleType throttleType, TransactionPriority priority, Optional<double> expirationTime,
|
||||||
|
Optional<uint8_t> reason) {
|
||||||
state Transaction tr(db);
|
state Transaction tr(db);
|
||||||
state Key key = TagThrottleKey(tags, throttleType, priority).toKey();
|
state Key key = TagThrottleKey(tags, throttleType, priority).toKey();
|
||||||
|
|
||||||
ASSERT(initialDuration > 0);
|
ASSERT(initialDuration > 0);
|
||||||
|
|
||||||
TagThrottleValue throttle(tpsRate, expirationTime.present() ? expirationTime.get() : 0, initialDuration);
|
if(throttleType == TagThrottleType::MANUAL) {
|
||||||
|
reason = TagThrottledReason::MANUAL;
|
||||||
|
}
|
||||||
|
TagThrottleValue throttle(tpsRate, expirationTime.present() ? expirationTime.get() : 0, initialDuration,
|
||||||
|
reason.present() ? reason.get() : TagThrottledReason::UNSET);
|
||||||
BinaryWriter wr(IncludeVersion(ProtocolVersion::withTagThrottleValue()));
|
BinaryWriter wr(IncludeVersion(ProtocolVersion::withTagThrottleValue()));
|
||||||
wr << throttle;
|
wr << throttle;
|
||||||
state Value value = wr.toValue();
|
state Value value = wr.toValue();
|
||||||
|
|
|
@ -115,6 +115,10 @@ enum class TagThrottleType : uint8_t {
|
||||||
AUTO
|
AUTO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TagThrottledReason {
|
||||||
|
static constexpr uint8_t UNSET = 0, MANUAL = 1, BUSY_READ = 2, BUSY_WRITE = 3;
|
||||||
|
};
|
||||||
|
|
||||||
struct TagThrottleKey {
|
struct TagThrottleKey {
|
||||||
TagSet tags;
|
TagSet tags;
|
||||||
TagThrottleType throttleType;
|
TagThrottleType throttleType;
|
||||||
|
@ -132,17 +136,18 @@ struct TagThrottleValue {
|
||||||
double tpsRate;
|
double tpsRate;
|
||||||
double expirationTime;
|
double expirationTime;
|
||||||
double initialDuration;
|
double initialDuration;
|
||||||
|
uint8_t reason;
|
||||||
|
|
||||||
TagThrottleValue() : tpsRate(0), expirationTime(0), initialDuration(0) {}
|
TagThrottleValue() : tpsRate(0), expirationTime(0), initialDuration(0), reason(TagThrottledReason::UNSET) {}
|
||||||
TagThrottleValue(double tpsRate, double expirationTime, double initialDuration)
|
TagThrottleValue(double tpsRate, double expirationTime, double initialDuration, uint8_t reason)
|
||||||
: tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration) {}
|
: tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration), reason(reason) {}
|
||||||
|
|
||||||
static TagThrottleValue fromValue(const ValueRef& value);
|
static TagThrottleValue fromValue(const ValueRef& value);
|
||||||
|
|
||||||
//To change this serialization, ProtocolVersion::TagThrottleValue must be updated, and downgrades need to be considered
|
//To change this serialization, ProtocolVersion::TagThrottleValue must be updated, and downgrades need to be considered
|
||||||
template<class Ar>
|
template<class Ar>
|
||||||
void serialize(Ar& ar) {
|
void serialize(Ar& ar) {
|
||||||
serializer(ar, tpsRate, expirationTime, initialDuration);
|
serializer(ar, tpsRate, expirationTime, initialDuration, reason);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,12 +158,13 @@ struct TagThrottleInfo {
|
||||||
double tpsRate;
|
double tpsRate;
|
||||||
double expirationTime;
|
double expirationTime;
|
||||||
double initialDuration;
|
double initialDuration;
|
||||||
|
uint8_t reason;
|
||||||
|
|
||||||
TagThrottleInfo(TransactionTag tag, TagThrottleType throttleType, TransactionPriority priority, double tpsRate, double expirationTime, double initialDuration)
|
TagThrottleInfo(TransactionTag tag, TagThrottleType throttleType, TransactionPriority priority, double tpsRate, double expirationTime, double initialDuration, uint8_t reason = TagThrottledReason::UNSET)
|
||||||
: tag(tag), throttleType(throttleType), priority(priority), tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration) {}
|
: tag(tag), throttleType(throttleType), priority(priority), tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration), reason(reason) {}
|
||||||
|
|
||||||
TagThrottleInfo(TagThrottleKey key, TagThrottleValue value)
|
TagThrottleInfo(TagThrottleKey key, TagThrottleValue value)
|
||||||
: throttleType(key.throttleType), priority(key.priority), tpsRate(value.tpsRate), expirationTime(value.expirationTime), initialDuration(value.initialDuration)
|
: throttleType(key.throttleType), priority(key.priority), tpsRate(value.tpsRate), expirationTime(value.expirationTime), initialDuration(value.initialDuration), reason(value.reason)
|
||||||
{
|
{
|
||||||
ASSERT(key.tags.size() == 1); // Multiple tags per throttle is not currently supported
|
ASSERT(key.tags.size() == 1); // Multiple tags per throttle is not currently supported
|
||||||
tag = *key.tags.begin();
|
tag = *key.tags.begin();
|
||||||
|
@ -167,10 +173,11 @@ struct TagThrottleInfo {
|
||||||
|
|
||||||
namespace ThrottleApi {
|
namespace ThrottleApi {
|
||||||
Future<std::vector<TagThrottleInfo>> getThrottledTags(Database const& db, int const& limit, bool const& containsRecommend = false);
|
Future<std::vector<TagThrottleInfo>> getThrottledTags(Database const& db, int const& limit, bool const& containsRecommend = false);
|
||||||
Future<std::vector<TagThrottleInfo>> getRecommendedTags(Database const& db, int limit);
|
Future<std::vector<TagThrottleInfo>> getRecommendedTags(Database const& db, int const& limit);
|
||||||
|
|
||||||
Future<Void> throttleTags(Database const& db, TagSet const& tags, double const& tpsRate, double const& initialDuration,
|
Future<Void> throttleTags(Database const& db, TagSet const& tags, double const& tpsRate, double const& initialDuration,
|
||||||
TagThrottleType const& throttleType, TransactionPriority const& priority, Optional<double> const& expirationTime = Optional<double>());
|
TagThrottleType const& throttleType, TransactionPriority const& priority, Optional<double> const& expirationTime = Optional<double>(),
|
||||||
|
Optional<uint8_t> const& reason = Optional<uint8_t>());
|
||||||
|
|
||||||
Future<bool> unthrottleTags(Database const& db, TagSet const& tags, Optional<TagThrottleType> const& throttleType, Optional<TransactionPriority> const& priority);
|
Future<bool> unthrottleTags(Database const& db, TagSet const& tags, Optional<TagThrottleType> const& throttleType, Optional<TransactionPriority> const& priority);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue