From afd1f9c5ab403eb37d5c352dbda6993867303f06 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 8 Sep 2025 16:07:26 -0400 Subject: [PATCH] Refactor(APCu): clarity, comments, & streamlining Signed-off-by: Josh --- lib/private/Memcache/APCu.php | 163 +++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 60 deletions(-) diff --git a/lib/private/Memcache/APCu.php b/lib/private/Memcache/APCu.php index 937f8a863ab..f90fbdf66d8 100644 --- a/lib/private/Memcache/APCu.php +++ b/lib/private/Memcache/APCu.php @@ -7,24 +7,33 @@ */ namespace OC\Memcache; -use bantu\IniGetWrapper\IniGetWrapper; use OCP\IMemcache; class APCu extends Cache implements IMemcache { use CASTrait { cas as casEmulated; } - use CADTrait; + /** + * Fetches a value from the cache. + * + * @param string $key + * @return mixed|null Value if found, null otherwise + */ public function get($key) { $result = apcu_fetch($this->getPrefix() . $key, $success); - if (!$success) { - return null; - } - return $result; + return $success ? $result : null; } + /** + * Stores a value in the cache. + * + * @param string $key + * @param mixed $value + * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 (24h) + * @return bool + */ public function set($key, $value, $ttl = 0) { if ($ttl === 0) { $ttl = self::DEFAULT_TTL; @@ -32,33 +41,59 @@ class APCu extends Cache implements IMemcache { return apcu_store($this->getPrefix() . $key, $value, $ttl); } + /** + * Checks if a given key exists in the cache. + * + * @param string $key + * @return bool + */ public function hasKey($key) { return apcu_exists($this->getPrefix() . $key); } - + + /** + * Removes a value from the cache. + * + * @param string $key + * @return bool + */ public function remove($key) { return apcu_delete($this->getPrefix() . $key); } + /** + * Clears all cache entries that match the given prefix. + * + * @param string $prefix + * @return bool|int + */ public function clear($prefix = '') { - $ns = $this->getPrefix() . $prefix; - $ns = preg_quote($ns, '/'); - if (class_exists('\APCIterator')) { - $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY); - } else { - $iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY); - } - return apcu_delete($iter); + /** + * Note: Prefixes/namespaces in caching are currently inconsistent/confusing. + * There are multiple levels (instance, user, app/use case) which may overlap. + * Also, other implementations (e.g., MemCached) clear everything regardless + * of prefix. + * TODO: Standardize prefix naming and document any differences across cache + * backends. + */ + $combinedNamespace = preg_quote($this->getPrefix() . $prefix, '/'); + $iterator = new \APCUIterator( + // only care about keys that start with our $combinedNamespace + '/^' . $combinedNamespace . '/', + // only return the key names when interating + APC_ITER_KEY, + ); + return apcu_delete($iterator); } - /** - * Set a value in the cache if it's not already stored - * - * @param string $key - * @param mixed $value - * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 - * @return bool - */ + /** + * Adds a key to the cache only if it does not already exist. + * + * @param string $key + * @param mixed $value + * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 (24h) + * @return bool False if key already exists (new value is ignored) + */ public function add($key, $value, $ttl = 0) { if ($ttl === 0) { $ttl = self::DEFAULT_TTL; @@ -66,59 +101,67 @@ class APCu extends Cache implements IMemcache { return apcu_add($this->getPrefix() . $key, $value, $ttl); } - /** - * Increase a stored number - * - * @param string $key - * @param int $step - * @return int | bool - */ + /** + * Increments a stored number. + * + * If the key does not exist, it is created and set to `0` before + * performing the increment (i.e. returning a value of `1`). + * + * The TTL is left alone on preexisting keys, but newly created keys + * automatically get assigned a TTL of self::DEFAULT_TTL. + * + * @param string $key + * @param int $step + * @return int|bool New value on success, false on failure + */ public function inc($key, $step = 1) { - $success = null; + $success = null; // don't care return apcu_inc($this->getPrefix() . $key, $step, $success, self::DEFAULT_TTL); } - /** - * Decrease a stored number + /** + * Decrements a stored number. * - * @param string $key - * @param int $step - * @return int | bool - */ + * If the key does not exist, false is returned and the operation + * does not take place. This differs from `inc()` above for unknown reasons, + * but it does match the interface and other implementations. + * + * @param string $key + * @param int $step + * @return int|bool New value on success, false if key does not exist + */ public function dec($key, $step = 1) { - return apcu_exists($this->getPrefix() . $key) - ? apcu_dec($this->getPrefix() . $key, $step) - : false; + return $this->hasKey($key) ? apcu_dec($this->getPrefix() . $key, $step) : false; } /** - * Compare and set - * - * @param string $key - * @param mixed $old - * @param mixed $new - * @return bool - */ + * Compare and set operation (CAS). + * + * Sets $key's value to $new IF its current value matches $old. + * Uses APCu native CAS for integers, otherwise falls back to emulated CAS. + * + * @param string $key + * @param mixed $old + * @param mixed $new + * @return bool + */ public function cas($key, $old, $new) { - // apc only does cas for ints - if (is_int($old) and is_int($new)) { + // APCu only does cas for ints + if (is_int($old) && is_int($new)) { return apcu_cas($this->getPrefix() . $key, $old, $new); } else { return $this->casEmulated($key, $old, $new); } } + /** + * Checks if APCu is usable. + * + * @return bool + */ public static function isAvailable(): bool { - if (!extension_loaded('apcu')) { - return false; - } elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enabled')) { - return false; - } elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enable_cli') && \OC::$CLI) { - return false; - } elseif (version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1) { - return false; - } else { - return true; - } + return function_exists('apcu_enabled') + && apcu_enabled() + && version_compare(phpversion('apcu'), '5.1.19', '>='); } }