Permalink
Browse files

Merge branch '2.2-cache-groups' into 2.2

Conflicts:
	lib/Cake/Test/Case/Cache/Engine/XcacheEngineTest.php
  • Loading branch information...
2 parents 4b2804b + e5cc7d0 commit 9f415d012c75ca4c7147c615848d1dfaf631f84b @lorenzo lorenzo committed Apr 22, 2012
View
@@ -91,6 +91,8 @@ class Cache {
* The following keys are used in core cache engines:
*
* - `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
* with either another cache config or another application.
* - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
@@ -453,6 +455,22 @@ public static function clear($check = false, $config = 'default') {
}
/**
+ * Delete all keys from the cache belonging to the same group.
+ *
+ * @param string $group name of the group to be cleared
+ * @param string $config name of the configuration to use. Defaults to 'default'
+ * @return boolean True if the cache group was successfully cleared, false otherwise
+ */
+ public static function clearGroup($group, $config = 'default') {
+ if (!self::isInitialized($config)) {
+ return false;
+ }
+ $success = self::$_engines[$config]->clearGroup($group);
+ self::set(null, $config);
+ return $success;
+ }
+
+/**
* Check if Cache has initialized a working config for the given name.
*
* @param string $config name of the configuration to use. Defaults to 'default'
@@ -28,6 +28,14 @@
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
*
* Called automatically by the cache frontend
@@ -37,10 +45,14 @@
*/
public function init($settings = array()) {
$this->settings = array_merge(
- array('prefix' => 'cake_', 'duration' => 3600, 'probability' => 100),
+ array('prefix' => 'cake_', 'duration' => 3600, 'probability' => 100, 'groups' => array()),
$this->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'])) {
$this->settings['duration'] = strtotime($this->settings['duration']) - time();
}
@@ -111,6 +123,29 @@ public function gc($expires = null) {
abstract public function clear($check);
/**
+ * Clears all values belonging to a group. Is upt to the implementing engine
+ * to decide whether actually deete the keys or just simulate it to acheive
+ * the same result.
+ *
+ * @param string $groups name of the group to be cleared
+ * @return boolean
+ **/
+ public function clearGroup($group) {
+ return false;
+ }
+
+/**
+ * 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
*
* @return array settings
@@ -129,8 +164,14 @@ public function key($key) {
if (empty($key)) {
return false;
}
+
+ $prefix = '';
+ if (!empty($this->groupPrefix)) {
+ $prefix = vsprintf($this->groupPrefix, $this->groups());
+ }
+
$key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
- return $key;
+ return $prefix . $key;
}
}
@@ -26,6 +26,14 @@
class ApcEngine extends CacheEngine {
/**
+ * Contains the compiled group names
+ * (prefixed witht the global configuration prefix)
+ *
+ * @var array
+ **/
+ protected $_compiledGroupNames = array();
+
+/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
@@ -127,4 +135,48 @@ public function clear($check) {
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() {
+ if (empty($this->_compiledGroupNames)) {
+ foreach ($this->settings['groups'] as $group) {
+ $this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
+ }
+ }
+
+ $groups = apc_fetch($this->_compiledGroupNames);
+ if (count($groups) !== count($this->settings['groups'])) {
+ foreach ($this->_compiledGroupNames as $group) {
+ if (!isset($groups[$group])) {
+ apc_store($group, 1);
+ $groups[$group] = 1;
+ }
+ }
+ ksort($groups);
+ }
+
+ $result = array();
+ $groups = array_values($groups);
+ foreach ($this->settings['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.
+ *
+ * @return boolean success
+ **/
+ public function clearGroup($group) {
+ apc_inc($this->settings['prefix'] . $group, 1, $success);
+ return $success;
+ }
+
}
@@ -82,6 +82,9 @@ public function init($settings = array()) {
if (substr($this->settings['path'], -1) !== DS) {
$this->settings['path'] .= DS;
}
+ if (!empty($this->groupPrefix)) {
+ $this->groupPrefix = str_replace('_', DS, $this->groupPrefix);
+ }
return $this->_active();
}
@@ -285,7 +288,17 @@ public function increment($key, $offset = 1) {
* @return boolean true if the cache key could be set, false otherwise
*/
protected function _setKey($key, $createKey = false) {
- $path = new SplFileInfo($this->settings['path'] . $key);
+
+ $groups = null;
+ if (!empty($this->groupPrefix)) {
+ $groups = vsprintf($this->groupPrefix, $this->groups());
+ }
+ $dir = $this->settings['path'] . $groups;
+
+ if (!is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+ $path = new SplFileInfo($dir . $key);
if (!$createKey && !$path->isFile()) {
return false;
@@ -324,4 +337,35 @@ protected function _active() {
return true;
}
+/**
+ * Generates a safe key for use with cache engine storage engines.
+ *
+ * @param string $key the key passed over
+ * @return mixed string $key or false
+ */
+ public function key($key) {
+ if (empty($key)) {
+ return false;
+ }
+
+ $key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
+ return $key;
+ }
+
+/**
+ * Recursively deletes all files under any directory named as $group
+ *
+ * @return boolean success
+ **/
+ public function clearGroup($group) {
+ $directoryIterator = new RecursiveDirectoryIterator($this->settings['path']);
+ $contents = new RecursiveIteratorIterator($directoryIterator, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($contents as $object) {
+ $containsGroup = strpos($object->getPathName(), DS . $group . DS) !== false;
+ if ($object->isFile() && $containsGroup) {
+ unlink($object->getPathName());
+ }
+ }
+ return true;
+ }
}
@@ -28,6 +28,14 @@
class MemcacheEngine extends CacheEngine {
/**
+ * Contains the compiled group names
+ * (prefixed witht the global configuration prefix)
+ *
+ * @var array
+ **/
+ protected $_compiledGroupNames = array();
+
+/**
* Memcache wrapper.
*
* @var Memcache
@@ -235,4 +243,47 @@ public function connect($host, $port = 11211) {
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() {
+ if (empty($this->_compiledGroupNames)) {
+ foreach ($this->settings['groups'] as $group) {
+ $this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
+ }
+ }
+
+ $groups = $this->_Memcache->get($this->_compiledGroupNames);
+ if (count($groups) !== count($this->settings['groups'])) {
+ foreach ($this->_compiledGroupNames as $group) {
+ if (!isset($groups[$group])) {
+ $this->_Memcache->set($group, 1, false, 0);
+ $groups[$group] = 1;
+ }
+ }
+ ksort($groups);
+ }
+
+ $result = array();
+ $groups = array_values($groups);
+ foreach ($this->settings['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.
+ *
+ * @return boolean success
+ **/
+ public function clearGroup($group) {
+ return (bool) $this->_Memcache->increment($this->settings['prefix'] . $group);
+ }
}
@@ -27,6 +27,14 @@
class WincacheEngine extends CacheEngine {
/**
+ * Contains the compiled group names
+ * (prefixed witht the global configuration prefix)
+ *
+ * @var array
+ **/
+ protected $_compiledGroupNames = array();
+
+/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
@@ -134,4 +142,49 @@ public function clear($check) {
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() {
+ if (empty($this->_compiledGroupNames)) {
+ foreach ($this->settings['groups'] as $group) {
+ $this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
+ }
+ }
+
+ $groups = wincache_ucache_get($this->_compiledGroupNames);
+ if (count($groups) !== count($this->settings['groups'])) {
+ foreach ($this->_compiledGroupNames as $group) {
+ if (!isset($groups[$group])) {
+ wincache_ucache_set($group, 1);
+ $groups[$group] = 1;
+ }
+ }
+ ksort($groups);
+ }
+
+ $result = array();
+ $groups = array_values($groups);
+ foreach ($this->settings['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.
+ *
+ * @return boolean success
+ **/
+ public function clearGroup($group) {
+ wincache_ucache_inc($this->settings['prefix'] . $group, 1, $success);
+ return $success;
+ }
+
+
}
Oops, something went wrong.

0 comments on commit 9f415d0

Please sign in to comment.