querier_cache: unregister querier from reader_concurrency_semaphore during eviction
In insert_querier(), we may evict older queriers to make room for the new one. However, we forgot to unregister the evicted queriers from reader_concurrency_semaphore. As a result, when reader_concurrency_semaphore eventually wanted to evict something, it saw an inactive_read_handle that was not connected to a querier_cache::entry, and crashed on use-after-free. Fix by evicting through the inactive_read_handle associated with the querier to be evicted. This removes traces of the querier from both reader_concurrency_semaphore and querier_cache. We also have to massage the statistics since querier_inactive_read::evict() updates different counters. Fixes #4018. Tests: unit(release) Reviewed-by: Botond Denes <bdenes@scylladb.com> Message-Id: <20190102175023.26093-1-avi@scylladb.com>
This commit is contained in:
14
querier.cc
14
querier.cc
@@ -273,13 +273,15 @@ static void insert_querier(
|
||||
memory_usage += q.memory_usage();
|
||||
|
||||
if (memory_usage >= max_queriers_memory_usage) {
|
||||
auto it = entries.begin();
|
||||
const auto end = entries.end();
|
||||
while (it != end && memory_usage >= max_queriers_memory_usage) {
|
||||
++stats.memory_based_evictions;
|
||||
while (!entries.empty() && memory_usage >= max_queriers_memory_usage) {
|
||||
auto it = entries.begin();
|
||||
memory_usage -= it->memory_usage();
|
||||
--stats.population;
|
||||
it = entries.erase(it);
|
||||
auto ir = sem.unregister_inactive_read(it->get_inactive_handle());
|
||||
ir->evict();
|
||||
// querier_inactive_read::evict() updates resource_based_evictions,
|
||||
// (and population) while we want memory_based_evictions:
|
||||
--stats.resource_based_evictions;
|
||||
++stats.memory_based_evictions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user