Skip to content

Commit 9396b94

Browse files
committed
Fix apc_cache_default_expunge() to always remove expired entries
When apc_cache_default_expunge() is called, it now always cleans up expired entries and doesn't skip cleanup anymore, as it is only called when there is not enough memory available to store a cache entry and cleanup is really needed. The skip can happen because the function apc_sma_get_avail_mem() doesn't take into account that a block of contiguous memory is needed. In situations with huge fragmentation, the old behavior can cause apcu to not accept new entries anymore which don't fit into a fragment of available memory. This causes php-functions like apcu_store() to not being able to insert bigger entries, until the cache has filled up enough with small entries to trigger the cleanup. This commit fixes the issue and mostly implements a behavior that should have already been implemented previously according to the header file. This also applies to the smart configuration setting that is now used to tune the probability of a full cache wipe.
1 parent 5f37033 commit 9396b94

File tree

2 files changed

+25
-42
lines changed

2 files changed

+25
-42
lines changed

apc_cache.c

+21-30
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,7 @@ PHP_APCU_API void apc_cache_clear(apc_cache_t* cache)
735735
PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size)
736736
{
737737
time_t t;
738-
size_t suitable = 0L;
739-
size_t available = 0L;
738+
size_t i;
740739

741740
if (!cache) {
742741
return;
@@ -751,43 +750,35 @@ PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size)
751750
return;
752751
}
753752

754-
/* make suitable selection */
755-
suitable = (cache->smart > 0L) ? (size_t) (cache->smart * size) : (size_t) (cache->sma->size/2);
753+
/* smart adjusts the required memory-size, to increase the probability of a full cache wipe */
754+
size = (cache->smart > 0L) ? (size_t) (cache->smart * size) : size;
756755

757756
/* gc */
758757
apc_cache_wlocked_gc(cache);
759758

760-
/* get available */
761-
available = apc_sma_get_avail_mem(cache->sma);
762-
763-
/* check that expunge is necessary */
764-
if (available < suitable) {
765-
size_t i;
766-
767-
/* look for junk */
768-
for (i = 0; i < cache->nslots; i++) {
769-
apc_cache_entry_t **entry = &cache->slots[i];
770-
while (*entry) {
771-
if (apc_cache_entry_expired(cache, *entry, t)) {
772-
apc_cache_wlocked_remove_entry(cache, entry);
773-
continue;
774-
}
775-
776-
/* grab next entry */
777-
entry = &(*entry)->next;
759+
/* remove expired entries */
760+
for (i = 0; i < cache->nslots; i++) {
761+
apc_cache_entry_t **entry = &cache->slots[i];
762+
while (*entry) {
763+
if (apc_cache_entry_expired(cache, *entry, t)) {
764+
apc_cache_wlocked_remove_entry(cache, entry);
765+
continue;
778766
}
779-
}
780767

781-
/* if the cache now has space, then reset last key */
782-
if (apc_sma_get_avail_size(cache->sma, size)) {
783-
/* wipe lastkey */
784-
memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t));
785-
} else {
786-
/* with not enough space left in cache, we are forced to expunge */
787-
apc_cache_wlocked_real_expunge(cache);
768+
/* grab next entry */
769+
entry = &(*entry)->next;
788770
}
789771
}
790772

773+
/* if the cache now has space, then reset last key */
774+
if (apc_sma_get_avail_size(cache->sma, size)) {
775+
/* wipe lastkey */
776+
memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t));
777+
} else {
778+
/* with not enough space left in cache, we are forced to expunge */
779+
apc_cache_wlocked_real_expunge(cache);
780+
}
781+
791782
apc_cache_wunlock(cache);
792783
}
793784
/* }}} */

apc_cache.h

+4-12
Original file line numberDiff line numberDiff line change
@@ -251,20 +251,12 @@ PHP_APCU_API void apc_cache_serializer(apc_cache_t* cache, const char* name);
251251

252252
/* {{{ apc_cache_default_expunge
253253
* Where smart is not set:
254-
* Where no ttl is set on cache:
255-
* 1) Perform cleanup of stale entries
256-
* 2) Expunge if available memory is less than sma->size/2
257-
* Where ttl is set on cache:
258-
* 1) Perform cleanup of stale entries
259-
* 2) If available memory if less than the size requested, run full expunge
254+
* 1) Perform cleanup of stale entries
255+
* 2) If available memory is less than the size requested, run full expunge
260256
*
261257
* Where smart is set:
262-
* Where no ttl is set on cache:
263-
* 1) Perform cleanup of stale entries
264-
* 2) Expunge is available memory is less than size * smart
265-
* Where ttl is set on cache:
266-
* 1) Perform cleanup of stale entries
267-
* 2) If available memory if less than the size requested, run full expunge
258+
* 1) Perform cleanup of stale entries
259+
* 2) If available memory is less than the size requested * smart, run full expunge
268260
*
269261
* The TTL of an entry takes precedence over the TTL of a cache
270262
*/

0 commit comments

Comments
 (0)