2020-04-10 07:55:56 +08:00
|
|
|
/*
|
|
|
|
* TagThrottle.h
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2020 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FDBCLIENT_TAG_THROTTLE_H
|
|
|
|
#define FDBCLIENT_TAG_THROTTLE_H
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "flow/Error.h"
|
|
|
|
#include "flow/flow.h"
|
|
|
|
#include "flow/network.h"
|
|
|
|
#include "fdbclient/FDBTypes.h"
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
class Database;
|
|
|
|
|
2020-04-17 23:07:01 +08:00
|
|
|
namespace ThrottleApi {
|
|
|
|
}
|
2020-04-10 07:55:56 +08:00
|
|
|
|
2020-04-17 23:07:01 +08:00
|
|
|
typedef StringRef TransactionTagRef;
|
|
|
|
typedef Standalone<TransactionTagRef> TransactionTag;
|
2020-04-10 07:55:56 +08:00
|
|
|
|
|
|
|
class TagSet {
|
|
|
|
public:
|
2020-04-17 05:43:22 +08:00
|
|
|
typedef std::set<TransactionTagRef>::const_iterator const_iterator;
|
2020-04-10 07:55:56 +08:00
|
|
|
|
|
|
|
TagSet() : bytes(0) {}
|
|
|
|
|
2020-04-17 05:43:22 +08:00
|
|
|
void addTag(TransactionTagRef tag);
|
2020-04-24 11:50:40 +08:00
|
|
|
size_t size() const;
|
2020-04-10 07:55:56 +08:00
|
|
|
|
|
|
|
const_iterator begin() const {
|
|
|
|
return tags.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
const_iterator end() const {
|
|
|
|
return tags.end();
|
|
|
|
}
|
2020-07-20 11:17:46 +08:00
|
|
|
void clear() {
|
|
|
|
tags.clear();
|
|
|
|
bytes = 0;
|
|
|
|
}
|
2020-04-10 07:55:56 +08:00
|
|
|
//private:
|
2020-04-23 05:15:35 +08:00
|
|
|
Arena arena;
|
2020-04-17 05:43:22 +08:00
|
|
|
std::set<TransactionTagRef> tags;
|
2020-04-10 07:55:56 +08:00
|
|
|
size_t bytes;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct dynamic_size_traits<TagSet> : std::true_type {
|
|
|
|
// May be called multiple times during one serialization
|
|
|
|
template <class Context>
|
|
|
|
static size_t size(const TagSet& t, Context&) {
|
2020-05-05 06:49:55 +08:00
|
|
|
return t.tags.size() + t.bytes;
|
2020-04-10 07:55:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Guaranteed to be called only once during serialization
|
|
|
|
template <class Context>
|
2020-05-05 06:49:55 +08:00
|
|
|
static void save(uint8_t* out, const TagSet& t, Context& c) {
|
2020-05-05 07:24:13 +08:00
|
|
|
uint8_t *start = out;
|
2020-04-10 07:55:56 +08:00
|
|
|
for (const auto& tag : t.tags) {
|
2020-05-03 06:58:45 +08:00
|
|
|
*(out++) = (uint8_t)tag.size();
|
2020-04-10 07:55:56 +08:00
|
|
|
|
|
|
|
std::copy(tag.begin(), tag.end(), out);
|
|
|
|
out += tag.size();
|
|
|
|
}
|
2020-05-05 06:49:55 +08:00
|
|
|
|
|
|
|
ASSERT((size_t)(out-start) == size(t, c));
|
2020-04-10 07:55:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Context is an arbitrary type that is plumbed by reference throughout the
|
|
|
|
// load call tree.
|
|
|
|
template <class Context>
|
|
|
|
static void load(const uint8_t* data, size_t size, TagSet& t, Context& context) {
|
2020-05-05 06:49:55 +08:00
|
|
|
//const uint8_t *start = data;
|
2020-04-10 07:55:56 +08:00
|
|
|
const uint8_t *end = data + size;
|
2020-05-05 06:49:55 +08:00
|
|
|
while(data < end) {
|
2020-05-03 06:58:45 +08:00
|
|
|
uint8_t len = *(data++);
|
2020-04-17 05:43:22 +08:00
|
|
|
TransactionTagRef tag(context.tryReadZeroCopy(data, len), len);
|
2020-04-10 07:55:56 +08:00
|
|
|
data += len;
|
|
|
|
|
|
|
|
t.tags.insert(tag);
|
|
|
|
t.bytes += tag.size();
|
|
|
|
}
|
|
|
|
|
2020-05-05 06:49:55 +08:00
|
|
|
ASSERT(data == end);
|
2020-05-03 06:58:45 +08:00
|
|
|
|
2020-04-23 05:15:35 +08:00
|
|
|
// Deserialized tag sets share the arena with the request that contained them
|
|
|
|
// For this reason, persisting a TagSet that shares memory with other request
|
|
|
|
// members should be done with caution.
|
|
|
|
t.arena = context.arena();
|
2020-04-10 07:55:56 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-16 03:47:55 +08:00
|
|
|
enum class TagThrottleType : uint8_t {
|
|
|
|
MANUAL,
|
|
|
|
AUTO
|
|
|
|
};
|
|
|
|
|
2020-08-21 12:07:25 +08:00
|
|
|
enum class TagThrottledReason: uint8_t {
|
|
|
|
UNSET = 0,
|
|
|
|
MANUAL,
|
|
|
|
BUSY_READ,
|
|
|
|
BUSY_WRITE
|
2020-08-20 14:26:31 +08:00
|
|
|
};
|
|
|
|
|
2020-04-24 11:50:40 +08:00
|
|
|
struct TagThrottleKey {
|
|
|
|
TagSet tags;
|
2020-05-16 03:47:55 +08:00
|
|
|
TagThrottleType throttleType;
|
2020-04-25 02:31:16 +08:00
|
|
|
TransactionPriority priority;
|
2020-04-24 11:50:40 +08:00
|
|
|
|
2020-05-16 03:47:55 +08:00
|
|
|
TagThrottleKey() : throttleType(TagThrottleType::MANUAL), priority(TransactionPriority::DEFAULT) {}
|
|
|
|
TagThrottleKey(TagSet tags, TagThrottleType throttleType, TransactionPriority priority)
|
|
|
|
: tags(tags), throttleType(throttleType), priority(priority) {}
|
2020-04-24 11:50:40 +08:00
|
|
|
|
|
|
|
Key toKey() const;
|
|
|
|
static TagThrottleKey fromKey(const KeyRef& key);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TagThrottleValue {
|
|
|
|
double tpsRate;
|
|
|
|
double expirationTime;
|
|
|
|
double initialDuration;
|
2020-08-21 12:07:25 +08:00
|
|
|
TagThrottledReason reason;
|
2020-04-11 01:12:26 +08:00
|
|
|
|
2020-08-20 14:26:31 +08:00
|
|
|
TagThrottleValue() : tpsRate(0), expirationTime(0), initialDuration(0), reason(TagThrottledReason::UNSET) {}
|
2020-08-21 12:07:25 +08:00
|
|
|
TagThrottleValue(double tpsRate, double expirationTime, double initialDuration, TagThrottledReason reason)
|
2020-08-20 14:26:31 +08:00
|
|
|
: tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration), reason(reason) {}
|
2020-04-10 07:55:56 +08:00
|
|
|
|
2020-04-24 11:50:40 +08:00
|
|
|
static TagThrottleValue fromValue(const ValueRef& value);
|
2020-04-10 07:55:56 +08:00
|
|
|
|
2020-05-23 08:14:21 +08:00
|
|
|
//To change this serialization, ProtocolVersion::TagThrottleValue must be updated, and downgrades need to be considered
|
2020-04-24 11:50:40 +08:00
|
|
|
template<class Ar>
|
|
|
|
void serialize(Ar& ar) {
|
2020-08-24 05:03:26 +08:00
|
|
|
if(ar.protocolVersion().hasTagThrottleValueReason()) {
|
|
|
|
serializer(ar, tpsRate, expirationTime, initialDuration, reinterpret_cast<uint8_t&>(reason));
|
|
|
|
}
|
|
|
|
else if(ar.protocolVersion().hasTagThrottleValue()) {
|
|
|
|
serializer(ar, tpsRate, expirationTime, initialDuration);
|
|
|
|
if(ar.isDeserializing) {
|
|
|
|
reason = TagThrottledReason::UNSET;
|
|
|
|
}
|
|
|
|
}
|
2020-04-24 11:50:40 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TagThrottleInfo {
|
|
|
|
TransactionTag tag;
|
2020-05-16 03:47:55 +08:00
|
|
|
TagThrottleType throttleType;
|
2020-04-25 02:31:16 +08:00
|
|
|
TransactionPriority priority;
|
2020-04-24 11:50:40 +08:00
|
|
|
double tpsRate;
|
|
|
|
double expirationTime;
|
|
|
|
double initialDuration;
|
2020-08-21 12:07:25 +08:00
|
|
|
TagThrottledReason reason;
|
2020-04-24 11:50:40 +08:00
|
|
|
|
2020-08-21 12:07:25 +08:00
|
|
|
TagThrottleInfo(TransactionTag tag, TagThrottleType throttleType, TransactionPriority priority, double tpsRate, double expirationTime, double initialDuration, TagThrottledReason reason = TagThrottledReason::UNSET)
|
2020-08-20 14:26:31 +08:00
|
|
|
: tag(tag), throttleType(throttleType), priority(priority), tpsRate(tpsRate), expirationTime(expirationTime), initialDuration(initialDuration), reason(reason) {}
|
2020-05-02 12:36:28 +08:00
|
|
|
|
2020-08-20 14:26:31 +08:00
|
|
|
TagThrottleInfo(TagThrottleKey key, TagThrottleValue value)
|
|
|
|
: throttleType(key.throttleType), priority(key.priority), tpsRate(value.tpsRate), expirationTime(value.expirationTime), initialDuration(value.initialDuration), reason(value.reason)
|
2020-04-24 11:50:40 +08:00
|
|
|
{
|
|
|
|
ASSERT(key.tags.size() == 1); // Multiple tags per throttle is not currently supported
|
|
|
|
tag = *key.tags.begin();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace ThrottleApi {
|
2020-08-20 01:40:45 +08:00
|
|
|
Future<std::vector<TagThrottleInfo>> getThrottledTags(Database const& db, int const& limit, bool const& containsRecommend = false);
|
2020-08-20 14:26:31 +08:00
|
|
|
Future<std::vector<TagThrottleInfo>> getRecommendedTags(Database const& db, int const& limit);
|
2020-04-24 11:50:40 +08:00
|
|
|
|
|
|
|
Future<Void> throttleTags(Database const& db, TagSet const& tags, double const& tpsRate, double const& initialDuration,
|
2020-08-20 14:26:31 +08:00
|
|
|
TagThrottleType const& throttleType, TransactionPriority const& priority, Optional<double> const& expirationTime = Optional<double>(),
|
2020-08-21 12:07:25 +08:00
|
|
|
Optional<TagThrottledReason> const& reason = Optional<TagThrottledReason>());
|
2020-04-24 11:50:40 +08:00
|
|
|
|
2020-05-16 03:47:55 +08:00
|
|
|
Future<bool> unthrottleTags(Database const& db, TagSet const& tags, Optional<TagThrottleType> const& throttleType, Optional<TransactionPriority> const& priority);
|
2020-04-10 07:55:56 +08:00
|
|
|
|
2020-05-16 03:47:55 +08:00
|
|
|
Future<bool> unthrottleAll(Database db, Optional<TagThrottleType> throttleType, Optional<TransactionPriority> priority);
|
2020-05-02 12:36:28 +08:00
|
|
|
Future<bool> expire(Database db);
|
2020-04-10 07:55:56 +08:00
|
|
|
|
|
|
|
Future<Void> enableAuto(Database const& db, bool const& enabled);
|
|
|
|
};
|
|
|
|
|
2020-04-25 02:31:16 +08:00
|
|
|
BINARY_SERIALIZABLE(TransactionPriority);
|
2020-04-17 23:07:01 +08:00
|
|
|
|
|
|
|
template<class Value>
|
2020-04-18 00:06:45 +08:00
|
|
|
using TransactionTagMap = std::unordered_map<TransactionTag, Value, std::hash<TransactionTagRef>>;
|
2020-04-17 23:07:01 +08:00
|
|
|
|
|
|
|
template<class Value>
|
2020-04-25 02:31:16 +08:00
|
|
|
using PrioritizedTransactionTagMap = std::map<TransactionPriority, TransactionTagMap<Value>>;
|
2020-04-17 23:07:01 +08:00
|
|
|
|
2020-08-30 03:35:31 +08:00
|
|
|
template <class Value>
|
2020-08-01 14:14:52 +08:00
|
|
|
using UIDTransactionTagMap = std::unordered_map<UID, TransactionTagMap<Value>>;
|
2020-04-10 07:55:56 +08:00
|
|
|
#endif
|