Project

General

Profile

Bug #19506 » 9645.diff

Administrator Admin, 2008-11-27 14:54

View differences:

t3lib/cache/backend/class.t3lib_cache_backend_memcached.php (working copy)
/**
* A caching backend which stores cache entries by using Memcached
* A caching backend which stores cache entries by using Memcached.
*
* This file is a backport from FLOW3
* This backend uses the following types of Memcache keys:
* - tag_xxx
* xxx is tag name, value is array of associated identifiers identifier. This
* is "forward" tag index. It is mainly used for obtaining content by tag
* (get identifier by tag -> get content by identifier)
* - ident_xxx
* xxx is identifier, value is array of associated tags. This is "reverse" tag
* index. It provides quick access for all tags associated with this identifier
* and used when removing the identifier
* - tagIndex
* Value is a List of all tags (array)
* Each key is prepended with a prefix. By default prefix consists from two parts
* separated by underscore character and ends in yet another underscore character:
* - "TYPO3"
* - Current host name obtained from the HTTP_HOST variable
* This prefix makes sure that keys from the different installations do not
* conflict.
*
* This file is a backport from FLOW3 by Ingo Renner.
*
* @package TYPO3
* @subpackage t3lib_cache
* @version $Id$
......
class t3lib_cache_backend_Memcached extends t3lib_cache_AbstractBackend {
/**
* Instance of the PHP Memcache class
*
* @var Memcache
*/
protected $memcache;
/**
* Array of Memcache server configurations
*
* @var array
*/
protected $servers = array();
/**
* @var boolean whether the memcache uses compression or not (requires zlib)
* Indicates whether the memcache uses compression or not (requires zlib)
*
* @var boolean
*/
protected $useCompressed;
/**
* @var string A prefix to seperate stored data from other data possible stored in the memcache
* A prefix to seperate stored data from other data possibly stored in the
* memcache. This prefix must be unique for each site in the tree. Default
* implementation uses MD5 of the current host name to make identifier prefix
* unique.
*
* @var string
*/
protected $identifierPrefix;
/**
* @var string The ID of this TYPO3 server. If many sites are using the same memcached, it prevents conflicts
*/
protected $serverId;
/**
* Constructs this backend
*
* @param string $context FLOW3's application context
* @param mixed $options Configuration options - depends on the actual backend
* @author Robert Lemke <robert@typo3.org>
*/
public function __construct($options = array()) {
if (!extension_loaded('memcache')) {
throw new t3lib_cache_Exception(
'The PHP extension "memcached" must be installed and loaded in order to use the Memcached backend.',
'The PHP extension "memcached" must be installed and loaded in ' .
'order to use the Memcached backend.',
1213987706
);
}
// Set default value for the server ID
$this->serverId = t3lib_div::getIndpEnv('HTTP_HOST');
parent::__construct($options);
$this->memcache = new Memcache();
$this->identifierPrefix = 'TYPO3_' . md5(
t3lib_div::getIndpEnv('SCRIPT_FILENAME')
. php_sapi_name()
. $this->serverId
) . '_';
$this->identifierPrefix = $this->getIdentifierPrefix();
if (!count($this->servers)) {
throw new t3lib_cache_Exception(
......
}
/**
* Setter for serverId property.
* Sets servers property.
*
* @param int $serverId The value of the property
* @param array An array of servers to add (format: "host:port")
* @return void
* @author Christian Jul Jensen <julle@typo3.org>
*/
protected function setServerId($serverId) {
$this->serverId = $serverId;
}
/**
* setter for servers property
* should be an array of entries like host:port
*
* @param array An array of servers to add
* @return void
* @author Christian Jul Jensen <julle@typo3.org>
*/
protected function setServers(array $servers) {
$this->servers = $servers;
}
/**
* Setter for useCompressed
* Sets for compression flag
*
* @param boolean $enableCompression
* @return void
* @author Christian Jul Jensen <julle@typo3.org>
* @param boolean $enableCompression New value of compression flag
* @return void
* @author Christian Jul Jensen <julle@typo3.org>
*/
protected function setCompression($enableCompression) {
$this->useCompressed = $enableCompression;
......
if (!is_string($data)) {
throw new t3lib_cache_Exception_InvalidData(
'The specified data is of type "' . gettype($data) . '" but a string is expected.',
'The specified data is of type "' . gettype($data) .
'" but a string is expected.',
1207149231
);
}
......
$this->addIdentifierToTags($entryIdentifier, $tags);
} catch(Exception $exception) {
throw new t3lib_cache_Exception(
'Memcache was unable to connect to any server. ' . $exception->getMessage(),
'Memcache was unable to connect to any server. ' .
$exception->getMessage(),
1207208100
);
}
......
* @author Karsten Dambekalns <karsten@typo3.org>
*/
public function has($entryIdentifier) {
return (boolean) $this->memcache->get($this->identifierPrefix . $entryIdentifier);
return $this->memcache->get($this->identifierPrefix . $entryIdentifier) !== false;
}
/**
......
*/
public function remove($entryIdentifier) {
$this->removeIdentifierFromAllTags($entryIdentifier);
$this->memcache->delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
return $this->memcache->delete($this->identifierPrefix . $entryIdentifier);
}
......
);
}
$entries = array();
$entries = array();
$identifiers = $this->findIdentifiersTaggedWith($tag);
foreach($identifiers as $identifier) {
$entries[] = $this->get($identifier);
......
* @author Karsten Dambekalns <karsten@typo3.org>
*/
protected function getTagIndex() {
return (array) $this->memcache->get($this->identifierPrefix . '_tagIndex');
$tagIndex = $this->memcache->get($this->identifierPrefix . 'tagIndex');
return ($tagIndex == false ? array() : (array)$tagIndex);
}
/**
......
* @author Karsten Dambekalns <karsten@typo3.org>
*/
protected function setTagIndex(array $tags) {
$this->memcache->set(
$this->identifierPrefix . '_tagIndex',
array_unique($tags),
0,
0
);
$this->memcache->set($this->identifierPrefix . 'tagIndex', array_unique($tags), 0, 0);
}
/**
......
* @param string $entryIdentifier
* @param array Array of tags
* @author Karsten Dambekalns <karsten@typo3.org>
* @author Dmitry Dulepov
*/
protected function addIdentifierToTags($entryIdentifier, array $tags) {
foreach($tags as $tag) {
$identifiers = $this->findIdentifiersTaggedWith($tag);
$identifiers[] = $entryIdentifier;
$this->memcache->set(
$this->identifierPrefix . '_tag_' . $tag,
array_unique($identifiers)
);
// Update tag-to-identifier index
$identifiers = $this->findIdentifiersTaggedWith($tag);
if (array_search($entryIdentifier, $identifiers) === false) {
$identifiers[] = $entryIdentifier;
$this->memcache->set($this->identifierPrefix . 'tag_' . $tag,
$identifiers);
}
// Update identifier-to-tag index
$existingTags = $this->findTagsForIdentifier($entryIdentifier);
if (array_search($entryIdentifier, $existingTags) === false) {
$this->memcache->set($this->identifierPrefix . 'ident_' . $entryIdentifier,
array_merge($existingTags, $tags));
}
}
}
......
* @param string $entryIdentifier
* @param array Array of tags
* @author Karsten Dambekalns <karsten@typo3.org>
* @author Dmitry Dulepov
*/
protected function removeIdentifierFromAllTags($entryIdentifier) {
$tags = $this->getTagIndex();
foreach($tags as $tag) {
// Get tags for this identifier
$tags = $this->findTagsForIdentifier($entryIdentifier);
// Deassociate tags with this identifier
foreach ($tags as $tag) {
$identifiers = $this->findIdentifiersTaggedWith($tag);
// Formally array_search() below should never return false due to
// the behavior of findTagsForIdentifier(). But if reverse index is
// corrupted, we still can get 'false' from array_search(). This is
// not a problem because we are removing this identifier from
// anywhere.
if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
unset($identifiers[$key]);
if(array_search($entryIdentifier, $identifiers) !== FALSE) {
unset($identifiers[array_search($entryIdentifier, $identifiers)]);
if(count($identifiers)) {
$this->memcache->set(
$this->identifierPrefix . 'tag_' . $tag,
$identifiers
);
} else {
$this->removeTagsFromTagIndex(array($tag));
$this->memcache->delete($this->identifierPrefix . 'tag_' . $tag);
}
}
if(count($identifiers)) {
$this->memcache->set(
$this->identifierPrefix . '_tag_' . $tag,
array_unique($identifiers)
);
} else {
$this->removeTagsFromTagIndex(array($tag));
$this->memcache->delete($this->identifierPrefix . '_tag_' . $tag);
}
}
// Clear reverse tag index for this identifier
$this->memcache->delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
}
/**
......
* @author Karsten Dambekalns <karsten@typo3.org>
*/
public function findIdentifiersTaggedWith($tag) {
$identifiers = $this->memcache->get($this->identifierPrefix . '_tag_' . $tag);
$identifiers = $this->memcache->get($this->identifierPrefix . 'tag_' . $tag);
return ($identifiers === false ? array() : $identifiers);
}
if($identifiers !== FALSE) {
return (array) $identifiers;
} else {
return array();
}
/**
* Finds all tags for the given identifier. This function uses reverse tag
* index to search for tags.
*
* @param string $identifier Identifier to search tags for
* @return array Array with tags
*/
protected function findTagsForIdentifier($identifier) {
$tags = $this->memcache->get($this->identifierPrefix . 'ident_' . $identifier);
return ($tags == false ? array() : (array)$tags);
}
/**
* Returns idenfier prefix. Extensions can override this function to provide
* another identifier prefix if it is necessary for special purposes.
* Default identifier prefix is based on HTTP_HOST only. In most cases
* it is enough because there should be one host, which serves requests
* and other hosts that redirect to the serving host.
*
* @return string Identifier prefix, ending with underscore
* @author Dmitry Dulepov
*/
protected function getIdentifierPrefix() {
return 'TYPO3_' . md5(t3lib_div::getIndpEnv('HTTP_HOST')) . '_';
}
}
(1-1/2)