Encoding of tags in the database now supports multiple tags per throttle. Remove throttle prefix search.

This commit is contained in:
A.J. Beamon 2020-04-10 10:12:26 -07:00
parent ebeca10bce
commit 55a0d00ad4
5 changed files with 65 additions and 27 deletions

View File

@ -3788,17 +3788,16 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
continue;
}
else if(tokencmp(tokens[1], "list")) {
if(tokens.size() > 4) {
printf("Usage: throttle list [LIMIT] [PREFIX]\n");
if(tokens.size() > 3) {
printf("Usage: throttle list [LIMIT]\n");
printf("\n");
printf("Lists tags that are currently throttled, optionally limited to a certain tag PREFIX.\n");
printf("The default LIMIT is 100 tags, and by default all tags will be searched.\n");
printf("Lists tags that are currently throttled.\n");
printf("The default LIMIT is 100 tags.\n");
is_error = true;
continue;
}
state int throttleListLimit = 100;
state StringRef prefix;
if(tokens.size() >= 3) {
char *end;
throttleListLimit = std::strtol((const char*)tokens[2].begin(), &end, 10);
@ -3808,19 +3807,11 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
continue;
}
}
if(tokens.size() >= 4) {
prefix = tokens[3];
}
std::map<Standalone<StringRef>, TagThrottleInfo> tags = wait(ThrottleApi::getTags(db, throttleListLimit, prefix));
std::string prefixString = "";
if(prefix.size() > 0) {
prefixString = format(" with prefix `%s'", prefix.toString().c_str());
}
std::map<Standalone<StringRef>, TagThrottleInfo> tags = wait(ThrottleApi::getTags(db, throttleListLimit));
if(tags.size() > 0) {
printf("Throttled tags%s:\n\n", prefixString.c_str());
printf("Throttled tags:\n\n");
printf(" Rate | Expiration (s) | Priority | Type | Tag\n");
printf(" ------+----------------+-----------+--------+------------------\n");
for(auto itr = tags.begin(); itr != tags.end(); ++itr) {
@ -3829,16 +3820,16 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
(int)(itr->second.expiration-now()),
TagThrottleInfo::priorityToString(itr->second.priority),
itr->second.autoThrottled ? "auto" : "manual",
itr->first.substr(tagThrottleKeysPrefix.size()).toString().c_str());
itr->first.toString().c_str());
}
if(tags.size() == throttleListLimit) {
printf("\nThe tag limit `%d' was reached. Use the [LIMIT] or [PREFIX] arguments to view additional tags.\n", throttleListLimit);
printf("Usage: throttle list [LIMIT] [PREFIX]\n");
printf("\nThe tag limit `%d' was reached. Use the [LIMIT] argument to view additional tags.\n", throttleListLimit);
printf("Usage: throttle list [LIMIT]\n");
}
}
else {
printf("There are no throttled tags%s\n", prefixString.c_str());
printf("There are no throttled tags\n");
}
}
else if(tokencmp(tokens[1], "on") && tokens.size() <=6) {

View File

@ -3275,8 +3275,6 @@ ACTOR Future<Version> extractReadVersion(DatabaseContext* cx, uint32_t flags, Re
if(rep.locked && !lockAware)
throw database_locked();
TagThrottleInfo::Priority priority;
++cx->transactionReadVersionsCompleted;
auto &priorityThrottledTags = cx->throttledTags[TagThrottleInfo::priorityFromReadVersionFlags(flags)];

View File

@ -62,7 +62,52 @@ namespace ThrottleApi {
tr.atomicOp(tagThrottleSignalKey, LiteralStringRef("XXXXXXXXXX\x00\x00\x00\x00"), MutationRef::SetVersionstampedValue);
}
ACTOR Future<std::map<Standalone<StringRef>, TagThrottleInfo>> getTags(Database db, int limit, KeyRef prefix) {
// Format for throttle key:
//
// tagThrottleKeysPrefix + [tag list]
// tag list consists of 1 or more consecutive tags, each encoded as:
// tag.size() (1 byte) + tag's bytes. For example, tag 'foo' is: \x03foo
// The tags are listed in sorted order
//
// Currently, the throttle API supports only 1 tag per throttle
Standalone<StringRef> throttleKeyForTags(std::set<StringRef> const& tags) {
ASSERT(CLIENT_KNOBS->MAX_TRANSACTION_TAG_LENGTH < 256);
ASSERT(tags.size() > 0);
ASSERT(tags.size() == 1); // TODO: support multiple tags per throttle
int size = tagThrottleKeysPrefix.size() + tags.size();
for(auto tag : tags) {
ASSERT(tag.size() <= CLIENT_KNOBS->MAX_TRANSACTION_TAG_LENGTH);
size += tag.size();
}
Key result;
uint8_t* str = new (result.arena()) uint8_t[size];
result.contents() = StringRef(str, size);
memcpy(str, tagThrottleKeysPrefix.begin(), tagThrottleKeysPrefix.size());
str += tagThrottleKeysPrefix.size();
for(auto tag : tags) {
*(str++) = (uint8_t)tag.size();
if(tag.size() > 0) {
memcpy(str, tag.begin(), tag.size());
str += tag.size();
}
}
return result;
}
StringRef tagFromThrottleKey(KeyRef key) {
StringRef tag = key.substr(tagThrottleKeysPrefix.size()+1);
ASSERT(tag.size() == key.begin()[tagThrottleKeysPrefix.size()]); // TODO: support multiple tags per throttle
return tag;
}
ACTOR Future<std::map<Standalone<StringRef>, TagThrottleInfo>> getTags(Database db, int limit) {
state Transaction tr(db);
loop {
@ -70,7 +115,7 @@ namespace ThrottleApi {
Standalone<RangeResultRef> tags = wait(tr.getRange(tagThrottleKeys, limit));
std::map<Standalone<StringRef>, TagThrottleInfo> results;
for(auto tag : tags) {
results[tag.key] = decodeTagThrottleValue(tag.value);
results[tagFromThrottleKey(tag.key)] = decodeTagThrottleValue(tag.value);
}
return results;
}
@ -82,7 +127,7 @@ namespace ThrottleApi {
ACTOR Future<Void> throttleTag(Database db, Standalone<StringRef> tag, double rate, double expiration, bool serializeExpirationAsDuration, bool autoThrottled) {
state Transaction tr(db);
state Key key = tag.withPrefix(tagThrottleKeysPrefix);
state Key key = throttleKeyForTags(std::set<StringRef>{ tag });
TagThrottleInfo throttle(rate, expiration, autoThrottled, TagThrottleInfo::Priority::DEFAULT, serializeExpirationAsDuration);
BinaryWriter wr(IncludeVersion());
@ -108,7 +153,7 @@ namespace ThrottleApi {
ACTOR Future<bool> unthrottleTag(Database db, Standalone<StringRef> tag) {
state Transaction tr(db);
state Key key = tag.withPrefix(tagThrottleKeysPrefix);
state Key key = throttleKeyForTags(std::set<StringRef>{ tag });
loop {
try {

View File

@ -151,7 +151,11 @@ struct dynamic_size_traits<TagSet> : std::true_type {
BINARY_SERIALIZABLE(TagThrottleInfo::Priority);
namespace ThrottleApi {
Future<std::map<Standalone<StringRef>, TagThrottleInfo>> getTags(Database const& db, int const& limit, KeyRef const& prefix);
// Currently, only 1 tag in a key is supported
Standalone<StringRef> throttleKeyForTags(std::set<StringRef> const& tags);
StringRef tagFromThrottleKey(KeyRef key);
Future<std::map<Standalone<StringRef>, TagThrottleInfo>> getTags(Database const& db, int const& limit);
Future<Void> throttleTag(Database const& db, Standalone<StringRef> const& tag, double const& rate, double const& expiration,
bool const& serializeExpirationAsDuration, bool const& autoThrottled); // TODO: priorities

View File

@ -424,7 +424,7 @@ ACTOR Future<Void> monitorThrottlingChanges(RatekeeperData *self) {
}
for(auto entry : throttledTags.get()) {
StringRef tag = entry.key.substr(tagThrottleKeysPrefix.size());
StringRef tag = ThrottleApi::tagFromThrottleKey(entry.key);
TagThrottleInfo throttleInfo = ThrottleApi::decodeTagThrottleValue(entry.value);
TraceEvent("RatekeeperReadThrottleRead").detail("Tag", tag).detail("Expiration", throttleInfo.expiration);
if((!self->autoThrottlingEnabled && throttleInfo.autoThrottled) || throttleInfo.expiration <= now()) { // TODO: keep or delete auto throttles when disabling auto-throttling