mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-15 19:02:04 +00:00
Fix potential busy loop in keepFreeSpaceRatioFunc
This commit is contained in:
parent
89551e0043
commit
5ab8c0357a
@ -998,18 +998,19 @@ void FileCache::freeSpaceRatioKeepingThreadFunc()
|
|||||||
FileCacheReserveStat stat;
|
FileCacheReserveStat stat;
|
||||||
EvictionCandidates eviction_candidates;
|
EvictionCandidates eviction_candidates;
|
||||||
|
|
||||||
bool limits_satisfied = true;
|
IFileCachePriority::DesiredSizeStatus desired_size_status;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/// Collect at most `keep_up_free_space_remove_batch` elements to evict,
|
/// Collect at most `keep_up_free_space_remove_batch` elements to evict,
|
||||||
/// (we use batches to make sure we do not block cache for too long,
|
/// (we use batches to make sure we do not block cache for too long,
|
||||||
/// by default the batch size is quite small).
|
/// by default the batch size is quite small).
|
||||||
limits_satisfied = main_priority->collectCandidatesForEviction(
|
desired_size_status = main_priority->collectCandidatesForEviction(
|
||||||
desired_size, desired_elements_num, keep_up_free_space_remove_batch, stat, eviction_candidates, lock);
|
desired_size, desired_elements_num, keep_up_free_space_remove_batch, stat, eviction_candidates, lock);
|
||||||
|
|
||||||
#ifdef DEBUG_OR_SANITIZER_BUILD
|
#ifdef DEBUG_OR_SANITIZER_BUILD
|
||||||
/// Let's make sure that we correctly processed the limits.
|
/// Let's make sure that we correctly processed the limits.
|
||||||
if (limits_satisfied && eviction_candidates.size() < keep_up_free_space_remove_batch)
|
if (desired_size_status == IFileCachePriority::DesiredSizeStatus::SUCCESS
|
||||||
|
&& eviction_candidates.size() < keep_up_free_space_remove_batch)
|
||||||
{
|
{
|
||||||
const auto current_size = main_priority->getSize(lock);
|
const auto current_size = main_priority->getSize(lock);
|
||||||
chassert(current_size >= stat.total_stat.releasable_size);
|
chassert(current_size >= stat.total_stat.releasable_size);
|
||||||
@ -1063,13 +1064,24 @@ void FileCache::freeSpaceRatioKeepingThreadFunc()
|
|||||||
watch.stop();
|
watch.stop();
|
||||||
ProfileEvents::increment(ProfileEvents::FilesystemCacheFreeSpaceKeepingThreadWorkMilliseconds, watch.elapsedMilliseconds());
|
ProfileEvents::increment(ProfileEvents::FilesystemCacheFreeSpaceKeepingThreadWorkMilliseconds, watch.elapsedMilliseconds());
|
||||||
|
|
||||||
LOG_TRACE(log, "Free space ratio keeping thread finished in {} ms", watch.elapsedMilliseconds());
|
LOG_TRACE(log, "Free space ratio keeping thread finished in {} ms (status: {})",
|
||||||
|
watch.elapsedMilliseconds(), desired_size_status);
|
||||||
|
|
||||||
[[maybe_unused]] bool scheduled = false;
|
[[maybe_unused]] bool scheduled = false;
|
||||||
if (limits_satisfied)
|
switch (desired_size_status)
|
||||||
|
{
|
||||||
|
case IFileCachePriority::DesiredSizeStatus::SUCCESS: [[fallthrough]];
|
||||||
|
case IFileCachePriority::DesiredSizeStatus::CANNOT_EVICT:
|
||||||
|
{
|
||||||
scheduled = keep_up_free_space_ratio_task->scheduleAfter(general_reschedule_ms);
|
scheduled = keep_up_free_space_ratio_task->scheduleAfter(general_reschedule_ms);
|
||||||
else
|
break;
|
||||||
|
}
|
||||||
|
case IFileCachePriority::DesiredSizeStatus::REACHED_MAX_CANDIDATES_LIMIT:
|
||||||
|
{
|
||||||
scheduled = keep_up_free_space_ratio_task->schedule();
|
scheduled = keep_up_free_space_ratio_task->schedule();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
chassert(scheduled);
|
chassert(scheduled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1546,7 +1558,7 @@ void FileCache::applySettingsIfPossible(const FileCacheSettings & new_settings,
|
|||||||
FileCacheReserveStat stat;
|
FileCacheReserveStat stat;
|
||||||
if (main_priority->collectCandidatesForEviction(
|
if (main_priority->collectCandidatesForEviction(
|
||||||
new_settings.max_size, new_settings.max_elements, 0/* max_candidates_to_evict */,
|
new_settings.max_size, new_settings.max_elements, 0/* max_candidates_to_evict */,
|
||||||
stat, eviction_candidates, cache_lock))
|
stat, eviction_candidates, cache_lock) == IFileCachePriority::DesiredSizeStatus::SUCCESS)
|
||||||
{
|
{
|
||||||
if (eviction_candidates.size() == 0)
|
if (eviction_candidates.size() == 0)
|
||||||
{
|
{
|
||||||
|
@ -151,7 +151,13 @@ public:
|
|||||||
/// and `desired_elements_num` as current cache state.
|
/// and `desired_elements_num` as current cache state.
|
||||||
/// Collect no more than `max_candidates_to_evict` elements.
|
/// Collect no more than `max_candidates_to_evict` elements.
|
||||||
/// Return `true` if the first condition is satisfied.
|
/// Return `true` if the first condition is satisfied.
|
||||||
virtual bool collectCandidatesForEviction(
|
enum class DesiredSizeStatus
|
||||||
|
{
|
||||||
|
SUCCESS,
|
||||||
|
CANNOT_EVICT,
|
||||||
|
REACHED_MAX_CANDIDATES_LIMIT,
|
||||||
|
};
|
||||||
|
virtual DesiredSizeStatus collectCandidatesForEviction(
|
||||||
size_t desired_size,
|
size_t desired_size,
|
||||||
size_t desired_elements_count,
|
size_t desired_elements_count,
|
||||||
size_t max_candidates_to_evict,
|
size_t max_candidates_to_evict,
|
||||||
|
@ -323,7 +323,7 @@ bool LRUFileCachePriority::collectCandidatesForEviction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LRUFileCachePriority::collectCandidatesForEviction(
|
IFileCachePriority::DesiredSizeStatus LRUFileCachePriority::collectCandidatesForEviction(
|
||||||
size_t desired_size,
|
size_t desired_size,
|
||||||
size_t desired_elements_count,
|
size_t desired_elements_count,
|
||||||
size_t max_candidates_to_evict,
|
size_t max_candidates_to_evict,
|
||||||
@ -336,12 +336,24 @@ bool LRUFileCachePriority::collectCandidatesForEviction(
|
|||||||
return canFit(0, 0, stat.total_stat.releasable_size, stat.total_stat.releasable_count,
|
return canFit(0, 0, stat.total_stat.releasable_size, stat.total_stat.releasable_count,
|
||||||
lock, &desired_size, &desired_elements_count);
|
lock, &desired_size, &desired_elements_count);
|
||||||
};
|
};
|
||||||
|
auto status = DesiredSizeStatus::CANNOT_EVICT;
|
||||||
auto stop_condition = [&]()
|
auto stop_condition = [&]()
|
||||||
{
|
{
|
||||||
return desired_limits_satisfied() || (max_candidates_to_evict && res.size() >= max_candidates_to_evict);
|
if (desired_limits_satisfied())
|
||||||
|
{
|
||||||
|
status = DesiredSizeStatus::SUCCESS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (max_candidates_to_evict && res.size() >= max_candidates_to_evict)
|
||||||
|
{
|
||||||
|
status = DesiredSizeStatus::REACHED_MAX_CANDIDATES_LIMIT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
iterateForEviction(res, stat, stop_condition, lock);
|
iterateForEviction(res, stat, stop_condition, lock);
|
||||||
return desired_limits_satisfied();
|
chassert(status != DesiredSizeStatus::SUCCESS || stop_condition());
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LRUFileCachePriority::iterateForEviction(
|
void LRUFileCachePriority::iterateForEviction(
|
||||||
@ -350,6 +362,9 @@ void LRUFileCachePriority::iterateForEviction(
|
|||||||
StopConditionFunc stop_condition,
|
StopConditionFunc stop_condition,
|
||||||
const CachePriorityGuard::Lock & lock)
|
const CachePriorityGuard::Lock & lock)
|
||||||
{
|
{
|
||||||
|
if (stop_condition())
|
||||||
|
return;
|
||||||
|
|
||||||
ProfileEvents::increment(ProfileEvents::FilesystemCacheEvictionTries);
|
ProfileEvents::increment(ProfileEvents::FilesystemCacheEvictionTries);
|
||||||
|
|
||||||
IterateFunc iterate_func = [&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
|
IterateFunc iterate_func = [&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
|
||||||
|
@ -63,7 +63,7 @@ public:
|
|||||||
const UserID & user_id,
|
const UserID & user_id,
|
||||||
const CachePriorityGuard::Lock &) override;
|
const CachePriorityGuard::Lock &) override;
|
||||||
|
|
||||||
bool collectCandidatesForEviction(
|
DesiredSizeStatus collectCandidatesForEviction(
|
||||||
size_t desired_size,
|
size_t desired_size,
|
||||||
size_t desired_elements_count,
|
size_t desired_elements_count,
|
||||||
size_t max_candidates_to_evict,
|
size_t max_candidates_to_evict,
|
||||||
|
@ -256,7 +256,7 @@ bool SLRUFileCachePriority::collectCandidatesForEvictionInProtected(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SLRUFileCachePriority::collectCandidatesForEviction(
|
IFileCachePriority::DesiredSizeStatus SLRUFileCachePriority::collectCandidatesForEviction(
|
||||||
size_t desired_size,
|
size_t desired_size,
|
||||||
size_t desired_elements_count,
|
size_t desired_elements_count,
|
||||||
size_t max_candidates_to_evict,
|
size_t max_candidates_to_evict,
|
||||||
@ -268,7 +268,7 @@ bool SLRUFileCachePriority::collectCandidatesForEviction(
|
|||||||
const auto desired_probationary_elements_num = getRatio(desired_elements_count, 1 - size_ratio);
|
const auto desired_probationary_elements_num = getRatio(desired_elements_count, 1 - size_ratio);
|
||||||
|
|
||||||
FileCacheReserveStat probationary_stat;
|
FileCacheReserveStat probationary_stat;
|
||||||
const bool probationary_limit_satisfied = probationary_queue.collectCandidatesForEviction(
|
const auto probationary_desired_size_status = probationary_queue.collectCandidatesForEviction(
|
||||||
desired_probationary_size, desired_probationary_elements_num,
|
desired_probationary_size, desired_probationary_elements_num,
|
||||||
max_candidates_to_evict, probationary_stat, res, lock);
|
max_candidates_to_evict, probationary_stat, res, lock);
|
||||||
|
|
||||||
@ -285,14 +285,14 @@ bool SLRUFileCachePriority::collectCandidatesForEviction(
|
|||||||
chassert(!max_candidates_to_evict || res.size() <= max_candidates_to_evict);
|
chassert(!max_candidates_to_evict || res.size() <= max_candidates_to_evict);
|
||||||
chassert(res.size() == stat.total_stat.releasable_count);
|
chassert(res.size() == stat.total_stat.releasable_count);
|
||||||
|
|
||||||
if (max_candidates_to_evict && res.size() >= max_candidates_to_evict)
|
if (probationary_desired_size_status == DesiredSizeStatus::REACHED_MAX_CANDIDATES_LIMIT)
|
||||||
return probationary_limit_satisfied;
|
return probationary_desired_size_status;
|
||||||
|
|
||||||
const auto desired_protected_size = getRatio(desired_size, size_ratio);
|
const auto desired_protected_size = getRatio(desired_size, size_ratio);
|
||||||
const auto desired_protected_elements_num = getRatio(desired_elements_count, size_ratio);
|
const auto desired_protected_elements_num = getRatio(desired_elements_count, size_ratio);
|
||||||
|
|
||||||
FileCacheReserveStat protected_stat;
|
FileCacheReserveStat protected_stat;
|
||||||
const bool protected_limit_satisfied = protected_queue.collectCandidatesForEviction(
|
const auto protected_desired_size_status = protected_queue.collectCandidatesForEviction(
|
||||||
desired_protected_size, desired_protected_elements_num,
|
desired_protected_size, desired_protected_elements_num,
|
||||||
max_candidates_to_evict - res.size(), protected_stat, res, lock);
|
max_candidates_to_evict - res.size(), protected_stat, res, lock);
|
||||||
|
|
||||||
@ -306,7 +306,10 @@ bool SLRUFileCachePriority::collectCandidatesForEviction(
|
|||||||
desired_protected_size, desired_protected_elements_num,
|
desired_protected_size, desired_protected_elements_num,
|
||||||
protected_queue.getStateInfoForLog(lock));
|
protected_queue.getStateInfoForLog(lock));
|
||||||
|
|
||||||
return probationary_limit_satisfied && protected_limit_satisfied;
|
if (probationary_desired_size_status == DesiredSizeStatus::SUCCESS)
|
||||||
|
return protected_desired_size_status;
|
||||||
|
else
|
||||||
|
return probationary_desired_size_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SLRUFileCachePriority::downgrade(IteratorPtr iterator, const CachePriorityGuard::Lock & lock)
|
void SLRUFileCachePriority::downgrade(IteratorPtr iterator, const CachePriorityGuard::Lock & lock)
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
const UserID & user_id,
|
const UserID & user_id,
|
||||||
const CachePriorityGuard::Lock &) override;
|
const CachePriorityGuard::Lock &) override;
|
||||||
|
|
||||||
bool collectCandidatesForEviction(
|
DesiredSizeStatus collectCandidatesForEviction(
|
||||||
size_t desired_size,
|
size_t desired_size,
|
||||||
size_t desired_elements_count,
|
size_t desired_elements_count,
|
||||||
size_t max_candidates_to_evict,
|
size_t max_candidates_to_evict,
|
||||||
|
Loading…
Reference in New Issue
Block a user