mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-12 19:02:12 +00:00
cache_hitrate_calculator: make cache hitrate calculation preemptable
The calculation is done in a non preemptable loop over all tables, so if numbers of tables is very large it may take a while since we also build a string for gossiper state. Make the loop preemtable and also make the string calculation more efficient by preallocating memory for it. Message-Id: <20190516132748.6469-3-gleb@scylladb.com>
This commit is contained in:
committed by
Tomasz Grabiec
parent
4517c56a57
commit
31bf4cfb5e
@@ -46,6 +46,8 @@ class cache_hitrate_calculator : public seastar::async_sharded_service<cache_hit
|
||||
bool _stopped = false;
|
||||
float _diff = 0;
|
||||
std::unordered_map<utils::UUID, stat> _rates;
|
||||
size_t _slen = 0;
|
||||
std::string _gstate;
|
||||
future<> _done = make_ready_future();
|
||||
|
||||
future<lowres_clock::duration> recalculate_hitrates();
|
||||
|
||||
@@ -134,16 +134,18 @@ future<lowres_clock::duration> cache_hitrate_calculator::recalculate_hitrates()
|
||||
|
||||
return _db.map_reduce0(cf_to_cache_hit_stats, std::unordered_map<utils::UUID, stat>(), sum_stats_per_cf).then([this, non_system_filter] (std::unordered_map<utils::UUID, stat> rates) mutable {
|
||||
_diff = 0;
|
||||
_gstate.reserve(_slen); // assume length did not change from previous iteration
|
||||
_slen = 0;
|
||||
_rates = std::move(rates);
|
||||
// set calculated rates on all shards
|
||||
return _db.invoke_on_all([this, cpuid = engine().cpu_id(), non_system_filter] (database& db) {
|
||||
sstring gstate;
|
||||
for (auto& cf : db.get_column_families() | boost::adaptors::filtered(non_system_filter)) {
|
||||
auto it = _rates.find(cf.first);
|
||||
if (it == _rates.end()) { // a table may be added before map/reduce completes and this code runs
|
||||
continue;
|
||||
return do_for_each(_rates, [this, cpuid, &db] (auto&& r) mutable {
|
||||
auto it = db.get_column_families().find(r.first);
|
||||
if (it == db.get_column_families().end()) { // a table may be added before map/reduce completes and this code runs
|
||||
return;
|
||||
}
|
||||
stat s = it->second;
|
||||
auto& cf = *it;
|
||||
stat& s = r.second;
|
||||
float rate = 0;
|
||||
if (s.h) {
|
||||
rate = s.h / (s.h + s.m);
|
||||
@@ -151,25 +153,25 @@ future<lowres_clock::duration> cache_hitrate_calculator::recalculate_hitrates()
|
||||
if (engine().cpu_id() == cpuid) {
|
||||
// calculate max difference between old rate and new one for all cfs
|
||||
_diff = std::max(_diff, std::abs(float(cf.second->get_global_cache_hit_rate()) - rate));
|
||||
gstate += format("{}.{}:{:f};", cf.second->schema()->ks_name(), cf.second->schema()->cf_name(), rate);
|
||||
_gstate += format("{}.{}:{:0.6f};", cf.second->schema()->ks_name(), cf.second->schema()->cf_name(), rate);
|
||||
}
|
||||
cf.second->set_global_cache_hit_rate(cache_temperature(rate));
|
||||
}
|
||||
if (gstate.size()) {
|
||||
auto& g = gms::get_local_gossiper();
|
||||
auto& ss = get_local_storage_service();
|
||||
return g.add_local_application_state(gms::application_state::CACHE_HITRATES, ss.value_factory.cache_hitrates(std::move(gstate)));
|
||||
}
|
||||
return make_ready_future<>();
|
||||
});
|
||||
});
|
||||
}).then([this] {
|
||||
_rates.clear();
|
||||
auto& g = gms::get_local_gossiper();
|
||||
auto& ss = get_local_storage_service();
|
||||
_slen = _gstate.size();
|
||||
g.add_local_application_state(gms::application_state::CACHE_HITRATES, ss.value_factory.cache_hitrates(_gstate));
|
||||
// if max difference during this round is big schedule next recalculate earlier
|
||||
if (_diff < 0.01) {
|
||||
return std::chrono::milliseconds(2000);
|
||||
} else {
|
||||
return std::chrono::milliseconds(500);
|
||||
}
|
||||
}).finally([this] {
|
||||
_gstate = std::string(); // free memory, do not trust clear() to do that for string
|
||||
_rates.clear();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user