From 3b4823d89c03e54917ce6844dfbd227c8b4d6adc Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 12 Sep 2014 23:33:18 -0700 Subject: [PATCH] add function to invalidate one opcache file, use it if possible #9885 Issue #9885 appears to be triggered by ownCloud invalidating the entire PHP opcache. Testing indicates it can be avoided by only invalidating the single file that was written from the opcache, instead of clearing the whole thing. In general it is more efficient to invalidate only the single file that was changed, rather than the whole cache. This adds a deleteFromOpcodeCache() function which invalidates a single file from the opcache if possible, returning true if the underlying function returns true (which may mean 'success', or 'file does not exist', or 'file exists but is not in opcache', all of which are OK to treat as good for our purposes). It also changes writeData() in config.php to try using deleteFromOpcodeCache() and only fall back on clearOpcodeCache() if that fails. --- lib/private/config.php | 7 +++++-- lib/private/util.php | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/private/config.php b/lib/private/config.php index f0548442ab5..8bb2a5c48d1 100644 --- a/lib/private/config.php +++ b/lib/private/config.php @@ -207,8 +207,11 @@ class Config { flock($filePointer, LOCK_UN); fclose($filePointer); - // Clear the opcode cache - \OC_Util::clearOpcodeCache(); + // Try invalidating the opcache just for the file we wrote... + if (!\OC_Util::deleteFromOpcodeCache($this->configFilename)) { + // But if that doesn't work, clear the whole cache. + \OC_Util::clearOpcodeCache(); + } } } diff --git a/lib/private/util.php b/lib/private/util.php index bee0a579192..fa0c6f13c9a 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -1249,6 +1249,31 @@ class OC_Util { return $theme; } + /** + * Clear a single file from the opcode cache + * This is useful for writing to the config file + * in case the opcode cache does not re-validate files + * Returns true if successful, false if unsuccessful: + * caller should fall back on clearing the entire cache + * with clearOpcodeCache() if unsuccessful + * + * @return bool true if underlying function returns true, otherwise false + */ + public static function deleteFromOpcodeCache($path=NULL) { + $ret = false; + if ($path) { + // APC >= 3.1.1 + if (function_exists('apc_delete_file')) { + $ret = @apc_delete_file($path); + } + // Zend OpCache >= 7.0.0, PHP >= 5.5.0 + if (function_exists('opcache_invalidate')) { + $ret = opcache_invalidate($path); + } + } + return $ret; + } + /** * Clear the opcode cache if one exists * This is necessary for writing to the config file -- 2.39.5