Skip to content

Fix APC tests and add APCu support #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,3 @@
#
# Copy to `.env` in order to use it.
#

# APC test are disabled.
#
# To enable them in order to provide a fix, set to "on".
#
APC_ENABLE_CLI=off
2 changes: 2 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
extensions: apcu
ini-values: apc.enable_cli=1

- name: Get composer cache directory
id: composer-cache
Expand Down
2 changes: 1 addition & 1 deletion data/bin/check_configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function get_ini_path()
check(function_exists('posix_isatty'), 'The posix_isatty() is available', 'Install and enable the php_posix extension (used to colorized the CLI output)', false);

$accelerator =
(function_exists('apc_store') && ini_get('apc.enabled'))
((function_exists('apc_store') || function_exists('apcu_store')) && ini_get('apc.enabled'))
|| function_exists('eaccelerator_put') && ini_get('eaccelerator.enable')
|| function_exists('xcache_set');
check($accelerator, 'A PHP accelerator is installed', 'Install a PHP accelerator like APC (highly recommended)', false);
Expand Down
22 changes: 11 additions & 11 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ services:
echo 'short_open_tag = off'
echo 'magic_quotes_gpc = off'
echo 'date.timezone = "UTC"'
echo 'apc.enable_cli = ${APC_ENABLE_CLI-off}'
echo 'apc.enable_cli = on'
echo 'apc.use_request_time = 0'
} | tee -a /usr/local/lib/php.ini

Expand Down Expand Up @@ -60,7 +60,7 @@ services:
echo 'short_open_tag = off'
echo 'magic_quotes_gpc = off'
echo 'date.timezone = "UTC"'
echo 'apc.enable_cli = ${APC_ENABLE_CLI-off}'
echo 'apc.enable_cli = on'
echo 'apc.use_request_time = 0'
} | tee -a /usr/local/etc/php/php.ini

Expand Down Expand Up @@ -94,7 +94,7 @@ services:
args:
PHP_TAG: '7.0-cli-jessie'
MEMCACHE_VERSION: '4.0.5.2'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'

php71:
<<: *services_php54
Expand All @@ -103,7 +103,7 @@ services:
args:
PHP_TAG: '7.1-cli-jessie'
MEMCACHE_VERSION: '4.0.5.2'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


php72:
Expand All @@ -113,7 +113,7 @@ services:
args:
PHP_VERSION: '7.2'
MEMCACHE_VERSION: '4.0.5.2'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


php73:
Expand All @@ -123,7 +123,7 @@ services:
args:
PHP_VERSION: '7.3'
MEMCACHE_VERSION: '4.0.5.2'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


php74:
Expand All @@ -133,7 +133,7 @@ services:
args:
PHP_VERSION: '7.4'
MEMCACHE_VERSION: '4.0.5.2'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


php80:
Expand All @@ -143,7 +143,7 @@ services:
args:
PHP_VERSION: '8.0'
MEMCACHE_VERSION: '8.0'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


php81:
Expand All @@ -153,7 +153,7 @@ services:
args:
PHP_VERSION: '8.1'
MEMCACHE_VERSION: '8.0'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'

php82:
<<: *services_php54
Expand All @@ -162,7 +162,7 @@ services:
args:
PHP_VERSION: '8.2'
MEMCACHE_VERSION: '8.0'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'

php83:
<<: *services_php54
Expand All @@ -171,7 +171,7 @@ services:
args:
PHP_VERSION: '8.3'
MEMCACHE_VERSION: '8.0'
APCU_VERSION: ''
APCU_VERSION: '5.1.23'


db:
Expand Down
1 change: 1 addition & 0 deletions lib/autoload/sfCoreAutoload.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class sfCoreAutoload
'sfcoreautoload' => 'autoload/sfCoreAutoload.class.php',
'sfsimpleautoload' => 'autoload/sfSimpleAutoload.class.php',
'sfapccache' => 'cache/sfAPCCache.class.php',
'sfapcucache' => 'cache/sfAPCuCache.class.php',
'sfcache' => 'cache/sfCache.class.php',
'sfeacceleratorcache' => 'cache/sfEAcceleratorCache.class.php',
'sffilecache' => 'cache/sfFileCache.class.php',
Expand Down
195 changes: 195 additions & 0 deletions lib/cache/sfAPCuCache.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<?php

/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/**
* Cache class that stores cached content in APCu.
*
* @author Fabien Potencier <[email protected]>
* @author Paulo M
*
* @version SVN: $Id$
*/
class sfAPCuCache extends sfCache
{
protected $enabled;

/**
* Initializes this sfCache instance.
*
* Available options:
*
* * see sfCache for options available for all drivers
*
* @see sfCache
*/
public function initialize($options = array())
{
parent::initialize($options);

$this->enabled = function_exists('apcu_store') && ini_get('apc.enabled');
}

/**
* @see sfCache
*
* @param mixed|null $default
*/
public function get($key, $default = null)
{
if (!$this->enabled) {
return $default;
}

$value = $this->fetch($this->getOption('prefix').$key, $has);

return $has ? $value : $default;
}

/**
* @see sfCache
*/
public function has($key)
{
if (!$this->enabled) {
return false;
}

$this->fetch($this->getOption('prefix').$key, $has);

return $has;
}

/**
* @see sfCache
*
* @param mixed|null $lifetime
*/
public function set($key, $data, $lifetime = null)
{
if (!$this->enabled) {
return true;
}

return apcu_store($this->getOption('prefix').$key, $data, $this->getLifetime($lifetime));
}

/**
* @see sfCache
*/
public function remove($key)
{
if (!$this->enabled) {
return true;
}

return apcu_delete($this->getOption('prefix').$key);
}

/**
* @see sfCache
*/
public function clean($mode = sfCache::ALL)
{
if (!$this->enabled) {
return true;
}

if (sfCache::ALL === $mode) {
return apcu_clear_cache();
}
}

/**
* @see sfCache
*/
public function getLastModified($key)
{
if ($info = $this->getCacheInfo($key)) {
return $info['creation_time'] + $info['ttl'] > time() ? $info['mtime'] : 0;
}

return 0;
}

/**
* @see sfCache
*/
public function getTimeout($key)
{
if ($info = $this->getCacheInfo($key)) {
return $info['creation_time'] + $info['ttl'] > time() ? $info['creation_time'] + $info['ttl'] : 0;
}

return 0;
}

/**
* @see sfCache
*/
public function removePattern($pattern)
{
if (!$this->enabled) {
return true;
}

$infos = apcu_cache_info();
if (!is_array($infos['cache_list'])) {
return;
}

$regexp = self::patternToRegexp($this->getOption('prefix').$pattern);

foreach ($infos['cache_list'] as $info) {
if (preg_match($regexp, $info['info'])) {
apcu_delete($info['info']);
}
}
}

/**
* Gets the cache info.
*
* @param string $key The cache key
*
* @return string
*/
protected function getCacheInfo($key)
{
if (!$this->enabled) {
return false;
}

$infos = apcu_cache_info();

if (is_array($infos['cache_list'])) {
foreach ($infos['cache_list'] as $info) {
if ($this->getOption('prefix').$key == $info['info']) {
return $info;
}
}
}

return null;
}

private function fetch($key, &$success)
{
$has = null;
$value = apcu_fetch($key, $has);
// the second argument was added in APC 3.0.17. If it is still null we fall back to the value returned
if (null !== $has) {
$success = $has;
} else {
$success = false !== $value;
}

return $value;
}
}
23 changes: 21 additions & 2 deletions test/unit/cache/sfAPCCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,23 @@
$plan = 64;
$t = new lime_test($plan);

if (extension_loaded('apc')) {
$cacheClass = 'sfAPCCache';
} elseif (extension_loaded('apcu')) {
if ('5.1.22' === phpversion('apcu')) {
$t->skip('APCu 5.1.22 has a regression and shouldn\'t be used', $plan);

return;
}
$cacheClass = 'sfAPCuCache';
} else {
$t->skip('APC or APCu must be loaded to run these tests', $plan);

return;
}

try {
new sfAPCCache();
new $cacheClass();
} catch (sfInitializationException $e) {
$t->skip($e->getMessage(), $plan);

Expand All @@ -34,7 +49,11 @@

// ->initialize()
$t->diag('->initialize()');
$cache = new sfAPCCache();
$cache = new $cacheClass();
$cache->initialize();

// make sure expired keys are dropped
// see https://github.com/krakjoe/apcu/issues/391
ini_set('apc.use_request_time', 0);

sfCacheDriverTests::launch($t, $cache);
Loading