2013-08-12 00:36:18 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2016-05-23 00:40:28 +00:00
|
|
|
|
#include <cstring>
|
2014-01-08 16:33:28 +00:00
|
|
|
|
#include <unordered_map>
|
2015-04-16 06:12:35 +00:00
|
|
|
|
#include <memory>
|
2016-05-23 00:40:28 +00:00
|
|
|
|
#include <random>
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
#include <Poco/Timespan.h>
|
|
|
|
|
|
|
|
|
|
#include <Poco/Util/Application.h>
|
|
|
|
|
#include <Poco/Util/AbstractConfiguration.h>
|
|
|
|
|
|
|
|
|
|
#include <Poco/Net/IPAddress.h>
|
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/Common.h>
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/Core/Types.h>
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2013-08-12 00:36:18 +00:00
|
|
|
|
#include <DB/IO/WriteHelpers.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Квота на потребление ресурсов за заданный интервал - часть настроек.
|
|
|
|
|
* Используются, чтобы ограничить потребление ресурсов пользователем.
|
|
|
|
|
* Квота действует "мягко" - может быть немного превышена, так как проверяется, как правило, на каждый блок.
|
|
|
|
|
* Квота не сохраняется при перезапуске сервера.
|
|
|
|
|
* Квота распространяется только на один сервер.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/// Используется как для максимальных значений, так и в качестве счётчика накопившихся значений.
|
|
|
|
|
struct QuotaValues
|
|
|
|
|
{
|
|
|
|
|
/// Нули в качестве ограничений означают "не ограничено".
|
|
|
|
|
size_t queries; /// Количество запросов.
|
|
|
|
|
size_t errors; /// Количество запросов с эксепшенами.
|
|
|
|
|
size_t result_rows; /// Количество строк, отданных в качестве результата.
|
2013-08-28 17:23:00 +00:00
|
|
|
|
size_t result_bytes; /// Количество байт, отданных в качестве результата.
|
2013-08-12 00:36:18 +00:00
|
|
|
|
size_t read_rows; /// Количество строк, прочитанных из таблиц.
|
2013-08-28 17:23:00 +00:00
|
|
|
|
size_t read_bytes; /// Количество байт, прочитанных из таблиц.
|
2013-08-12 00:36:18 +00:00
|
|
|
|
Poco::Timespan execution_time; /// Суммарное время выполнения запросов.
|
|
|
|
|
|
|
|
|
|
QuotaValues()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
memset(this, 0, sizeof(*this));
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 07:17:22 +00:00
|
|
|
|
void initFromConfig(const String & config_elem, Poco::Util::AbstractConfiguration & config);
|
|
|
|
|
|
|
|
|
|
bool operator== (const QuotaValues & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
queries == rhs.queries &&
|
|
|
|
|
errors == rhs.errors &&
|
|
|
|
|
result_rows == rhs.result_rows &&
|
|
|
|
|
result_bytes == rhs.result_bytes &&
|
|
|
|
|
read_rows == rhs.read_rows &&
|
|
|
|
|
read_bytes == rhs.read_bytes &&
|
|
|
|
|
execution_time == rhs.execution_time;
|
|
|
|
|
}
|
2013-08-12 00:36:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Время, округлённое до границы интервала, квота за интервал и накопившиеся за этот интервал значения.
|
|
|
|
|
struct QuotaForInterval
|
|
|
|
|
{
|
|
|
|
|
time_t rounded_time;
|
|
|
|
|
size_t duration;
|
2015-05-29 21:32:10 +00:00
|
|
|
|
time_t offset; /// Смещение интервала, для рандомизации.
|
2013-08-12 00:36:18 +00:00
|
|
|
|
QuotaValues max;
|
|
|
|
|
QuotaValues used;
|
|
|
|
|
|
|
|
|
|
QuotaForInterval() : rounded_time() {}
|
|
|
|
|
QuotaForInterval(time_t duration_) : duration(duration_) {}
|
|
|
|
|
|
2015-05-29 21:32:10 +00:00
|
|
|
|
void initFromConfig(const String & config_elem, time_t duration_, time_t offset_, Poco::Util::AbstractConfiguration & config);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
/// Увеличить соответствующее значение.
|
|
|
|
|
void addQuery(time_t current_time, const String & quota_name);
|
2015-07-01 05:18:54 +00:00
|
|
|
|
void addError(time_t current_time, const String & quota_name) noexcept;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
/// Проверить, не превышена ли квота уже. Если превышена - кидает исключение.
|
|
|
|
|
void checkExceeded(time_t current_time, const String & quota_name);
|
|
|
|
|
|
|
|
|
|
/// Проверить соответствующее значение. Если превышено - кинуть исключение. Иначе - увеличить его.
|
2013-08-28 20:47:22 +00:00
|
|
|
|
void checkAndAddResultRowsBytes(time_t current_time, const String & quota_name, size_t rows, size_t bytes);
|
|
|
|
|
void checkAndAddReadRowsBytes(time_t current_time, const String & quota_name, size_t rows, size_t bytes);
|
2013-08-28 17:23:00 +00:00
|
|
|
|
void checkAndAddExecutionTime(time_t current_time, const String & quota_name, Poco::Timespan amount);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
2013-08-28 20:47:22 +00:00
|
|
|
|
/// Получить текст, описывающий, какая часть квоты израсходована.
|
|
|
|
|
String toString() const;
|
|
|
|
|
|
2014-02-13 07:17:22 +00:00
|
|
|
|
bool operator== (const QuotaForInterval & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
rounded_time == rhs.rounded_time &&
|
|
|
|
|
duration == rhs.duration &&
|
|
|
|
|
max == rhs.max &&
|
|
|
|
|
used == rhs.used;
|
|
|
|
|
}
|
2013-08-12 00:36:18 +00:00
|
|
|
|
private:
|
|
|
|
|
/// Сбросить счётчик использованных ресурсов, если соответствующий интервал, за который считается квота, прошёл.
|
|
|
|
|
void updateTime(time_t current_time);
|
2013-08-28 17:23:00 +00:00
|
|
|
|
void check(size_t max_amount, size_t used_amount, time_t current_time, const String & quota_name, const char * resource_name);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Quota;
|
|
|
|
|
|
|
|
|
|
/// Длина интервала -> квота и накопившиеся за текущий интервал такой длины значения (например, 3600 -> значения за текущий час).
|
|
|
|
|
class QuotaForIntervals
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/// При проверке, будем обходить интервалы в порядке, обратном величине - от самого большого до самого маленького.
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Container = std::map<size_t, QuotaForInterval>;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
Container cont;
|
|
|
|
|
|
2014-02-13 07:17:22 +00:00
|
|
|
|
std::string name;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
public:
|
2014-02-13 07:17:22 +00:00
|
|
|
|
QuotaForIntervals(const std::string & name_ = "") : name(name_) {}
|
2013-08-28 20:47:22 +00:00
|
|
|
|
|
|
|
|
|
/// Есть ли хотя бы один интервал, за который считается квота?
|
|
|
|
|
bool empty() const
|
|
|
|
|
{
|
|
|
|
|
return cont.empty();
|
|
|
|
|
}
|
2015-04-16 06:12:35 +00:00
|
|
|
|
|
2015-05-29 21:32:10 +00:00
|
|
|
|
void initFromConfig(const String & config_elem, Poco::Util::AbstractConfiguration & config, std::mt19937 & rng);
|
2014-02-13 07:17:22 +00:00
|
|
|
|
|
|
|
|
|
/// Обновляет максимальные значения значениями из quota.
|
|
|
|
|
/// Удаляет интервалы, которых нет в quota, добавляет интревалы, которых нет здесь, но есть в quota.
|
|
|
|
|
void setMax(const QuotaForIntervals & quota);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
void addQuery(time_t current_time);
|
2015-07-01 05:18:54 +00:00
|
|
|
|
void addError(time_t current_time) noexcept;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
void checkExceeded(time_t current_time);
|
|
|
|
|
|
2013-08-28 20:47:22 +00:00
|
|
|
|
void checkAndAddResultRowsBytes(time_t current_time, size_t rows, size_t bytes);
|
|
|
|
|
void checkAndAddReadRowsBytes(time_t current_time, size_t rows, size_t bytes);
|
2013-08-28 17:23:00 +00:00
|
|
|
|
void checkAndAddExecutionTime(time_t current_time, Poco::Timespan amount);
|
2013-08-28 20:47:22 +00:00
|
|
|
|
|
|
|
|
|
/// Получить текст, описывающий, какая часть квоты израсходована.
|
|
|
|
|
String toString() const;
|
2014-02-13 07:17:22 +00:00
|
|
|
|
|
|
|
|
|
bool operator== (const QuotaForIntervals & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return cont == rhs.cont && name == rhs.name;
|
|
|
|
|
}
|
2013-08-12 00:36:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using QuotaForIntervalsPtr = std::shared_ptr<QuotaForIntervals>;
|
2014-02-13 07:17:22 +00:00
|
|
|
|
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
/// Ключ квоты -> квоты за интервалы. Если квота не допускает ключей, то накопленные значения хранятся по ключу 0.
|
|
|
|
|
struct Quota
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Container = std::unordered_map<UInt64, QuotaForIntervalsPtr>;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
String name;
|
|
|
|
|
|
|
|
|
|
/// Максимальные значения из конфига.
|
|
|
|
|
QuotaForIntervals max;
|
|
|
|
|
/// Максимальные и накопленные значения для разных ключей.
|
2014-02-13 07:17:22 +00:00
|
|
|
|
/// Для всех ключей максимальные значения одинаковы и взяты из max.
|
2013-08-12 00:36:18 +00:00
|
|
|
|
Container quota_for_keys;
|
2016-05-28 10:15:36 +00:00
|
|
|
|
std::mutex mutex;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
|
|
|
|
bool is_keyed;
|
|
|
|
|
bool keyed_by_ip;
|
|
|
|
|
|
2014-02-13 07:17:22 +00:00
|
|
|
|
Quota() : is_keyed(false), keyed_by_ip(false) {}
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
2015-05-29 21:32:10 +00:00
|
|
|
|
void loadFromConfig(const String & config_elem, const String & name_, Poco::Util::AbstractConfiguration & config, std::mt19937 & rng);
|
2014-02-13 07:17:22 +00:00
|
|
|
|
QuotaForIntervalsPtr get(const String & quota_key, const String & user_name, const Poco::Net::IPAddress & ip);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Quotas
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/// Имя квоты -> квоты.
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Container = std::unordered_map<String, std::unique_ptr<Quota>>;
|
2013-08-12 00:36:18 +00:00
|
|
|
|
Container cont;
|
|
|
|
|
|
|
|
|
|
public:
|
2014-02-13 07:17:22 +00:00
|
|
|
|
void loadFromConfig(Poco::Util::AbstractConfiguration & config);
|
|
|
|
|
QuotaForIntervalsPtr get(const String & name, const String & quota_key,
|
|
|
|
|
const String & user_name, const Poco::Net::IPAddress & ip);
|
2013-08-12 00:36:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|