phpwindowsiisapcu

APCu Cached Variables - Not remaining in cache as expected


This is my server setup

General Cache Information

APCu Version    5.1.21
PHP Version 8.1.23
APCu Host   *server.url*
Server Software Microsoft-IIS/10.0
Shared Memory   1 Segment(s) with 32.0 MBytes
(IPC shared memory)
Start Time  2023/09/28 23:50:34
Uptime  1 hour and 3 minutes

Runtime Settings

apc.coredump_unmap  0
apc.enable_cli  0
apc.enabled 1
apc.entries_hint    4096
apc.gc_ttl  3600
apc.preload_path    
apc.serializer  php
apc.shm_segments    1
apc.shm_size    32M
apc.slam_defense    0
apc.smart   0
apc.ttl 3600
apc.use_request_time    0

Example PHP Code:

datastore class configuration array (snippet) This is returning the correct value, so as far as I can tell, this is not the issue

datastore::$configuration['cache']          = array(
                                                'data interval'              => 300, //

I have encapsulated the apcu cache functions into a class, this is a snippet from that class.

class cache {
    
    public static $name;
...
    public static function setCacheArray($name, $data, $ttl){
        apcu_store($name, $data, $ttl);
    }

...
    public static function cacheItemExists(){
        return apcu_exists(cache::$name);
    }
...
    public static function returnCacheSharedMemoryInfo(){
        return apcu_sma_info();
    }
...
    public static function returnCacheInfo(){
        return apcu_cache_info();
    }

utility class snippet

class utility{
    public static $array;
...
    public static function prettyPrintArray(){
        return "<pre>".print_r(utility::$array, true)."</pre>";
    }

apuc config from phpinfo (image attached) enter image description here

calling the class method from a script

cache::$name = 'test';
if(cache::cacheItemExists()){
    # item exists already, so do some work
    print cache::$name." already exists<br />";
}else{
    print cache::$name." does not exists - set data for cache item: 'test'<br />";
    cache::setCacheArray('test', 'this is a test', 3600);
}

utility::$array = cache::returnCacheInfo();
print utility::prettyPrintArray();
utility::$array = cache::returnCacheSharedMemoryInfo();
print utility::prettyPrintArray();

output from script

APCu is installed and enabled.
- Configuration Interval: 86400
- Data Interval: 300
- Configuration Timestamp:
- Data Timestamp:
*test does not exists - set data for cache item: 'test'*
Array
(
    [num_slots] => 4099
    [ttl] => 3600
    [num_hits] => 0
    [num_misses] => 2
    [num_inserts] => 1
    [num_entries] => 1
    [expunges] => 0
    [start_time] => 1695910174
    [mem_size] => 168
    [memory_type] => IPC shared
    [cache_list] => Array
        (
            [0] => Array
                (
                    [info] => test
                    [ttl] => 3600
                    [num_hits] => 0
                    [mtime] => 1695914146
                    [creation_time] => 1695914146
                    [deletion_time] => 0
                    [access_time] => 1695914146
                    [ref_count] => 0
                    [mem_size] => 168
                )

        )

    [deleted_list] => Array
        (
        )

    [slot_distribution] => Array
        (
            [122] => 1
        )

)
Array
(
    [num_seg] => 1
    [seg_size] => 33554344
    [avail_mem] => 33521208
    [block_lists] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [size] => 33521176
                            [offset] => 33192
                        )

                )

        )

)

What I am expecting is the cache value to remain for the duration of the TTL which is set in the call to:

cache::setCacheArray() method

Whilst this initially appears to work, it takes 2 refreshes of the page to see the msg:

test already exists
Array
(
    [num_slots] => 4099
    [ttl] => 3600
    [num_hits] => 0
    [num_misses] => 4
    [num_inserts] => 1
    [num_entries] => 1
    [expunges] => 0
    [start_time] => 1695910837
    [mem_size] => 168
    [memory_type] => IPC shared
    [cache_list] => Array
        (
            [0] => Array
                (
                    [info] => test
                    [ttl] => 3600
                    [num_hits] => 0
                    [mtime] => 1695914537
                    [creation_time] => 1695914537
                    [deletion_time] => 0
                    [access_time] => 1695914537
                    [ref_count] => 0
                    [mem_size] => 168
                )

        )

It also takes 2 refreshes of apc.php on the User Cache Entries page to see the data appear.

When I rerun the script I get the following:

test already exists
Array
(
    [num_slots] => 4099
    [ttl] => 3600
    [num_hits] => 0
    [num_misses] => 4
    [num_inserts] => 1
    [num_entries] => 1
    [expunges] => 0
    [start_time] => 1695910837
    [mem_size] => 168
    [memory_type] => IPC shared
    [cache_list] => Array
        (
            [0] => Array
                (
                    [info] => test
                    [ttl] => 3600
                    [num_hits] => 0
                    [mtime] => 1695914537
                    [creation_time] => 1695914537
                    [deletion_time] => 0
                    [access_time] => 1695914537
                    [ref_count] => 0
                    [mem_size] => 168
                )

        )

On a third refresh of the apc.php User Cache Entries page (within the configured ttl time frame), the data in cache simply dissapears. The same thing occurs on the third reload of the script.

It seems the cache is suddenly cleared!

I read somewhere that I needed to ensure that the c:\windows\temp directory required permissions from the IIS_IUSRS account, which IIS runs under. I set the appropriate permissions, however nothing changes with regards to the result I am getting.

I tried a very simple version of the apcu script to see if I could replicate the behaviour

<?php
if(apcu_exists('test2')){
    print "test already exists<br />";

}else{
    apcu_store("test2", "this is a test", 3600);
}

print "<pre>".print_r(apcu_cache_info(), true)."</pre>";
print "<pre>".print_r(apcu_sma_info(), true)."</pre>";
?>

Ended up with exactly the same result.

Hopefully I am doing something incorrectly and this behaviour can be resolved with a change to the configuration or script.

Does anyone have any thoughts, experience or ideas why this might be happening?


Solution

  • What I was actually after, is not possible with APCu, at least on Windows.

    I ended up building my own lightweight c# caching system which can be accessed by any PHP process either via a json file or from RAM via a web request.

    Edit: To put some context around this, I was trying to cache the results of multiple MySQL queries so I didn't need to keep hitting the DB.