Implemented group read/write support for the ApcEngine

This commit is contained in:
Jose Lorenzo Rodriguez 2012-03-25 19:17:08 -04:30
parent 58a59fd4a4
commit 3c9c3ef9ba
4 changed files with 83 additions and 2 deletions

View file

@ -91,6 +91,8 @@ class Cache {
* The following keys are used in core cache engines: * The following keys are used in core cache engines:
* *
* - `duration` Specify how long items in this cache configuration last. * - `duration` Specify how long items in this cache configuration last.
* - `groups` List of groups or 'tags' associated to every key stored in this config.
* handy for deleting a complete group from cache.
* - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace
* with either another cache config or another application. * with either another cache config or another application.
* - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable

View file

@ -27,6 +27,14 @@ abstract class CacheEngine {
*/ */
public $settings = array(); public $settings = array();
/**
* Contains the compiled string with all groups
* prefixes to be prepeded to every key in this cache engine
*
* @var string
**/
protected $groupPrefix = null;
/** /**
* Initialize the cache engine * Initialize the cache engine
* *
@ -37,10 +45,14 @@ abstract class CacheEngine {
*/ */
public function init($settings = array()) { public function init($settings = array()) {
$this->settings = array_merge( $this->settings = array_merge(
array('prefix' => 'cake_', 'duration' => 3600, 'probability' => 100), array('prefix' => 'cake_', 'duration' => 3600, 'probability' => 100, 'groups' => array()),
$this->settings, $this->settings,
$settings $settings
); );
if (!empty($this->settings['groups'])) {
sort($this->settings['groups']);
$this->groupPrefix = str_repeat('%s_', count($this->settings['groups']));
}
if (!is_numeric($this->settings['duration'])) { if (!is_numeric($this->settings['duration'])) {
$this->settings['duration'] = strtotime($this->settings['duration']) - time(); $this->settings['duration'] = strtotime($this->settings['duration']) - time();
} }
@ -108,6 +120,17 @@ abstract class CacheEngine {
*/ */
abstract public function clear($check); abstract public function clear($check);
/**
* Does whatever initialization for each group is required
* and returns the `group value` for each of them, this is
* the token representing each group in the cache key
*
* @return array
**/
public function groups() {
return $this->settings['groups'];
}
/** /**
* Cache Engine settings * Cache Engine settings
* *
@ -127,8 +150,14 @@ abstract class CacheEngine {
if (empty($key)) { if (empty($key)) {
return false; return false;
} }
$prefix = '';
if (!empty($this->groupPrefix)) {
$prefix = vsprintf($this->groupPrefix, $this->groups());
}
$key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key))); $key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
return $key; return $prefix . $key;
} }
} }

View file

@ -127,4 +127,30 @@ class ApcEngine extends CacheEngine {
return true; return 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
**/
public function groups() {
$groups = apc_fetch($this->settings['groups']);
if (count($groups) !== count($this->settings['groups'])) {
foreach ($this->settings['groups'] as $group) {
if (!isset($groups[$group])) {
apc_store($group, 1);
$groups[$group] = 1;
}
}
ksort($groups);
}
$result = array();
foreach ($groups as $group => $value) {
$result[] = $group . $value;
}
return $result;
}
} }

View file

@ -47,6 +47,7 @@ class ApcEngineTest extends CakeTestCase {
public function tearDown() { public function tearDown() {
Configure::write('Cache.disable', $this->_cacheDisable); Configure::write('Cache.disable', $this->_cacheDisable);
Cache::drop('apc'); Cache::drop('apc');
Cache::drop('apc_groups');
Cache::config('default'); Cache::config('default');
} }
@ -198,4 +199,27 @@ class ApcEngineTest extends CakeTestCase {
$this->assertEquals('survive', apc_fetch('not_cake')); $this->assertEquals('survive', apc_fetch('not_cake'));
apc_delete('not_cake'); apc_delete('not_cake');
} }
/**
* Tests that configuring groups for stored keys return the correct values when read/written
* Shows that altering the group value is equivalent to deleting all keys under the same
* group
*
* @return void
*/
public function testGroupsReadWrite() {
Cache::config('apc_groups', array('engine' => 'Apc', 'duration' => 0, 'groups' => array('group_a', 'group_b')));
$this->assertTrue(Cache::write('test_groups', 'value', 'apc_groups'));
$this->assertEquals('value', Cache::read('test_groups', 'apc_groups'));
apc_inc('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'));
apc_inc('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'));
}
} }