Edit report at https://bugs.php.net/bug.php?id=77478&edit=1
ID: 77478
Comment by: rolmos at endertech dot com
Reported by: anders dot henke at 1und1 dot de
Summary: opcache_reset() does not reset an
opcache.file_cache-based cache
Status: Open
Type: Bug
Package: opcache
Operating System: Linux
PHP Version: 7.3.1
Block user comment: N
Private report: N
New Comment:
This is related to an open report from 2016: https://bugs.php.net/bug.php?id=71749
Also experiencing the same issue. What's the official method to clear the memory & file
cache so that changes are detected by opcache, without a race condition of manually deleting cache
files?
Previous Comments:
------------------------------------------------------------------------
[2019-01-28 11:27:10] spam2 at rhsoft dot net
> To me this is not a bug.
it is
> We depend on opcache.file_cache as a second level fallback
> cache used when PHP-FPM is restarted
irrelevant! when you say "reset cache" you mean exactly that
------------------------------------------------------------------------
[2019-01-28 11:09:20] anders dot henke at 1und1 dot de
The documentation for opcache_reset() clearly states: "reset the entire opcode cache. After
calling opcache_reset(), all scripts will be reloaded and reparsed the next time they are hit."
In contrast to the docs, opcache_reset() does not clear the entire opcode cache, and post at minhost
dot no is using this bug as a feature.
Probably either one of us does need a more adjustable opcache_reset() mechanism (flush everything,
flush only memory, flush only outdated hash directrories from file cache, flush entire file cache)
or an option to have opcache_reset() only flush specific parts of opcache (with a configurable
default).
> Also you can set opcache.revalidate_freq=0 (like we have done), so that the timestamp is
> checked for every updates on every request, that way you will never get code from outdated cache
> objects.
Revalidation does only check for changed files, but is unable to remove objects from cache whose
source has been moved or removed - those files stay in the file cache. And with every PHP version, a
new hash directory is created, resulting in a new copy of the cache. Unless the file cache is
manually purged, a lot of cruft does accumulate in the file cache. A cache should be managed
automatically and not rely on someone manually removing files.
> Also, if you update PHP every month with a new PHP version, then the entire directory for
> file_cache get a new name/number, and you simply delete the old directory after each PHP upgrade.
If the "freshness" of a hash directory were known, opcache_reset() invoked after an update
could also remove the file cache for the outdated hash directories.
Manually removing file caches is a workaround I'm certainly not happy with.
------------------------------------------------------------------------
[2019-01-25 20:58:55] post at minhost dot no
To me this is not a bug. We depend on opcache.file_cache as a second level fallback cache used when
PHP-FPM is restarted, so that even when opcache in memory is empty, the first hit will be from file
cache.
If opcache_reset is changed so that the files in opcache.file_cache is emptied every time PHP-FPM is
restarted, that would be very bad, as it would defeat the purpose of having opcache.file_cache as
second level fallback cache.
Also you can set opcache.revalidate_freq=0 (like we have done), so that the timestamp is checked for
every updates on every request, that way you will never get code from outdated cache objects.
Also, if you update PHP every month with a new PHP version, then the entire directory for file_cache
get a new name/number, and you simply delete the old directory after each PHP upgrade.
I ask that the current behavior is not changed, as we very much depend on having opcache.file_cache
as a second level fallback cache, so that first request when opcache in memory is empty, is from the
opcache.file_cache
------------------------------------------------------------------------
[2019-01-17 12:28:37] anders dot henke at 1und1 dot de
Description:
------------
From PHP 7.0 on, PHP's opcache includes a file-cache as an optional overflow mechanism and
optionally as the only kind of opcache storage (opcache.file_cache_only=1). The later is interesting
in CGI-mode, where shared memory does not survive a single PHP run.
PHP's opcache does provide a function opcache_reset() to "reset the entire opcode cache.
After calling opcache_reset(), all scripts will be reloaded and reparsed the next time they are
hit.".
This function may be called explicitely (e.g. during software deployment) to clear any caches and
remove accumulated stale cache objects who are no longer being accessed. Whenever a file-based
opcache storage is being added to Opcache, opcache_reset() does only reset a shared memory-based
opcache, but does not reset any file-based opcache storage.
In a performance-optimized setup, a user may use shared-memory-based opcache with file-based opcache
storage as a fallback, disable automatic revalidation and manually perform opcache_reset() during
the deployment process. In such a situation, opcache_reset() returns true and restarts the shared
memory-based storage, but does not remove any objects from the file-based opcache storage. This
possibly might result in running code from outdated cache objects.
Test script:
---------------
php.ini:
---cut
zend_extension=opcache.so;
opcache.enable=1;
opcache.revalidate_freq=180;
opcache.validate_timestamps=2;
opcache.file_cache=/var/tmp/opcache;
opcache.file_cache_only=1;
---cut
clear.php:
---cut
<pre>
<?php
echo "**Before Clear Opcache:\n";
system('ls -lRt ' . ini_get('opcache.file_cache'));
echo "\n\n**Clear Opcache: ";
var_dump(opcache_reset());
echo "\n";
echo "**After Clear Opcache:\n";
system('ls -lRt ' . ini_get('opcache.file_cache'));
?>
</pre>
---cut
Expected result:
----------------
http://php.net/manual/en/function.opcache-reset.php
states "This function resets the entire opcode cache. After calling opcache_reset(), all
scripts will be reloaded and reparsed the next time they are hit.
According to my reading, "reset the entire opcache" does also include the file-based
opcache.
In my test script above, the actual content "before" and "after" opcache_reset()
stays the same.
Actual result:
--------------
opcache_reset() does not affect a file-based opcache at all and only restarts the
shared-memory-based opcache.
In a file_cache_only-configuration, opcache_reset() does not reset the file-based opcache, but
returns "false", which should only happen when opcache is disabled.
According to phpinfo(), opcache is enabled and running.
In a overflow/fallback configuration, opcache_reset() does return true, but will only restart the
shared memory storage and not reset any file-based opcache storage. Depending on the overall
configuration, this might result in running cached but outdated code. Such an issue has also been
reported in bug #75670.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=77478&edit=1