From 464aa04188c42c82f411ac7d43fabf0f6038c98e Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" Date: Sun, 18 Sep 2022 22:46:24 +0800 Subject: fix infinite sleep in performEvictions when have lazyfree jobs (#11237) This bug is introduced in #7653. (Redis 6.2.0) When `server.maxmemory_eviction_tenacity` is 100, `eviction_time_limit_us` is `ULONG_MAX`, and if we cannot find the best key to delete (e.g. maxmemory-policy is `volatile-lru` and all keys with ttl have been evicted), in `cant_free` redis will sleep forever if some items are being freed in the lazyfree thread. --- src/evict.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/evict.c') diff --git a/src/evict.c b/src/evict.c index 3c767a557..45ec95f1f 100644 --- a/src/evict.c +++ b/src/evict.c @@ -595,7 +595,7 @@ int performEvictions(void) { { struct evictionPoolEntry *pool = EvictionPoolLRU; - while(bestkey == NULL) { + while (bestkey == NULL) { unsigned long total_keys = 0, keys; /* We don't want to make local-db choices when expiring keys, @@ -738,12 +738,18 @@ cant_free: /* At this point, we have run out of evictable items. It's possible * that some items are being freed in the lazyfree thread. Perform a * short wait here if such jobs exist, but don't wait long. */ - if (bioPendingJobsOfType(BIO_LAZY_FREE)) { - usleep(eviction_time_limit_us); + mstime_t lazyfree_latency; + latencyStartMonitor(lazyfree_latency); + while (bioPendingJobsOfType(BIO_LAZY_FREE) && + elapsedUs(evictionTimer) < eviction_time_limit_us) { if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { result = EVICT_OK; + break; } + usleep(eviction_time_limit_us < 1000 ? eviction_time_limit_us : 1000); } + latencyEndMonitor(lazyfree_latency); + latencyAddSampleIfNeeded("eviction-lazyfree",lazyfree_latency); } serverAssert(server.core_propagates); /* This function should not be re-entrant */ -- cgit v1.2.1