Skip to content

Commit f26d563

Browse files
authoredFeb 26, 2025
Fix apc_sma_get_avail_size() to look for a contiguous block of memory to make expunge more reliable (#532)
apc_sma_get_avail_size() is used by apc_cache_default_expunge() to check whether enough memory is available to store a new cache entry after expired entries are removed. If there is not enough memory available, a real expunge is performed to be able to store the new entry. The problem is that apc_sma_get_avail_size() only checks the total amount of available memory, which is usually divided into several fragments of memory. However, we need a contiguous block of memory to store a cache entry. This pull request fixes apc_sma_get_avail_size() to check if a continuous block of memory is available to store a new entry, which solves the problem. Prior to this fix, the result was that in situations with fragmentation, new cache entries cannot be saved and PHP functions such as apcu_store() return false, which is not the expected behavior.
1 parent 0415f0a commit f26d563

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed
 

‎apc_sma.c

+21-3
Original file line numberDiff line numberDiff line change
@@ -631,11 +631,29 @@ PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size) {
631631
int32_t i;
632632

633633
for (i = 0; i < sma->num; i++) {
634-
sma_header_t* header = SMA_HDR(sma, i);
635-
if (header->avail > size) {
636-
return 1;
634+
sma_header_t *shmaddr = SMA_HDR(sma, i);
635+
636+
/* If total size of available memory is too small, we can skip the contiguous-block check */
637+
if (shmaddr->avail < size) {
638+
continue;
639+
}
640+
641+
SMA_LOCK(sma, i);
642+
block_t *cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t)));
643+
644+
/* Look for a contiguous block of memory */
645+
while (cur->fnext) {
646+
cur = BLOCKAT(cur->fnext);
647+
648+
if (cur->size >= size) {
649+
SMA_UNLOCK(sma, i);
650+
return 1;
651+
}
637652
}
653+
654+
SMA_UNLOCK(sma, i);
638655
}
656+
639657
return 0;
640658
}
641659

‎apc_sma.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ PHP_APCU_API void apc_sma_free_info(apc_sma_t* sma, apc_sma_info_t* info);
138138
PHP_APCU_API size_t apc_sma_get_avail_mem(apc_sma_t* sma);
139139

140140
/*
141-
* apc_sma_api_get_avail_size will return true if at least size bytes are available to the sma
141+
* apc_sma_api_get_avail_size will return true if at least size contiguous bytes are available to the sma
142142
*/
143143
PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size);
144144

‎tests/apc_020.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ apc.shm_size=1M
1717
apcu_store("no_ttl_unaccessed", 12);
1818
apcu_store("no_ttl_accessed", 24);
1919
apcu_store("ttl", 42, 3);
20-
apcu_store("dummy", "xxx");
20+
apcu_store("dummy", str_repeat('x', 1000));
2121

2222
apcu_inc_request_time(1);
2323
apcu_fetch("no_ttl_accessed");

0 commit comments

Comments
 (0)
Failed to load comments.