From 65b540e6078d0e4ca66d821c9477b357f2270b9b Mon Sep 17 00:00:00 2001 From: Arndt Kaiser <42686074+madmajestro@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:37:04 +0100 Subject: [PATCH 1/2] Fix apc_sma_get_avail_size() to look for a contiguous block of memory apc_sma_get_avail_size() is used by apc_cache_default_expunge() to check if enough memory is available to store the next cache entry. Therefore, it is not enough to check the total amount of available memory. The memory must be available in one contiguous block. --- apc_sma.c | 24 +++++++++++++++++++++--- apc_sma.h | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apc_sma.c b/apc_sma.c index b0bbbc86..a4534012 100644 --- a/apc_sma.c +++ b/apc_sma.c @@ -631,11 +631,29 @@ PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size) { int32_t i; for (i = 0; i < sma->num; i++) { - sma_header_t* header = SMA_HDR(sma, i); - if (header->avail > size) { - return 1; + sma_header_t *shmaddr = SMA_HDR(sma, i); + + /* If total size of available memory is too small, we can skip the contiguous-block check */ + if (shmaddr->avail < size) { + continue; + } + + SMA_LOCK(sma, i); + block_t *cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); + + /* Look for a contiguous block of memory */ + while (cur->fnext) { + cur = BLOCKAT(cur->fnext); + + if (cur->size >= size) { + SMA_UNLOCK(sma, i); + return 1; + } } + + SMA_UNLOCK(sma, i); } + return 0; } diff --git a/apc_sma.h b/apc_sma.h index b4891f5e..6e4998e1 100644 --- a/apc_sma.h +++ b/apc_sma.h @@ -138,7 +138,7 @@ PHP_APCU_API void apc_sma_free_info(apc_sma_t* sma, apc_sma_info_t* info); PHP_APCU_API size_t apc_sma_get_avail_mem(apc_sma_t* sma); /* -* apc_sma_api_get_avail_size will return true if at least size bytes are available to the sma +* apc_sma_api_get_avail_size will return true if at least size contiguous bytes are available to the sma */ PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size); From 12c92acf5693fdd28d6e4710e886a30d5d18a47f Mon Sep 17 00:00:00 2001 From: Arndt Kaiser <42686074+madmajestro@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:54:44 +0100 Subject: [PATCH 2/2] Fix test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory occupied by “dummy” should be large enough for one of the entries inserted by the loop to fit into it. This allows the last inserted record of the loop (which triggers expunge) to replace this entry, which prevents a real_expunge of the whole cache. --- tests/apc_020.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/apc_020.phpt b/tests/apc_020.phpt index ea388d31..7c74ee3d 100644 --- a/tests/apc_020.phpt +++ b/tests/apc_020.phpt @@ -17,7 +17,7 @@ apc.shm_size=1M apcu_store("no_ttl_unaccessed", 12); apcu_store("no_ttl_accessed", 24); apcu_store("ttl", 42, 3); -apcu_store("dummy", "xxx"); +apcu_store("dummy", str_repeat('x', 1000)); apcu_inc_request_time(1); apcu_fetch("no_ttl_accessed");