add fdbcli support to list recommended tags

This commit is contained in:
XiaoxiWang 2020-08-20 06:26:31 +00:00
parent bc6e42c634
commit 0945959a35
3 changed files with 88 additions and 27 deletions

View File

@ -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")) {

View File

@ -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();

View File

@ -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);