Browse Source

Merge pull request #11313 from inoas/3.next-ApcuEngine-Improvements

3.next ApcuEngine: More atomic & verbose on failures
Mark Story 8 years ago
parent
commit
e0e40ecd14

+ 9 - 8
src/Cache/Cache.php

@@ -33,28 +33,28 @@ use RuntimeException;
  *
  * ```
  * Cache::config('shared', [
- *    'className' => 'Cake\Cache\Engine\ApcEngine',
+ *    'className' => 'Cake\Cache\Engine\ApcuEngine',
  *    'prefix' => 'my_app_'
  * ]);
  * ```
  *
- * This would configure an APC cache engine to the 'shared' alias. You could then read and write
+ * This would configure an APCu cache engine to the 'shared' alias. You could then read and write
  * to that cache alias by using it for the `$config` parameter in the various Cache methods.
  *
  * In general all Cache operations are supported by all cache engines.
  * However, Cache::increment() and Cache::decrement() are not supported by File caching.
  *
- * There are 5 built-in caching engines:
+ * There are 6 built-in caching engines:
  *
  * - `FileEngine` - Uses simple files to store content. Poor performance, but good for
  *    storing large objects, or things that are not IO sensitive. Well suited to development
  *    as it is an easy cache to inspect and manually flush.
- * - `ApcEngine` - Uses the APC object cache, one of the fastest caching engines.
+ * - `ApcuEngine` - Uses the APCu object cache, one of the fastest caching engines.
  * - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage.
- *   Fast reads/writes, and benefits from memcache being distributed.
- * - `XcacheEngine` - Uses the Xcache extension, an alternative to APC.
+ *    Fast reads/writes, and benefits from memcache being distributed.
+ * - `XcacheEngine` - Uses the Xcache extension, an alternative to APCu.
  * - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher.
- *   This engine is recommended to people deploying on windows with IIS.
+ *    This engine is recommended to people deploying on windows with IIS.
  * - `RedisEngine` - Uses redis and php-redis extension to store cache data.
  *
  * See Cache engine documentation for expected configuration keys.
@@ -76,7 +76,8 @@ class Cache
      * @var array
      */
     protected static $_dsnClassMap = [
-        'apc' => 'Cake\Cache\Engine\ApcEngine',
+        'apc' => 'Cake\Cache\Engine\ApcuEngine', // @deprecated Since 3.6. Use apcu instead.
+        'apcu' => 'Cake\Cache\Engine\ApcuEngine',
         'file' => 'Cake\Cache\Engine\FileEngine',
         'memcached' => 'Cake\Cache\Engine\MemcachedEngine',
         'null' => 'Cake\Cache\Engine\NullEngine',

+ 20 - 1
src/Cache/CacheEngine.php

@@ -38,6 +38,8 @@ abstract class CacheEngine
      *    with either another cache config or another application.
      * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
      *    cache::gc from ever being called automatically.
+     * - `warnOnWriteFailures` Some engines, such as ApcuEngine, may raise warnings on
+     *    write failures.
      *
      * @var array
      */
@@ -45,7 +47,8 @@ abstract class CacheEngine
         'duration' => 3600,
         'groups' => [],
         'prefix' => 'cake_',
-        'probability' => 100
+        'probability' => 100,
+        'warnOnWriteFailures' => true,
     ];
 
     /**
@@ -276,4 +279,20 @@ abstract class CacheEngine
 
         return $this->_config['prefix'] . $key;
     }
+
+    /**
+     * Cache Engines may trigger warnings if they encounter failures during operation,
+     * if option warnOnWriteFailures is set to true.
+     *
+     * @param string $message The warning message.
+     * @return void
+     */
+    protected function warning($message)
+    {
+        if ($this->getConfig('warnOnWriteFailures') !== true) {
+            return;
+        }
+
+        triggerWarning($message);
+    }
 }

+ 2 - 222
src/Cache/Engine/ApcEngine.php

@@ -14,225 +14,5 @@
  */
 namespace Cake\Cache\Engine;
 
-use APCUIterator;
-use Cake\Cache\CacheEngine;
-
-/**
- * APC storage engine for cache
- */
-class ApcEngine extends CacheEngine
-{
-
-    /**
-     * Contains the compiled group names
-     * (prefixed with the global configuration prefix)
-     *
-     * @var string[]
-     */
-    protected $_compiledGroupNames = [];
-
-    /**
-     * Initialize the Cache Engine
-     *
-     * Called automatically by the cache frontend
-     *
-     * @param array $config array of setting for the engine
-     * @return bool True if the engine has been successfully initialized, false if not
-     */
-    public function init(array $config = [])
-    {
-        if (!extension_loaded('apcu')) {
-            return false;
-        }
-
-        parent::init($config);
-
-        return true;
-    }
-
-    /**
-     * Write data for key into cache
-     *
-     * @param string $key Identifier for the data
-     * @param mixed $value Data to be cached
-     * @return bool True if the data was successfully cached, false on failure
-     */
-    public function write($key, $value)
-    {
-        $key = $this->_key($key);
-
-        $expires = 0;
-        $duration = $this->_config['duration'];
-        if ($duration) {
-            $expires = time() + $duration;
-        }
-        apcu_store($key . '_expires', $expires, $duration);
-
-        return apcu_store($key, $value, $duration);
-    }
-
-    /**
-     * Read a key from the cache
-     *
-     * @param string $key Identifier for the data
-     * @return mixed The cached data, or false if the data doesn't exist,
-     *   has expired, or if there was an error fetching it
-     */
-    public function read($key)
-    {
-        $key = $this->_key($key);
-
-        $time = time();
-        $cachetime = (int)apcu_fetch($key . '_expires');
-        if ($cachetime !== 0 && ($cachetime < $time || ($time + $this->_config['duration']) < $cachetime)) {
-            return false;
-        }
-
-        return apcu_fetch($key);
-    }
-
-    /**
-     * Increments the value of an integer cached key
-     *
-     * @param string $key Identifier for the data
-     * @param int $offset How much to increment
-     * @return bool|int New incremented value, false otherwise
-     */
-    public function increment($key, $offset = 1)
-    {
-        $key = $this->_key($key);
-
-        return apcu_inc($key, $offset);
-    }
-
-    /**
-     * Decrements the value of an integer cached key
-     *
-     * @param string $key Identifier for the data
-     * @param int $offset How much to subtract
-     * @return bool|int New decremented value, false otherwise
-     */
-    public function decrement($key, $offset = 1)
-    {
-        $key = $this->_key($key);
-
-        return apcu_dec($key, $offset);
-    }
-
-    /**
-     * Delete a key from the cache
-     *
-     * @param string $key Identifier for the data
-     * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
-     */
-    public function delete($key)
-    {
-        $key = $this->_key($key);
-
-        return apcu_delete($key);
-    }
-
-    /**
-     * Delete all keys from the cache. This will clear every cache config using APC.
-     *
-     * @param bool $check If true, nothing will be cleared, as entries are removed
-     *    from APC as they expired. This flag is really only used by FileEngine.
-     * @return bool True Returns true.
-     */
-    public function clear($check)
-    {
-        if ($check) {
-            return true;
-        }
-        if (class_exists('APCUIterator', false)) {
-            $iterator = new APCUIterator(
-                '/^' . preg_quote($this->_config['prefix'], '/') . '/',
-                APC_ITER_NONE
-            );
-            apcu_delete($iterator);
-
-            return true;
-        }
-        $cache = apcu_cache_info();
-        foreach ($cache['cache_list'] as $key) {
-            if (strpos($key['info'], $this->_config['prefix']) === 0) {
-                apcu_delete($key['info']);
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Write data for key into cache if it doesn't exist already.
-     * If it already exists, it fails and returns false.
-     *
-     * @param string $key Identifier for the data.
-     * @param mixed $value Data to be cached.
-     * @return bool True if the data was successfully cached, false on failure.
-     * @link https://secure.php.net/manual/en/function.apc-add.php
-     */
-    public function add($key, $value)
-    {
-        $key = $this->_key($key);
-
-        $expires = 0;
-        $duration = $this->_config['duration'];
-        if ($duration) {
-            $expires = time() + $duration;
-        }
-        apcu_add($key . '_expires', $expires, $duration);
-
-        return apcu_add($key, $value, $duration);
-    }
-
-    /**
-     * Returns the `group value` for each of the configured groups
-     * If the group initial value was not found, then it initializes
-     * the group accordingly.
-     *
-     * @return array
-     */
-    public function groups()
-    {
-        if (empty($this->_compiledGroupNames)) {
-            foreach ($this->_config['groups'] as $group) {
-                $this->_compiledGroupNames[] = $this->_config['prefix'] . $group;
-            }
-        }
-
-        $groups = apcu_fetch($this->_compiledGroupNames);
-        if (count($groups) !== count($this->_config['groups'])) {
-            foreach ($this->_compiledGroupNames as $group) {
-                if (!isset($groups[$group])) {
-                    apcu_store($group, 1);
-                    $groups[$group] = 1;
-                }
-            }
-            ksort($groups);
-        }
-
-        $result = [];
-        $groups = array_values($groups);
-        foreach ($this->_config['groups'] as $i => $group) {
-            $result[] = $group . $groups[$i];
-        }
-
-        return $result;
-    }
-
-    /**
-     * Increments the group value to simulate deletion of all keys under a group
-     * old values will remain in storage until they expire.
-     *
-     * @param string $group The group to clear.
-     * @return bool success
-     */
-    public function clearGroup($group)
-    {
-        $success = false;
-        apcu_inc($this->_config['prefix'] . $group, 1, $success);
-
-        return $success;
-    }
-}
+// @deprecated Add backwards compat alias.
+class_alias('Cake\Cache\Engine\ApcuEngine', 'Cake\Cache\Engine\ApcEngine');

+ 268 - 0
src/Cache/Engine/ApcuEngine.php

@@ -0,0 +1,268 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.5.4
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Cache\Engine;
+
+use APCUIterator;
+use Cake\Cache\CacheEngine;
+
+/**
+ * APCu storage engine for cache
+ */
+class ApcuEngine extends CacheEngine
+{
+
+    /**
+     * Contains the compiled group names
+     * (prefixed with the global configuration prefix)
+     *
+     * @var string[]
+     */
+    protected $_compiledGroupNames = [];
+
+    /**
+     * Initialize the Cache Engine
+     *
+     * Called automatically by the cache frontend
+     *
+     * @param array $config array of setting for the engine
+     * @return bool True if the engine has been successfully initialized, false if not
+     */
+    public function init(array $config = [])
+    {
+        if (!extension_loaded('apcu')) {
+            return false;
+        }
+
+        return parent::init($config);
+    }
+
+    /**
+     * Write data for key into cache
+     *
+     * @param string $key Identifier for the data
+     * @param mixed $value Data to be cached
+     * @return bool True if the data was successfully cached, false on failure
+     * @link https://secure.php.net/manual/en/function.apcu-store.php
+     */
+    public function write($key, $value)
+    {
+        $key = $this->_key($key);
+
+        $expires = 0;
+        $duration = $this->_config['duration'];
+        if ($duration) {
+            $expires = time() + $duration;
+        }
+
+        $values = [
+            $key . '_expires' => $expires,
+            $key => $value,
+        ];
+
+        $errors = apcu_store($values, null, $duration);
+
+        if ($errors !== []) {
+            $this->warning(
+                sprintf('Failed to store %s into APCu cache.', json_encode($errors))
+            );
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Read a key from the cache
+     *
+     * @param string $key Identifier for the data
+     * @return mixed The cached data, or false if the data doesn't exist,
+     *   has expired, or if there was an error fetching it
+     * @link https://secure.php.net/manual/en/function.apcu-fetch.php
+     */
+    public function read($key)
+    {
+        $key = $this->_key($key);
+
+        $time = time();
+        $success = false;
+        $cachetime = (int)apcu_fetch($key . '_expires', $success);
+        if ($success && $cachetime !== 0 && ($cachetime < $time || ($time + $this->_config['duration']) < $cachetime)) {
+            return false;
+        }
+
+        return apcu_fetch($key);
+    }
+
+    /**
+     * Increments the value of an integer cached key
+     *
+     * @param string $key Identifier for the data
+     * @param int $offset How much to increment
+     * @return bool|int New incremented value, false otherwise
+     * @link https://secure.php.net/manual/en/function.apcu-inc.php
+     */
+    public function increment($key, $offset = 1)
+    {
+        $key = $this->_key($key);
+
+        return apcu_inc($key, $offset);
+    }
+
+    /**
+     * Decrements the value of an integer cached key
+     *
+     * @param string $key Identifier for the data
+     * @param int $offset How much to subtract
+     * @return bool|int New decremented value, false otherwise
+     * @link https://secure.php.net/manual/en/function.apcu-dec.php
+     */
+    public function decrement($key, $offset = 1)
+    {
+        $key = $this->_key($key);
+
+        return apcu_dec($key, $offset);
+    }
+
+    /**
+     * Delete a key from the cache
+     *
+     * @param string $key Identifier for the data
+     * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
+     * @link https://secure.php.net/manual/en/function.apcu-delete.php
+     */
+    public function delete($key)
+    {
+        $key = $this->_key($key);
+
+        return apcu_delete($key);
+    }
+
+    /**
+     * Delete all keys from the cache. This will clear every cache config using APC.
+     *
+     * @param bool $check If true, nothing will be cleared, as entries are removed
+     *    from APC as they expired. This flag is really only used by FileEngine.
+     * @return bool True Returns true.
+     * @link https://secure.php.net/manual/en/function.apcu-cache-info.php
+     * @link https://secure.php.net/manual/en/function.apcu-delete.php
+     */
+    public function clear($check)
+    {
+        if ($check) {
+            return true;
+        }
+        if (class_exists('APCUIterator', false)) {
+            $iterator = new APCUIterator(
+                '/^' . preg_quote($this->_config['prefix'], '/') . '/',
+                APC_ITER_NONE
+            );
+            apcu_delete($iterator);
+
+            return true;
+        }
+
+        $cache = apcu_cache_info(); // Raises warning by itself already
+        foreach ($cache['cache_list'] as $key) {
+            if (strpos($key['info'], $this->_config['prefix']) === 0) {
+                apcu_delete($key['info']);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Write data for key into cache if it doesn't exist already.
+     * If it already exists, it fails and returns false.
+     *
+     * @param string $key Identifier for the data.
+     * @param mixed $value Data to be cached.
+     * @return bool True if the data was successfully cached, false on failure.
+     * @link https://secure.php.net/manual/en/function.apcu-add.php
+     */
+    public function add($key, $value)
+    {
+        $key = $this->_key($key);
+
+        $expires = 0;
+        $duration = $this->_config['duration'];
+        if ($duration) {
+            $expires = time() + $duration;
+        }
+
+        return apcu_add($key, $value, $duration) === true
+            && apcu_add($key . '_expires', $expires, $duration) === true;
+    }
+
+    /**
+     * Returns the `group value` for each of the configured groups
+     * If the group initial value was not found, then it initializes
+     * the group accordingly.
+     *
+     * @return array
+     * @link https://secure.php.net/manual/en/function.apcu-fetch.php
+     * @link https://secure.php.net/manual/en/function.apcu-store.php
+     */
+    public function groups()
+    {
+        if (empty($this->_compiledGroupNames)) {
+            foreach ($this->_config['groups'] as $group) {
+                $this->_compiledGroupNames[] = $this->_config['prefix'] . $group;
+            }
+        }
+
+        $success = false;
+        $groups = apcu_fetch($this->_compiledGroupNames, $success);
+        if ($success && count($groups) !== count($this->_config['groups'])) {
+            foreach ($this->_compiledGroupNames as $group) {
+                if (!isset($groups[$group])) {
+                    $value = 1;
+                    if (apcu_store($group, $value) === false) {
+                        $this->warning(
+                            sprintf('Failed to store key "%s" with value "%s" into APCu cache.', $group, $value)
+                        );
+                    }
+                    $groups[$group] = $value;
+                }
+            }
+            ksort($groups);
+        }
+
+        $result = [];
+        $groups = array_values($groups);
+        foreach ($this->_config['groups'] as $i => $group) {
+            $result[] = $group . $groups[$i];
+        }
+
+        return $result;
+    }
+
+    /**
+     * Increments the group value to simulate deletion of all keys under a group
+     * old values will remain in storage until they expire.
+     *
+     * @param string $group The group to clear.
+     * @return bool success
+     * @link https://secure.php.net/manual/en/function.apcu-inc.php
+     */
+    public function clearGroup($group)
+    {
+        $success = false;
+        apcu_inc($this->_config['prefix'] . $group, 1, $success);
+
+        return $success;
+    }
+}

+ 1 - 1
src/Cache/README.md

@@ -29,7 +29,7 @@ Cache::config('default', [
 
 // Using a fully namespaced name.
 Cache::config('long', [
-    'className' => 'Cake\Cache\Engine\ApcEngine',
+    'className' => 'Cake\Cache\Engine\ApcuEngine',
     'duration' => '+1 week',
     'prefix' => 'my_app_'
 ]);

+ 25 - 0
src/Core/functions.php

@@ -249,6 +249,31 @@ if (!function_exists('env')) {
 
 }
 
+if (!function_exists('throwWarning')) {
+    /**
+     * Triggers an E_USER_WARNING.
+     *
+     * @param string $message The warning message.
+     * @return void
+     */
+    function triggerWarning($message)
+    {
+        $stackFrame = 2;
+        $trace = debug_backtrace();
+        if (isset($trace[$stackFrame])) {
+            $frame = $trace[$stackFrame];
+            $frame += ['file' => '[internal]', 'line' => '??'];
+            $message = sprintf(
+                '%s - %s, line: %s',
+                $message,
+                $frame['file'],
+                $frame['line']
+            );
+        }
+        trigger_error($message, E_USER_WARNING);
+    }
+}
+
 if (!function_exists('deprecationWarning')) {
     /**
      * Helper method for outputting deprecation warnings

+ 3 - 3
src/Shell/CacheShell.php

@@ -15,7 +15,7 @@
 namespace Cake\Shell;
 
 use Cake\Cache\Cache;
-use Cake\Cache\Engine\ApcEngine;
+use Cake\Cache\Engine\ApcuEngine;
 use Cake\Cache\Engine\WincacheEngine;
 use Cake\Console\Shell;
 
@@ -75,8 +75,8 @@ class CacheShell extends Shell
         try {
             $engine = Cache::engine($prefix);
             Cache::clear(false, $prefix);
-            if ($engine instanceof ApcEngine) {
-                $this->warn("ApcEngine detected: Cleared $prefix CLI cache successfully " .
+            if ($engine instanceof ApcuEngine) {
+                $this->warn("ApcuEngine detected: Cleared $prefix CLI cache successfully " .
                 "but $prefix web cache must be cleared separately.");
             } elseif ($engine instanceof WincacheEngine) {
                 $this->warn("WincacheEngine detected: Cleared $prefix CLI cache successfully " .

+ 72 - 67
tests/TestCase/Cache/Engine/ApcEngineTest.php

@@ -1,6 +1,6 @@
 <?php
 /**
- * ApcEngineTest file
+ * ApcuEngineTest file
  *
  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  *
@@ -10,7 +10,7 @@
  *
  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  * @link          https://cakephp.org CakePHP(tm) Project
- * @since         1.2.0
+ * @since         3.5.4
  * @license       https://opensource.org/licenses/mit-license.php MIT License
  */
 namespace Cake\Test\TestCase\Cache\Engine;
@@ -19,9 +19,9 @@ use Cake\Cache\Cache;
 use Cake\TestSuite\TestCase;
 
 /**
- * ApcEngineTest class
+ * ApcuEngineTest class
  */
-class ApcEngineTest extends TestCase
+class ApcuEngineTest extends TestCase
 {
 
     /**
@@ -35,11 +35,12 @@ class ApcEngineTest extends TestCase
         $this->skipIf(!function_exists('apcu_store'), 'APCu is not installed or configured properly.');
 
         if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg')) {
-            $this->skipIf(!ini_get('apc.enable_cli'), 'APC is not enabled for the CLI.');
+            $this->skipIf(!ini_get('apc.enable_cli'), 'APCu is not enabled for the CLI.');
         }
 
         Cache::enable();
         $this->_configCache();
+        Cache::clearAll();
     }
 
     /**
@@ -50,8 +51,8 @@ class ApcEngineTest extends TestCase
     public function tearDown()
     {
         parent::tearDown();
-        Cache::drop('apc');
-        Cache::drop('apc_groups');
+        Cache::drop('apcu');
+        Cache::drop('apcu_groups');
     }
 
     /**
@@ -63,11 +64,12 @@ class ApcEngineTest extends TestCase
     protected function _configCache($config = [])
     {
         $defaults = [
-            'className' => 'Apc',
+            'className' => 'Apcu',
             'prefix' => 'cake_',
+            'warnOnWriteFailures' => true,
         ];
-        Cache::drop('apc');
-        Cache::config('apc', array_merge($defaults, $config));
+        Cache::drop('apcu');
+        Cache::config('apcu', array_merge($defaults, $config));
     }
 
     /**
@@ -79,19 +81,19 @@ class ApcEngineTest extends TestCase
     {
         $this->_configCache(['duration' => 1]);
 
-        $result = Cache::read('test', 'apc');
+        $result = Cache::read('test', 'apcu');
         $expecting = '';
         $this->assertEquals($expecting, $result);
 
         $data = 'this is a test of the emergency broadcasting system';
-        $result = Cache::write('test', $data, 'apc');
+        $result = Cache::write('test', $data, 'apcu');
         $this->assertTrue($result);
 
-        $result = Cache::read('test', 'apc');
+        $result = Cache::read('test', 'apcu');
         $expecting = $data;
         $this->assertEquals($expecting, $result);
 
-        Cache::delete('test', 'apc');
+        Cache::delete('test', 'apcu');
     }
 
     /**
@@ -101,12 +103,12 @@ class ApcEngineTest extends TestCase
      */
     public function testReadWriteDurationZero()
     {
-        Cache::drop('apc');
-        Cache::config('apc', ['engine' => 'Apc', 'duration' => 0, 'prefix' => 'cake_']);
-        Cache::write('zero', 'Should save', 'apc');
+        Cache::drop('apcu');
+        Cache::config('apcu', ['engine' => 'Apcu', 'duration' => 0, 'prefix' => 'cake_']);
+        Cache::write('zero', 'Should save', 'apcu');
         sleep(1);
 
-        $result = Cache::read('zero', 'apc');
+        $result = Cache::read('zero', 'apcu');
         $this->assertEquals('Should save', $result);
     }
 
@@ -119,15 +121,15 @@ class ApcEngineTest extends TestCase
     {
         $this->_configCache(['duration' => 1]);
 
-        $result = Cache::read('test', 'apc');
+        $result = Cache::read('test', 'apcu');
         $this->assertFalse($result);
 
         $data = 'this is a test of the emergency broadcasting system';
-        $result = Cache::write('other_test', $data, 'apc');
+        $result = Cache::write('other_test', $data, 'apcu');
         $this->assertTrue($result);
 
         sleep(2);
-        $result = Cache::read('other_test', 'apc');
+        $result = Cache::read('other_test', 'apcu');
         $this->assertFalse($result);
     }
 
@@ -139,10 +141,10 @@ class ApcEngineTest extends TestCase
     public function testDeleteCache()
     {
         $data = 'this is a test of the emergency broadcasting system';
-        $result = Cache::write('delete_test', $data, 'apc');
+        $result = Cache::write('delete_test', $data, 'apcu');
         $this->assertTrue($result);
 
-        $result = Cache::delete('delete_test', 'apc');
+        $result = Cache::delete('delete_test', 'apcu');
         $this->assertTrue($result);
     }
 
@@ -153,19 +155,19 @@ class ApcEngineTest extends TestCase
      */
     public function testDecrement()
     {
-        $result = Cache::write('test_decrement', 5, 'apc');
+        $result = Cache::write('test_decrement', 5, 'apcu');
         $this->assertTrue($result);
 
-        $result = Cache::decrement('test_decrement', 1, 'apc');
+        $result = Cache::decrement('test_decrement', 1, 'apcu');
         $this->assertEquals(4, $result);
 
-        $result = Cache::read('test_decrement', 'apc');
+        $result = Cache::read('test_decrement', 'apcu');
         $this->assertEquals(4, $result);
 
-        $result = Cache::decrement('test_decrement', 2, 'apc');
+        $result = Cache::decrement('test_decrement', 2, 'apcu');
         $this->assertEquals(2, $result);
 
-        $result = Cache::read('test_decrement', 'apc');
+        $result = Cache::read('test_decrement', 'apcu');
         $this->assertEquals(2, $result);
     }
 
@@ -176,19 +178,19 @@ class ApcEngineTest extends TestCase
      */
     public function testIncrement()
     {
-        $result = Cache::write('test_increment', 5, 'apc');
+        $result = Cache::write('test_increment', 5, 'apcu');
         $this->assertTrue($result);
 
-        $result = Cache::increment('test_increment', 1, 'apc');
+        $result = Cache::increment('test_increment', 1, 'apcu');
         $this->assertEquals(6, $result);
 
-        $result = Cache::read('test_increment', 'apc');
+        $result = Cache::read('test_increment', 'apcu');
         $this->assertEquals(6, $result);
 
-        $result = Cache::increment('test_increment', 2, 'apc');
+        $result = Cache::increment('test_increment', 2, 'apcu');
         $this->assertEquals(8, $result);
 
-        $result = Cache::read('test_increment', 'apc');
+        $result = Cache::read('test_increment', 'apcu');
         $this->assertEquals(8, $result);
     }
 
@@ -200,11 +202,11 @@ class ApcEngineTest extends TestCase
     public function testClear()
     {
         apcu_store('not_cake', 'survive');
-        Cache::write('some_value', 'value', 'apc');
+        Cache::write('some_value', 'value', 'apcu');
 
-        $result = Cache::clear(false, 'apc');
+        $result = Cache::clear(false, 'apcu');
         $this->assertTrue($result);
-        $this->assertFalse(Cache::read('some_value', 'apc'));
+        $this->assertFalse(Cache::read('some_value', 'apcu'));
         $this->assertEquals('survive', apcu_fetch('not_cake'));
         apcu_delete('not_cake');
     }
@@ -218,24 +220,25 @@ class ApcEngineTest extends TestCase
      */
     public function testGroupsReadWrite()
     {
-        Cache::config('apc_groups', [
-            'engine' => 'Apc',
+        Cache::config('apcu_groups', [
+            'engine' => 'Apcu',
             'duration' => 0,
             'groups' => ['group_a', 'group_b'],
-            'prefix' => 'test_'
+            'prefix' => 'test_',
+            'warnOnWriteFailures' => true,
         ]);
-        $this->assertTrue(Cache::write('test_groups', 'value', 'apc_groups'));
-        $this->assertEquals('value', Cache::read('test_groups', 'apc_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value', 'apcu_groups'));
+        $this->assertEquals('value', Cache::read('test_groups', 'apcu_groups'));
 
         apcu_inc('test_group_a');
-        $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
-        $this->assertTrue(Cache::write('test_groups', 'value2', 'apc_groups'));
-        $this->assertEquals('value2', Cache::read('test_groups', 'apc_groups'));
+        $this->assertFalse(Cache::read('test_groups', 'apcu_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value2', 'apcu_groups'));
+        $this->assertEquals('value2', Cache::read('test_groups', 'apcu_groups'));
 
         apcu_inc('test_group_b');
-        $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
-        $this->assertTrue(Cache::write('test_groups', 'value3', 'apc_groups'));
-        $this->assertEquals('value3', Cache::read('test_groups', 'apc_groups'));
+        $this->assertFalse(Cache::read('test_groups', 'apcu_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value3', 'apcu_groups'));
+        $this->assertEquals('value3', Cache::read('test_groups', 'apcu_groups'));
     }
 
     /**
@@ -245,17 +248,18 @@ class ApcEngineTest extends TestCase
      */
     public function testGroupDelete()
     {
-        Cache::config('apc_groups', [
-            'engine' => 'Apc',
+        Cache::config('apcu_groups', [
+            'engine' => 'Apcu',
             'duration' => 0,
             'groups' => ['group_a', 'group_b'],
-            'prefix' => 'test_'
+            'prefix' => 'test_',
+            'warnOnWriteFailures' => true,
         ]);
-        $this->assertTrue(Cache::write('test_groups', 'value', 'apc_groups'));
-        $this->assertEquals('value', Cache::read('test_groups', 'apc_groups'));
-        $this->assertTrue(Cache::delete('test_groups', 'apc_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value', 'apcu_groups'));
+        $this->assertEquals('value', Cache::read('test_groups', 'apcu_groups'));
+        $this->assertTrue(Cache::delete('test_groups', 'apcu_groups'));
 
-        $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
+        $this->assertFalse(Cache::read('test_groups', 'apcu_groups'));
     }
 
     /**
@@ -265,20 +269,21 @@ class ApcEngineTest extends TestCase
      */
     public function testGroupClear()
     {
-        Cache::config('apc_groups', [
-            'engine' => 'Apc',
+        Cache::config('apcu_groups', [
+            'engine' => 'Apcu',
             'duration' => 0,
             'groups' => ['group_a', 'group_b'],
-            'prefix' => 'test_'
+            'prefix' => 'test_',
+            'warnOnWriteFailures' => true,
         ]);
 
-        $this->assertTrue(Cache::write('test_groups', 'value', 'apc_groups'));
-        $this->assertTrue(Cache::clearGroup('group_a', 'apc_groups'));
-        $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value', 'apcu_groups'));
+        $this->assertTrue(Cache::clearGroup('group_a', 'apcu_groups'));
+        $this->assertFalse(Cache::read('test_groups', 'apcu_groups'));
 
-        $this->assertTrue(Cache::write('test_groups', 'value2', 'apc_groups'));
-        $this->assertTrue(Cache::clearGroup('group_b', 'apc_groups'));
-        $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
+        $this->assertTrue(Cache::write('test_groups', 'value2', 'apcu_groups'));
+        $this->assertTrue(Cache::clearGroup('group_b', 'apcu_groups'));
+        $this->assertFalse(Cache::read('test_groups', 'apcu_groups'));
     }
 
     /**
@@ -288,16 +293,16 @@ class ApcEngineTest extends TestCase
      */
     public function testAdd()
     {
-        Cache::delete('test_add_key', 'apc');
+        Cache::delete('test_add_key', 'apcu');
 
-        $result = Cache::add('test_add_key', 'test data', 'apc');
+        $result = Cache::add('test_add_key', 'test data', 'apcu');
         $this->assertTrue($result);
 
         $expected = 'test data';
-        $result = Cache::read('test_add_key', 'apc');
+        $result = Cache::read('test_add_key', 'apcu');
         $this->assertEquals($expected, $result);
 
-        $result = Cache::add('test_add_key', 'test data 2', 'apc');
+        $result = Cache::add('test_add_key', 'test data 2', 'apcu');
         $this->assertFalse($result);
     }
 }

+ 2 - 1
tests/TestCase/Core/StaticConfigTraitTest.php

@@ -30,7 +30,8 @@ class TestCacheStaticConfig
      * @var array
      */
     protected static $_dsnClassMap = [
-        'apc' => 'Cake\Cache\Engine\ApcEngine',
+        'apc' => 'Cake\Cache\Engine\ApcuEngine', // @deprecated in 3.6. Use apcu instead.
+        'apcu' => 'Cake\Cache\Engine\ApcuEngine',
         'file' => 'Cake\Cache\Engine\FileEngine',
         'memcached' => 'Cake\Cache\Engine\MemcachedEngine',
         'null' => 'Cake\Cache\Engine\NullEngine',