Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: Apc.php
- ===================================================================
- --- Apc.php (revision 24811)
- +++ Apc.php (working copy)
- @@ -41,12 +41,30 @@
- class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
- {
- /**
- - * Log message
- + * Available options
- + *
- + * =====> (int) metatadatas_array_max_size :
- + * - max size for the metadatas array (don't change this value unless you
- + * know what you are doing)
- + * =====> (string) apc_id_prefix :
- + * - prefix for the values stored in APC cache.
- + *
- + * @var array available options
- */
- - const TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND = 'Zend_Cache_Backend_Apc::clean() : tags are unsupported by the Apc backend';
- - const TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND = 'Zend_Cache_Backend_Apc::save() : tags are unsupported by the Apc backend';
- + protected $_options = array(
- + 'metadatas_array_max_size' => 100,
- + 'apc_id_prefix' => ''
- + );
- /**
- + * Array of metadatas (each item is an associative array)
- + *
- + * @var array
- + */
- + protected $_metadatasArray = array();
- +
- +
- + /**
- * Constructor
- *
- * @param array $options associative array of options
- @@ -59,6 +77,9 @@
- Zend_Cache::throwException('The apc extension must be loaded for using this backend !');
- }
- parent::__construct($options);
- + if ($this->_options['metadatas_array_max_size'] < 10) {
- + Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
- + }
- }
- /**
- @@ -72,11 +93,7 @@
- */
- public function load($id, $doNotTestCacheValidity = false)
- {
- - $tmp = apc_fetch($id);
- - if (is_array($tmp)) {
- - return $tmp[0];
- - }
- - return false;
- + return apc_fetch($this->_id($id));
- }
- /**
- @@ -87,9 +104,10 @@
- */
- public function test($id)
- {
- - $tmp = apc_fetch($id);
- - if (is_array($tmp)) {
- - return $tmp[1];
- + $id = $this->_id($id);
- + $metadatas = $this->_getMetadatas($id);
- + if ($metadatas !== false && apc_exists($id)) {
- + return $metadatas['mtime'];
- }
- return false;
- }
- @@ -108,11 +126,21 @@
- */
- public function save($data, $id, $tags = array(), $specificLifetime = false)
- {
- + $id = $this->_id($id);
- $lifetime = $this->getLifetime($specificLifetime);
- - $result = apc_store($id, array($data, time(), $lifetime), $lifetime);
- - if (count($tags) > 0) {
- - $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
- + $mtime = time();
- + $metadatas = array(
- + 'expire' => $mtime + $lifetime,
- + 'tags' => $tags,
- + 'mtime' => $mtime,
- + 'ttl' => $lifetime
- + );
- + $result = $this->_setMetadatas($id, $metadatas);
- + if (!$result) {
- + $this->_log('Zend_Cache_Backend_Apc::save() / error on saving metadata');
- + return false;
- }
- + $result = apc_store($id, $data, $lifetime);
- return $result;
- }
- @@ -124,87 +152,54 @@
- */
- public function remove($id)
- {
- - return apc_delete($id);
- + $id = $this->_id($id);
- + $boolRemove = $this->_remove($id);
- + $boolMetadata = $this->_delMetadatas($id);
- + return $boolMetadata && $boolRemove;
- }
- /**
- * Clean some cache records
- *
- * Available modes are :
- - * 'all' (default) => remove all cache entries ($tags is not used)
- - * 'old' => unsupported
- - * 'matchingTag' => unsupported
- - * 'notMatchingTag' => unsupported
- - * 'matchingAnyTag' => unsupported
- *
- + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
- + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
- + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
- + * ($tags can be an array of strings or a single string)
- + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
- + * ($tags can be an array of strings or a single string)
- + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
- + * ($tags can be an array of strings or a single string)
- + *
- * @param string $mode clean mode
- * @param array $tags array of tags
- - * @throws Zend_Cache_Exception
- * @return boolean true if no problem
- */
- public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
- {
- - switch ($mode) {
- - case Zend_Cache::CLEANING_MODE_ALL:
- - return apc_clear_cache('user');
- - break;
- - case Zend_Cache::CLEANING_MODE_OLD:
- - $this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend");
- - break;
- - case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
- - case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
- - case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
- - $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND);
- - break;
- - default:
- - Zend_Cache::throwException('Invalid mode for clean() method');
- - break;
- - }
- + // We use this protected method to hide the recursive stuff
- + return $this->_clean($mode, $tags);
- }
- /**
- - * Return true if the automatic cleaning is available for the backend
- + * Return an array of stored cache ids
- *
- - * DEPRECATED : use getCapabilities() instead
- - *
- - * @deprecated
- - * @return boolean
- + * @return array array of stored cache ids (string)
- */
- - public function isAutomaticCleaningAvailable()
- + public function getIds()
- {
- - return false;
- + return $this->_get('ids', array());
- }
- /**
- - * Return the filling percentage of the backend storage
- - *
- - * @throws Zend_Cache_Exception
- - * @return int integer between 0 and 100
- - */
- - public function getFillingPercentage()
- - {
- - $mem = apc_sma_info(true);
- - $memSize = $mem['num_seg'] * $mem['seg_size'];
- - $memAvailable= $mem['avail_mem'];
- - $memUsed = $memSize - $memAvailable;
- - if ($memSize == 0) {
- - Zend_Cache::throwException('can\'t get apc memory size');
- - }
- - if ($memUsed > $memSize) {
- - return 100;
- - }
- - return ((int) (100. * ($memUsed / $memSize)));
- - }
- -
- - /**
- * Return an array of stored tags
- *
- * @return array array of stored tags (string)
- */
- public function getTags()
- {
- - $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
- - return array();
- + return $this->_get('tags', array());
- }
- /**
- @@ -217,8 +212,7 @@
- */
- public function getIdsMatchingTags($tags = array())
- {
- - $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
- - return array();
- + return $this->_get('matching', $tags);
- }
- /**
- @@ -231,8 +225,7 @@
- */
- public function getIdsNotMatchingTags($tags = array())
- {
- - $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
- - return array();
- + return $this->_get('notMatching', $tags);
- }
- /**
- @@ -245,24 +238,28 @@
- */
- public function getIdsMatchingAnyTags($tags = array())
- {
- - $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
- - return array();
- + return $this->_get('matchingAny', $tags);
- }
- /**
- - * Return an array of stored cache ids
- + * Return the filling percentage of the backend storage
- *
- - * @return array array of stored cache ids (string)
- + * @throws Zend_Cache_Exception
- + * @return int integer between 0 and 100
- */
- - public function getIds()
- + public function getFillingPercentage()
- {
- - $res = array();
- - $array = apc_cache_info('user', false);
- - $records = $array['cache_list'];
- - foreach ($records as $record) {
- - $res[] = $record['info'];
- + $mem = apc_sma_info(true);
- + $memSize = $mem['num_seg'] * $mem['seg_size'];
- + $memAvailable= $mem['avail_mem'];
- + $memUsed = $memSize - $memAvailable;
- + if ($memSize == 0) {
- + Zend_Cache::throwException('can\'t get apc memory size');
- }
- - return $res;
- + if ($memUsed > $memSize) {
- + return 100;
- + }
- + return ((int) (100. * ($memUsed / $memSize)));
- }
- /**
- @@ -278,23 +275,12 @@
- */
- public function getMetadatas($id)
- {
- - $tmp = apc_fetch($id);
- - if (is_array($tmp)) {
- - $data = $tmp[0];
- - $mtime = $tmp[1];
- - if (!isset($tmp[2])) {
- - // because this record is only with 1.7 release
- - // if old cache records are still there...
- - return false;
- - }
- - $lifetime = $tmp[2];
- - return array(
- - 'expire' => $mtime + $lifetime,
- - 'tags' => array(),
- - 'mtime' => $mtime
- - );
- + $id = $this->_id($id);
- + $metadatas = $this->_getMetadatas($id);
- + if (!$metadatas) {
- + return false;
- }
- - return false;
- + return $metadatas;
- }
- /**
- @@ -306,22 +292,17 @@
- */
- public function touch($id, $extraLifetime)
- {
- - $tmp = apc_fetch($id);
- - if (is_array($tmp)) {
- - $data = $tmp[0];
- - $mtime = $tmp[1];
- - if (!isset($tmp[2])) {
- - // because this record is only with 1.7 release
- - // if old cache records are still there...
- + $id = $this->_id($id);
- + $metadatas = $this->_getMetadatas($id);
- + if (false !== $tmp = apc_fetch($id)) {
- + $metadatas['ttl'] = $metadatas['ttl'] - (time() - $metadatas['mtime']) + $extraLifetime;
- + $metadatas['mtime'] = time();
- + $metadatas['expire'] = $metadatas['mtime'] + $metadatas['ttl'];
- + if ($metadatas['ttl'] <=0) {
- return false;
- }
- - $lifetime = $tmp[2];
- - $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
- - if ($newLifetime <=0) {
- - return false;
- - }
- - apc_store($id, array($data, time(), $newLifetime), $newLifetime);
- - return true;
- + $this->_setMetadatas($id, $metadatas);
- + return apc_store($id, $tmp, $metadatas['ttl']);
- }
- return false;
- }
- @@ -344,7 +325,7 @@
- {
- return array(
- 'automatic_cleaning' => false,
- - 'tags' => false,
- + 'tags' => true,
- 'expired_read' => false,
- 'priority' => false,
- 'infinite_lifetime' => false,
- @@ -352,4 +333,365 @@
- );
- }
- + /**
- + * Get a metadatas record
- + *
- + * @param string $id Cache id
- + * @return array|false Associative array of metadatas
- + */
- + protected function _getMetadatas($id)
- + {
- + if (isset($this->_metadatasArray[$id])) {
- + return $this->_metadatasArray[$id];
- + } else {
- + $metadatas = $this->_loadMetadatas($id);
- + if (!$metadatas) {
- + return false;
- + }
- + $this->_setMetadatas($id, $metadatas, false);
- + return $metadatas;
- + }
- + }
- +
- + /**
- + * Set a metadatas record
- + *
- + * @param string $id Cache id
- + * @param array $metadatas Associative array of metadatas
- + * @param boolean $save optional pass false to disable saving to cache
- + * @return boolean True if no problem
- + */
- + protected function _setMetadatas($id, $metadatas, $save = true)
- + {
- + if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
- + $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
- + $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
- + }
- + if ($save) {
- + $result = $this->_saveMetadatas($id, $metadatas);
- + if (!$result) {
- + return false;
- + }
- + }
- + $this->_metadatasArray[$id] = $metadatas;
- + return true;
- + }
- +
- + /**
- + * Drop a metadata record
- + *
- + * @param string $id Cache id
- + * @return boolean True if no problem
- + */
- + protected function _delMetadatas($id)
- + {
- + if (isset($this->_metadatasArray[$id])) {
- + unset($this->_metadatasArray[$id]);
- + }
- + $metas = $this->_loadMetadatasStore();
- + if (isset($metas[$id])) {
- + unset($metas[$id]);
- + }
- + $result = $this->_saveMetadatasStore($metas);
- + return $result;
- + }
- +
- + /**
- + * Load metadatas from cache
- + *
- + * @param string $id Cache id
- + * @return array|false Metadatas associative array
- + */
- + protected function _loadMetadatas($id)
- + {
- + $metas = $this->_loadMetadatasStore();
- + if ($metas === false) {
- + return false;
- + }
- +
- + if (!isset($metas[$id]) || empty($metas[$id])) {
- + // Metadatas for this id not available, remove it.
- + $this->_remove($id);
- + return false;
- + }
- + return $metas[$id];
- + }
- +
- + /**
- + * Save metadatas to cache
- + *
- + * @param string $id Cache id
- + * @param array $metadatas Associative array
- + * @return boolean True if no problem
- + */
- + protected function _saveMetadatas($id, $metadatas)
- + {
- + $metas = $this->_loadMetadatasStore();
- + if ($metas === false) {
- + return false;
- + }
- + $metas[$id] = $metadatas;
- + $result = $this->_saveMetadatasStore($metas);
- + if (!$result) {
- + return false;
- + }
- + return true;
- + }
- +
- + /**
- + * Load the whole metadatas from cache
- + *
- + * @return array|false Metadatas associative array
- + */
- + protected function _loadMetadatasStore()
- + {
- + $result = apc_fetch($this->_metadatasId());
- + if ($result === false) {
- + // Metadatas not available, clean the whole cache. It's useless without it anyways.
- + $this->_clean(Zend_Cache::CLEANING_MODE_ALL, array(), true);
- + // Return an emty set to avoid failing the query. (Will fail anyways at the write)
- + return array();
- + }
- + return @unserialize($result);
- + }
- + /**
- + * Save the whole metadatas to cache
- + *
- + * @param array $metadatas Associative array
- + * @return boolean True if no problem
- + */
- + protected function _saveMetadatasStore($metadatas)
- + {
- + $result = apc_store($this->_metadatasId(), serialize($metadatas), 0);
- + if ($result === false) {
- + // Failed to save the metadatas, clean the cache.
- + $this->_clean(Zend_Cache::CLEANING_MODE_ALL, array(), true);
- + return false;
- + }
- + return true;
- + }
- +
- + /**
- + * Make and return the key for metadatas
- + *
- + * @return string Metadatas cache id
- + */
- + protected function _metadatasId()
- + {
- + return 'internal-metadatas---' . $this->_id('');
- + }
- +
- + /**
- + * Remove a key from cache
- + *
- + * @param string $id Cache id
- + * @return boolean True if ok
- + */
- + protected function _remove($id)
- + {
- + if (!apc_delete($id)) {
- + return false;
- + }
- + return true;
- + }
- +
- + /**
- + * Clean some cache records (protected method used for recursive stuff)
- + *
- + * Available modes are :
- + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
- + * Zend_Cache::CLEANING_MODE_OLD => unsupported
- + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
- + * ($tags can be an array of strings or a single string)
- + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
- + * ($tags can be an array of strings or a single string)
- + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
- + * ($tags can be an array of strings or a single string)
- + *
- + * @param string $mode Clean mode
- + * @param array $tags Array of tags
- + * @param boolean $blindClean If true, don't load metadatas, juste clean.
- + * @throws Zend_Cache_Exception
- + * @return boolean True if no problem
- + */
- + protected function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array(), $blindClean = false)
- + {
- + if ($mode === Zend_Cache::CLEANING_MODE_OLD) {
- + $this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend");
- + return false;
- + }
- + $result = true;
- + if (!$blindClean) {
- + $metas = $this->_loadMetadatasStore();
- + if ($metas === false) {
- + // Unable to read metadatas, clean the cache.
- + $mode = Zend_Cache::CLEANING_MODE_ALL;
- + $metas = array();
- + }
- + } else {
- + $metas = array();
- + }
- + // We forge a new metadatas store to prevent metadatas from fallen ids to stay on cache.
- + $newMetas = array();
- + $cleanList = array();
- + // List all cache entry for our cache. We are good neighbours, we don't touch or clean other caches.
- + $iterator = new APCIterator('user', '/^' . $this->_options['apc_id_prefix'] . '/') ;
- + foreach ($iterator as $entity) {
- + $id = $entity['key'];
- + if (!isset($metas[$id])) {
- + // No metadatas for this id, purge it from the cache.
- + $cleanList[] = $id;
- + continue;
- + }
- + $metadatas = $metas[$id];
- + switch ($mode) {
- + case Zend_Cache::CLEANING_MODE_ALL:
- + $cleanList[] = $id;
- + break;
- + case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
- + $matching = true;
- + foreach ($tags as $tag) {
- + if (!in_array($tag, $metadatas['tags'])) {
- + $matching = false;
- + break;
- + }
- + }
- + if ($matching) {
- + $cleanList[] = $id;;
- + } else {
- + $newMetas[] = $metadatas;
- + }
- + break;
- + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
- + $matching = false;
- + foreach ($tags as $tag) {
- + if (in_array($tag, $metadatas['tags'])) {
- + $matching = true;
- + break;
- + }
- + }
- + if (!$matching) {
- + $cleanList[] = $id;;
- + } else {
- + $newMetas[] = $metadatas;
- + }
- + break;
- + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
- + $matching = false;
- + foreach ($tags as $tag) {
- + if (in_array($tag, $metadatas['tags'])) {
- + $matching = true;
- + break;
- + }
- + }
- + if ($matching) {
- + $cleanList[] = $id;;
- + } else {
- + $newMetas[] = $metadatas;
- + }
- + break;
- + default:
- + Zend_Cache::throwException('Invalid mode for clean() method');
- + break;
- + }
- + }
- + apc_delete($cleanList);
- + $result = $result && $this->_saveMetadatasStore($newMetas);
- + return $result;
- + }
- +
- + /**
- + * Get some cache records
- + *
- + * Available modes are :
- + * 'ids' =>
- + * 'tags' =>
- + * 'matching' =>
- + * 'notMatching' =>
- + * 'matchingAny' =>
- + *
- + * @param string $dir Directory to clean
- + * @param string $mode Clean mode
- + * @param array $tags Array of tags
- + * @throws Zend_Cache_Exception
- + * @return boolean True if no problem
- + */
- + protected function _get($mode, $tags = array())
- + {
- + $result = array();
- + $metas = $this->_loadMetadatasStore();
- + foreach ($metas as $id => $metadatas) {
- + switch ($mode) {
- + case 'ids':
- + $result[] = $id;
- + break;
- + case 'tags':
- + $result = array_unique(array_merge($result, $metadatas['tags']));
- + break;
- + case 'matching':
- + $matching = true;
- + foreach ($tags as $tag) {
- + if (!in_array($tag, $metadatas['tags'])) {
- + $matching = false;
- + break;
- + }
- + }
- + if ($matching) {
- + $result[] = $id;
- + }
- + break;
- + case 'notMatching':
- + $matching = false;
- + foreach ($tags as $tag) {
- + if (in_array($tag, $metadatas['tags'])) {
- + $matching = true;
- + break;
- + }
- + }
- + if (!$matching) {
- + $result[] = $id;
- + }
- + break;
- + case 'matchingAny':
- + $matching = false;
- + foreach ($tags as $tag) {
- + if (in_array($tag, $metadatas['tags'])) {
- + $matching = true;
- + break;
- + }
- + }
- + if ($matching) {
- + $result[] = $id;
- + }
- + break;
- + default:
- + Zend_Cache::throwException('Invalid mode for _get() method');
- + break;
- + }
- + }
- + $result = array_unique($result);
- + if ($mode !== 'tags' && strlen($this->_options['apc_id_prefix'])) {
- + // Cleaning prefixes from ids
- + foreach ($result as &$res) {
- + $res = substr($res, strlen($this->_options['apc_id_prefix']));
- + }
- + }
- + return $result;
- + }
- +
- + /**
- + * Make and return a cache id
- + *
- + * Checks 'apc_id_prefix' and returns new id with prefix or simply the id if null
- + *
- + * @param string $id Cache id
- + * @return string Cache id (with or without prefix)
- + */
- + protected function _id($id)
- + {
- + if (($id !== null) && isset($this->_options['apc_id_prefix'])) {
- + return $this->_options['apc_id_prefix'] . $id; // return with prefix
- + }
- + return $id; // no prefix, just return the $id passed
- + }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement