mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-27 01:51:59 +00:00
Fixed not an issue, shown by TSan; minor modifications [#CLICKHOUSE-2].
This commit is contained in:
parent
0c41b87647
commit
fe717a4d6e
@ -37,10 +37,11 @@ template void QuotaValues<size_t>::initFromConfig(const String & config_elem, Po
|
||||
template void QuotaValues<std::atomic<size_t>>::initFromConfig(const String & config_elem, Poco::Util::AbstractConfiguration & config);
|
||||
|
||||
|
||||
void QuotaForInterval::initFromConfig(const String & config_elem, time_t duration_, time_t offset_, Poco::Util::AbstractConfiguration & config)
|
||||
void QuotaForInterval::initFromConfig(const String & config_elem, time_t duration_, bool randomize_, time_t offset_, Poco::Util::AbstractConfiguration & config)
|
||||
{
|
||||
rounded_time = 0;
|
||||
rounded_time.store(0, std::memory_order_relaxed);
|
||||
duration = duration_;
|
||||
randomize = randomize_;
|
||||
offset = offset_;
|
||||
max.initFromConfig(config_elem, config);
|
||||
}
|
||||
@ -61,8 +62,10 @@ String QuotaForInterval::toString() const
|
||||
{
|
||||
std::stringstream res;
|
||||
|
||||
auto loaded_rounded_time = rounded_time.load(std::memory_order_relaxed);
|
||||
|
||||
res << std::fixed << std::setprecision(3)
|
||||
<< "Interval: " << LocalDateTime(rounded_time) << " - " << LocalDateTime(rounded_time + duration) << ".\n"
|
||||
<< "Interval: " << LocalDateTime(loaded_rounded_time) << " - " << LocalDateTime(loaded_rounded_time + duration) << ".\n"
|
||||
<< "Queries: " << used.queries << ".\n"
|
||||
<< "Errors: " << used.errors << ".\n"
|
||||
<< "Result rows: " << used.result_rows << ".\n"
|
||||
@ -107,10 +110,22 @@ void QuotaForInterval::checkAndAddExecutionTime(time_t current_time, const Strin
|
||||
|
||||
void QuotaForInterval::updateTime(time_t current_time)
|
||||
{
|
||||
if (current_time >= rounded_time + static_cast<int>(duration))
|
||||
/** If current time is greater than end of interval,
|
||||
* then clear accumulated quota values and switch to next interval [rounded_time, rounded_time + duration).
|
||||
*/
|
||||
|
||||
auto loaded_rounded_time = rounded_time.load(std::memory_order_acquire);
|
||||
while (true)
|
||||
{
|
||||
rounded_time = (current_time - offset) / duration * duration + offset;
|
||||
used.clear();
|
||||
if (current_time < loaded_rounded_time + static_cast<time_t>(duration))
|
||||
break;
|
||||
|
||||
time_t new_rounded_time = (current_time - offset) / duration * duration + offset;
|
||||
if (rounded_time.compare_exchange_strong(loaded_rounded_time, new_rounded_time))
|
||||
{
|
||||
used.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +151,7 @@ void QuotaForInterval::check(
|
||||
|
||||
message << " has been exceeded. "
|
||||
<< resource_name << ": " << used_amount << ", max: " << max_amount << ". "
|
||||
<< "Interval will end at " << LocalDateTime(rounded_time + duration) << ". "
|
||||
<< "Interval will end at " << LocalDateTime(rounded_time.load(std::memory_order_relaxed) + duration) << ". "
|
||||
<< "Name of quota template: '" << quota_name << "'.";
|
||||
|
||||
throw Exception(message.str(), ErrorCodes::QUOTA_EXPIRED);
|
||||
@ -158,14 +173,14 @@ void QuotaForIntervals::initFromConfig(const String & config_elem, Poco::Util::A
|
||||
time_t duration = config.getInt(interval_config_elem + ".duration", 0);
|
||||
time_t offset = 0;
|
||||
|
||||
if (!duration) /// Skip quaotas with zero duration
|
||||
if (!duration) /// Skip quotas with zero duration
|
||||
continue;
|
||||
|
||||
bool randomize = config.getBool(interval_config_elem + ".randomize", false);
|
||||
if (randomize)
|
||||
offset = std::uniform_int_distribution<decltype(duration)>(0, duration - 1)(rng);
|
||||
|
||||
cont[duration].initFromConfig(interval_config_elem, duration, offset, config);
|
||||
cont[duration].initFromConfig(interval_config_elem, duration, randomize, offset, config);
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,7 +197,7 @@ void QuotaForIntervals::setMax(const QuotaForIntervals & quota)
|
||||
for (auto & x : quota.cont)
|
||||
{
|
||||
if (!cont.count(x.first))
|
||||
cont[x.first] = x.second;
|
||||
cont.emplace(x.first, x.second);
|
||||
else
|
||||
cont[x.first].max = x.second.max;
|
||||
}
|
||||
@ -254,7 +269,7 @@ void Quota::loadFromConfig(const String & config_elem, const String & name_, Poc
|
||||
|
||||
QuotaForIntervals new_max(name, {});
|
||||
new_max.initFromConfig(config_elem, config, rng);
|
||||
if (!(new_max == max))
|
||||
if (!new_max.hasEqualConfiguration(max))
|
||||
{
|
||||
max = new_max;
|
||||
for (auto & quota : quota_for_keys)
|
||||
@ -310,9 +325,9 @@ void Quotas::loadFromConfig(Poco::Util::AbstractConfiguration & config)
|
||||
|
||||
for (Poco::Util::AbstractConfiguration::Keys::const_iterator it = config_keys.begin(); it != config_keys.end(); ++it)
|
||||
{
|
||||
if (!cont[*it])
|
||||
cont[*it] = std::make_unique<Quota>();
|
||||
cont[*it]->loadFromConfig("quotas." + *it, *it, config, rng);
|
||||
if (!cont.count(*it))
|
||||
cont.try_emplace(*it);
|
||||
cont[*it].loadFromConfig("quotas." + *it, *it, config, rng);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +337,7 @@ QuotaForIntervalsPtr Quotas::get(const String & name, const String & quota_key,
|
||||
if (cont.end() == it)
|
||||
throw Exception("Unknown quota " + name, ErrorCodes::UNKNOWN_QUOTA);
|
||||
|
||||
return it->second->get(quota_key, user_name, ip);
|
||||
return it->second.get(quota_key, user_name, ip);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -99,16 +99,17 @@ inline auto QuotaValues<std::atomic<size_t>>::tuple() const
|
||||
/// Time, rounded down to start of interval; limits for that interval and accumulated values.
|
||||
struct QuotaForInterval
|
||||
{
|
||||
time_t rounded_time = 0;
|
||||
std::atomic<time_t> rounded_time {0};
|
||||
size_t duration = 0;
|
||||
bool randomize = false;
|
||||
time_t offset = 0; /// Offset of interval for randomization (to avoid DoS if intervals for many users end at one time).
|
||||
QuotaValues<size_t> max;
|
||||
QuotaValues<std::atomic<size_t>> used;
|
||||
|
||||
QuotaForInterval() {}
|
||||
QuotaForInterval() = default;
|
||||
QuotaForInterval(time_t duration_) : duration(duration_) {}
|
||||
|
||||
void initFromConfig(const String & config_elem, time_t duration_, time_t offset_, Poco::Util::AbstractConfiguration & config);
|
||||
void initFromConfig(const String & config_elem, time_t duration_, bool randomize_, time_t offset_, Poco::Util::AbstractConfiguration & config);
|
||||
|
||||
/// Increase current value.
|
||||
void addQuery() noexcept;
|
||||
@ -125,14 +126,30 @@ struct QuotaForInterval
|
||||
/// Get a text, describing what quota is exceeded.
|
||||
String toString() const;
|
||||
|
||||
/// Only compare configuration, not accumulated (used) values or random offsets.
|
||||
bool operator== (const QuotaForInterval & rhs) const
|
||||
{
|
||||
return
|
||||
rounded_time == rhs.rounded_time &&
|
||||
duration == rhs.duration &&
|
||||
max == rhs.max &&
|
||||
used == rhs.used;
|
||||
return randomize == rhs.randomize
|
||||
&& duration == rhs.duration
|
||||
&& max == rhs.max;
|
||||
}
|
||||
|
||||
QuotaForInterval & operator= (const QuotaForInterval & rhs)
|
||||
{
|
||||
rounded_time.store(rhs.rounded_time.load(std::memory_order_relaxed));
|
||||
duration = rhs.duration;
|
||||
randomize = rhs.randomize;
|
||||
offset = rhs.offset;
|
||||
max = rhs.max;
|
||||
used = rhs.used;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QuotaForInterval(const QuotaForInterval & rhs)
|
||||
{
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Reset counters of used resources, if interval for quota is expired.
|
||||
void updateTime(time_t current_time);
|
||||
@ -192,7 +209,7 @@ public:
|
||||
/// Get text, describing what part of quota has been exceeded.
|
||||
String toString() const;
|
||||
|
||||
bool operator== (const QuotaForIntervals & rhs) const
|
||||
bool hasEqualConfiguration(const QuotaForIntervals & rhs) const
|
||||
{
|
||||
return cont == rhs.cont && quota_name == rhs.quota_name;
|
||||
}
|
||||
@ -233,13 +250,13 @@ class Quotas
|
||||
{
|
||||
private:
|
||||
/// Name of quota -> quota.
|
||||
using Container = std::unordered_map<String, std::unique_ptr<Quota>>;
|
||||
using Container = std::unordered_map<String, Quota>;
|
||||
Container cont;
|
||||
|
||||
public:
|
||||
void loadFromConfig(Poco::Util::AbstractConfiguration & config);
|
||||
QuotaForIntervalsPtr get(const String & name, const String & quota_key,
|
||||
const String & user_name, const Poco::Net::IPAddress & ip);
|
||||
const String & user_name, const Poco::Net::IPAddress & ip);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user