{"id":16915881,"url":"https://github.com/tysonandre/immutable_cache-pecl","last_synced_at":"2025-06-30T14:03:29.496Z","repository":{"id":62003353,"uuid":"556081294","full_name":"TysonAndre/immutable_cache-pecl","owner":"TysonAndre","description":"Prototype PECL for faster immutable caching (fork of the APCu PECL)","archived":false,"fork":false,"pushed_at":"2023-09-16T16:24:51.000Z","size":1804,"stargazers_count":23,"open_issues_count":9,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-18T10:45:46.915Z","etag":null,"topics":["cache","pecl","php"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TysonAndre.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-23T02:29:01.000Z","updated_at":"2024-02-07T04:42:00.000Z","dependencies_parsed_at":"2024-10-28T13:16:00.999Z","dependency_job_id":"c347b90d-4800-4734-8d91-2b4075bd0c79","html_url":"https://github.com/TysonAndre/immutable_cache-pecl","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fimmutable_cache-pecl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fimmutable_cache-pecl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fimmutable_cache-pecl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fimmutable_cache-pecl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TysonAndre","download_url":"https://codeload.github.com/TysonAndre/immutable_cache-pecl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244944378,"owners_count":20536290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","pecl","php"],"created_at":"2024-10-13T19:23:16.572Z","updated_at":"2025-03-22T10:32:39.661Z","avatar_url":"https://github.com/TysonAndre.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"immutable\\_cache\n================\n\n[![Build Status](https://github.com/TysonAndre/immutable_cache-pecl/actions/workflows/config.yml/badge.svg?branch=main)](https://github.com/TysonAndre/immutable_cache-pecl/actions/workflows/config.yml?query=branch%3Amain)\n[![Build status (Windows)](https://ci.appveyor.com/api/projects/status/7kccfd2a5i4q58ku/branch/main?svg=true)](https://ci.appveyor.com/project/TysonAndre/immutable-cache-pecl/branch/main)\n\nThe [`immutable_cache` PECL](https://pecl.php.net/package/immutable_cache) adds functionality similar to APCu,\nbut with immutable values (either the values themselves or an immutable serialized copy of mutable values is stored in the shared memory region)\n\nSee [the installing section](#installing) for installation instructions.\n\nThis is a fork of the original [APCu PECL](https://github.com/krakjoe/apcu)\n\nFeatures:\n\n- Returns the original persistent strings/arrays rather than a copy (for arrays that don't contain objects or PHP references)\n\n  (not possible in a **mutable** in-memory pool with [APCu](https://github.com/krakjoe/apcu) due to eviction always being possible in APCu)\n\n  This is instantaneous regardless of how large the array or strings are.\n- Reuses immutable values if they were fetched from immutable_cache and stored again.\n\nPlanned but unimplemented features:\n\n- Aggressively deduplicate values across cache entries (not possible in APCu due to the need to cache entries separately)\n\nBenefits:\n\n- You can be certain that a value added to the cache doesn't get removed.\n- You can efficiently fetch entire immutable arrays or strings without copying or using extra memory\n  in cases where the serializer is not required.\n\n  (APCu needs to make copies of all strings and arrays in case of a cache clear during a request)\n\nCaveats:\n\n- APCu will also clear the shared memory cache as a way to recover from deadlocks or processes crashing while holding the shared memory lock, which should be rare (e.g. a process getting killed or crashing while copying values).\n  immutable_cache will never clear the shared memory cache.\n\nFeatures\n========\n\n`immutable_cache` is an in-memory key-value store for PHP. Keys are of type string and values can be any PHP variables.\n\n### API reference\n\nThis provides an API similar to a subset of the functions in https://php.net/apcu , but does not allow for modifying, deleting, incrementing, etc. on a created key.\n\nWhen storing mutable values such as objects, it will instead call PHP's serialize() on the entire object.\nEach retrieval will call unserialize() and return different values when the underlying value is mutable.\n\n```php\n\u003c?php\n/**\n * Returns whether immutable_cache is usable in the current environment.\n */\nfunction immutable_cache_enabled(): bool {}\n\n/**\n * Cache a new variable in the immutable_cache data store.\n * Does nothing if the entry already exists.\n *\n * @param array|string $key\n */\nfunction immutable_cache_add($key, mixed $value = UNKNOWN): array|bool {}\n\n/**\n * Fetch a stored variable from the cache.\n *\n * @param array|string $key\n * @param bool $success set to true on success.\n */\nfunction immutable_cache_fetch($key, \u0026$success = null): mixed {}\n\n/**\n * Returns whether a cache entry exists for the array/string $key\n * @param array|string $key\n */\nfunction immutable_cache_exists($key): array|bool {}\n\n/**\n * Retrieves information about the immutable_cache data store.\n *\n * @param bool $limited if true, then omit information about cache entries\n */\nfunction immutable_cache_cache_info(bool $limited = false): array|false {}\n\n/**\n * Get detailed information about the given cache key\n */\nfunction immutable_cache_key_info(string $key): ?array {}\n\n/**\n * Get immutable_cache Shared Memory Allocation information\n */\nfunction immutable_cache_sma_info(bool $limited = false): array|false {}\n```\n\n### Ini settings\n\nSimilar to https://www.php.net/manual/en/apcu.configuration.php\n\n- `immutable_cache.enabled` (bool, defaults to 1(on))\n- `immutable_cache.enable_cli` (bool, defaults to 0(off))\n- `immutable_cache.shm_size` (defaults to 256M)\n- `immutable_cache.entries_hint` (size of the hash table. If this is too small, uses of the immutable cache will take longer from traversing a longer linked list to find the entries)\n- `immutable_cache.serializer` (currently `php` or `default`. Defaults to `default` (Assumes the bugs with `serializer=default` were fixed in the upstream APCu 5.1.20 release). This is used to serialize data that doesn't have an immutable representation (e.g. objects, references (for now, it isn't converted)))\n\n\n\nThis is an immutable cache where entries can't be removed, so there is no need for ttl or gc_ttl.\n\n### Benefits\n\nImmutability allows `immutable_cache` to keep strings and arrays in shared memory, without making a copy.\nDifferent processes (e.g. from apache worker pools) or threads (in ZTS builds) would\nall be performing read-only access to the same constant arrays (like they would with opcache)\n\nOptimizations\n=============\n\n### Reducing memory usage\n\nTo reduce the total memory this uses, compile this with support for the igbinary PECL and enable `immutable_cache.serializer=igbinary`. See https://github.com/igbinary/igbinary#igbinary and https://github.com/igbinary/igbinary#installing\n\n1. Install `igbinary`\n2. Compile and install `immutable_cache`, configuring it `configure --enable-immutable-cache-igbinary`\n3. Set `immutable_cache.serializer=igbinary` in your php.ini settings.\n\nIf this is done properly, `phpinfo()` will show igbinary as an available serializer for `immutable_cache`.\n\nNote that arrays of non-objects/non-references will take longer to decode when using `php` or `igbinary` (faster than `php` in most cases) because they need to be unserialized.\n\n### Miscellaneous\n\nWhen using `immutable_cache.serializer=default`, `immutable_cache` will reuse arrays/strings that were fetched from `immutable_cache` with `immutable_cache_fetch` (i.e. in the shared memory region managed by `immutable_cache`), because they're guaranteed to be immutable.\n\nSo for this example, `myarrayclone` is using very little memory apart from managing the cache entry.\n\n```php\n\u003c?php\nprintf(\"immutable_cache.serializer=%s\\n\", ini_get('immutable_cache.serializer'));\n$array = [];\nfor ($i = 0; $i \u003c 16; $i++) {\n    $array[\"key$i\"] = \"value$i\";\n}\n\nimmutable_cache_add('myarray', $array);\nimmutable_cache_add('myarrayclone', immutable_cache_fetch('myarray'));\nforeach (immutable_cache_cache_info()['cache_list'] as $entry) {\n    printf(\"%12s memory usage: %d bytes\\n\", $entry['info'], $entry['mem_size']);\n}\n/*\nimmutable_cache.serializer=default\n     myarray memory usage: 1816 bytes\nmyarrayclone memory usage: 104 bytes\n */\n```\n\nNote that opcache does not expose any APIs (that I know of) to check if an immutable array/string is from opcache's shared memory, which would allow further memory sharing.\n\n### Preloading\n\nSimilarly to APCu, `immutable_cache.preload=/path/to/directory` can point to files in `/path/to/directory/*.data` containing PHP [serialize()d](https://www.php.net/serialize) data to unserialize before running the application.\n\nThis can be useful if you have large objects you want in the cache before a web server starts responding to requests.\n\nBenchmarks\n==========\n\nNote that when the data is completely immutable (i.e. does not need to call the php serializer for anything and `immutable_cache.serializer=default` (default) is used),\nvalues can be stored in shared memory and retrieved in constant time from\n`immutable_cache` without any modification (e.g. very large arrays, large strings, etc).\ni.e. these benchmarks have the same throughput regardless of the size of the data.\n\nBenchmarks were run with opcache enabled in php 8.2 on a computer with 4 physical cores and 8 logical cores (with hyperthreading).\n\n### Fetching an associative array of size 1000\n\n[`BENCHMARK_N=40000 BENCHMARK_ARRAY_SIZE=1000 php benchmark_shm.php`](./benchmark_shm.php)\nusing `immutable_cache.serializer=default`.\n\nThis benchmarks unserializing a 1000 element array of the form `{...,\"key999\":\"myValue999\"}` with 4 concurrently running processes,\nand is around 240 times faster than APCu.\n\n```\napc.serializer = default\nimmutable_cache.serializer = default\nimmutable_cache Elapsed: 0.007205 throughput    5551667 / second\nimmutable_cache Elapsed: 0.007373 throughput    5425447 / second\nimmutable_cache Elapsed: 0.007700 throughput    5195134 / second\nimmutable_cache Elapsed: 0.007252 throughput    5515629 / second\nAPCu            Elapsed: 1.787497 throughput      22378 / second\nAPCu            Elapsed: 1.788314 throughput      22367 / second\nAPCu            Elapsed: 1.791437 throughput      22328 / second\nAPCu            Elapsed: 1.796633 throughput      22264 / second\n```\n\n### Fetching an associative array of size 8\n\nRunning [`benchmark_shm.php`](./benchmark_shm.php), this is around 3.7 times as fast\n\n```\nE.g. to retrieve multiple versions of the fake cached config\n{\"key0\":\"myValue0\",\"key1\":\"myValue1\",\"key2\":\"myValue2\",\"key3\":\"myValue3\",\"key4\":\"myValue4\",\"key5\":\"myValue5\",\"key6\":\"myValue6\",\"key7\":\"myValue7\"}\nas a php array with 4 processes, repeatedly (with immutable_cache.enable_cli=1, immutable_cache.enabled=1, etc).\n\napc.serializer = default\nimmutable_cache.serializer = default\nimmutable_cache Elapsed: 0.083897 throughput    4767745 / second\nimmutable_cache Elapsed: 0.083710 throughput    4778405 / second\nimmutable_cache Elapsed: 0.085307 throughput    4688932 / second\nimmutable_cache Elapsed: 0.085654 throughput    4669966 / second\nAPCu            Elapsed: 0.317105 throughput    1261412 / second\nAPCu            Elapsed: 0.320551 throughput    1247850 / second\nAPCu            Elapsed: 0.322219 throughput    1241391 / second\nAPCu            Elapsed: 0.331782 throughput    1205612 / second\n```\n\n### Fetching a string of size 100000\n\n`BENCHMARK_ARRAY_SIZE=100000 BENCHMARK_USE_STRING_INSTEAD=1 php benchmark_shm.php`\nwas 20 times faster for retrieving strings of size 100000 with 4 processes running in parallel.\n(APCu must copy the entire string when retrieving strings in case of a cache clear.)\n\n```\nimmutable_cache Elapsed: 0.081627 throughput    4900352 / second\nimmutable_cache Elapsed: 0.082891 throughput    4825640 / second\nimmutable_cache Elapsed: 0.081830 throughput    4888166 / second\nimmutable_cache Elapsed: 0.082876 throughput    4826462 / second\nAPCu            Elapsed: 1.655446 throughput     241627 / second\nAPCu            Elapsed: 1.657670 throughput     241303 / second\nAPCu            Elapsed: 1.662154 throughput     240652 / second\nAPCu            Elapsed: 1.684609 throughput     237444 / second\n```\n\n### Fetching a scalar\n\n`BENCHMARK_USE_SCALAR_INSTEAD=1 php benchmark_shm.php` was used to fetch an integer from\n16 different cache keys. Because of the use of fine-grained locks in immutable_cache to avoid contention,\nthere was still a performance improvement (around 2.5x) compared to APCu.\n\n```\nimmutable_cache Elapsed: 0.078275 throughput    5110164 / second\nimmutable_cache Elapsed: 0.080960 throughput    4940725 / second\nimmutable_cache Elapsed: 0.080830 throughput    4948671 / second\nimmutable_cache Elapsed: 0.080430 throughput    4973270 / second\nAPCu            Elapsed: 0.194570 throughput    2055819 / second\nAPCu            Elapsed: 0.198471 throughput    2015405 / second\nAPCu            Elapsed: 0.198798 throughput    2012093 / second\nAPCu            Elapsed: 0.199741 throughput    2002590 / second\n```\n\n### Fetching with `immutable_cache.protect_memory=1`\n\n`php -d immutable_cache.protect_memory=1 benchmark_shm.php` was used to run immutable_cache with the option to protect memory for debugging (this will mark the memory as read-only when not in use.\nA side effect of this is that\n\n1. Read operations stop incrementing counters for cache hits, last access times, etc.\n   So those operations are sped up because processors do less work and caches aren't invalidated by changing these.\n2. Write operations are slower, because mprotect is called.\n\n```\nTesting string-\u003estring array of size 8 with 4 forked processes\nNote that the immutable array and strings part of shared memory in immutable_cache, where apcu must make copies of strings and arrays to account for eviction (and php must free them)\n{\"key0\":\"myValue0\",\"key1\":\"myValue1\",\"key2\":\"myValue2\",\"key3\":\"myValue3\",\"key4\":\"myValue4\",\"key5\":\"myValue5\",\"key6\":\"myValue6\",\"key7\":\"myValue7\"}\n\nimmutable_cache Elapsed: 0.053691 throughput    7450103 / second\nimmutable_cache Elapsed: 0.056164 throughput    7121941 / second\nimmutable_cache Elapsed: 0.054956 throughput    7278549 / second\nimmutable_cache Elapsed: 0.059204 throughput    6756267 / second\nAPCu            Elapsed: 0.318515 throughput    1255828 / second\nAPCu            Elapsed: 0.314734 throughput    1270913 / second\nAPCu            Elapsed: 0.320162 throughput    1249368 / second\nAPCu            Elapsed: 0.327550 throughput    1221189 / second\n```\n\nInstalling\n==========\n\n## Compile immutable_cache in Linux\n\n```\n$ phpize\n$ ./configure\n$ make\n$ make test\n$ make install\n```\n\nAdd the following line to your php.ini\n\n```\nextension=immutable_cache.so\n```\n\n## Compile immutable_cache in Windows\n\nSee https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2#building_pecl_extensions and .appveyor.yml for how to build this.\n\nReporting Bugs\n=============\n\nIf you believe you have found a bug in `immutable_cache`, please open an issue: Include in your report *minimal, executable, reproducing code*.\n\nMinimal: reduce your problem to the smallest amount of code possible; This helps with hunting the bug, but also it helps with integration and regression testing once the bug is fixed.\n\nExecutable: include all the information required to execute the example code, code snippets are not helpful.\n\nReproducing: some bugs don't show themselves on every execution, that's fine, mention that in the report and give an idea of how often you encounter the bug.\n\n__It is impossible to help without reproducing code, bugs that are opened without reproducing code will be closed.__\n\nPlease include version and operating system information in your report.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftysonandre%2Fimmutable_cache-pecl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftysonandre%2Fimmutable_cache-pecl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftysonandre%2Fimmutable_cache-pecl/lists"}