protected $_db;
/**
- * The memory cache object to use, if configured.
- *
- * @var Horde_Cache
- */
- protected $_mc = null;
-
- /**
* Constructor.
*
* @param array $params Parameters:
* 'db' - (Horde_Db_Adapter_Base) [REQUIRED] The DB instance.
* 'table' - (string) The name of the cache table.
* DEFAULT: 'horde_cache'
- * 'use_memorycache' - (Horde_Cache) Use this memory caching object to
- * cache the data (to avoid DB accesses).
* </pre>
*
* @throws Horde_Cache_Exception
throw new Horde_Cache_Exception('Missing db parameter.');
}
$this->_db = $params['db'];
-
- if (isset($params['use_memorycache'])) {
- $this->_mc = $params['use_memorycache'];
- }
-
- unset($params['db'], $params['use_memorycache']);
+ unset($params['db']);
$params = array_merge(array(
'table' => 'horde_cache',
$okey = $key;
$key = hash('md5', $key);
- if ($this->_mc) {
- $data = $this->_mc->get($key, $lifetime);
- if ($data !== false) {
- return $data;
- }
- }
-
$timestamp = time();
$maxage = $timestamp - $lifetime;
return false;
}
- if ($this->_mc) {
- $this->_mc->set($key, $result);
- }
-
if ($this->_logger) {
$this->_logger->log(sprintf('Cache hit: %s (Id %s newer than %d)', $okey, $key, $maxage), 'DEBUG');
}
$okey = $key;
$key = hash('md5', $key);
- if ($this->_mc) {
- $this->_mc->set($key, $data);
- }
-
$timestamp = time();
// 0 lifetime indicates the object should not be GC'd.
$okey = $key;
$key = hash('md5', $key);
- if ($this->_mc && $this->_mc->exists($key, $lifetime)) {
- return true;
- }
-
/* Build SQL query. */
$query = 'SELECT 1 FROM ' . $this->_params['table'] .
' WHERE cache_id = ?';
{
$key = hash('md5', $key);
- if ($this->_mc) {
- $this->_mc->expire($key);
- }
-
$query = 'DELETE FROM ' . $this->_params['table'] .
' WHERE cache_id = ?';
$values = array($key);
--- /dev/null
+<?php
+/**
+ * Horde_Cache_Stack:: is a Cache implementation that will loop through a
+ * given list of Cache drivers to search for a cached value. This driver
+ * allows for use of caching backends on top of persistent backends.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package Cache
+ */
+class Horde_Cache_Stack extends Horde_Cache_Base
+{
+ /**
+ * Stack of cache drivers.
+ *
+ * @var string
+ */
+ protected $_stack = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Parameters:
+ * <pre>
+ * 'stack' - (array) [REQUIRED] A list of cache drivers to loop
+ * through, in order of priority. The last entry is considered
+ * the 'master' driver, for purposes of writes.
+ * Each value should contain an array with two keys: 'driver', a
+ * string value with the Cache driver to use, and 'params',
+ * containing any parameters needed by this driver.
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ if (!isset($params['stack'])) {
+ throw new InvalidArgumentException('Missing stack parameter.');
+ }
+
+ foreach ($params['stack'] as $val) {
+ $this->_stack[] = Horde_Cache::factory($val['driver'], $val['params']);
+ }
+
+ unset($params['stack']);
+
+ parent::__construct($params);
+ }
+
+ /**
+ * Attempts to retrieve a cached object and return it to the
+ * caller.
+ *
+ * @param string $key Object ID to query.
+ * @param integer $lifetime Lifetime of the object in seconds.
+ *
+ * @return mixed Cached data, or false if none was found.
+ */
+ public function get($key, $lifetime = 1)
+ {
+ foreach ($this->_stack as $val) {
+ $result = $val->get($key, $lifetime);
+ if ($result !== false) {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Attempts to store an object in the cache.
+ *
+ * @param string $key Object ID used as the caching key.
+ * @param mixed $data Data to store in the cache.
+ * @param integer $lifetime Object lifetime - i.e. the time before the
+ * data becomes available for garbage
+ * collection. If null use the default Horde GC
+ * time. If 0 will not be GC'd.
+ *
+ * @return boolean True on success, false on failure.
+ */
+ public function set($key, $data, $lifetime = null)
+ {
+ /* Do writes in *reverse* order - it is OK if a write to one of the
+ * non-master backends fails. */
+ $master = true;
+
+ foreach (array_reverse($this->_stack) as $val) {
+ $result = $val->set($key, $data, $lifetime);
+ if ($result === false) {
+ if ($master) {
+ return false;
+ }
+
+ /* Attempt to invalidate cache if write failed. */
+ $val->expire($id);
+ }
+ $master = false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a given key exists in the cache, valid for the given
+ * lifetime.
+ *
+ * @param string $key Cache key to check.
+ * @param integer $lifetime Lifetime of the key in seconds.
+ *
+ * @return boolean Existence.
+ */
+ public function exists($key, $lifetime = 1)
+ {
+ foreach ($this->_stack as $val) {
+ $result = $val->exists($key, $lifetime);
+ if ($result === true) {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Expire any existing data for the given key.
+ *
+ * @param string $key Cache key to expire.
+ *
+ * @return boolean Success or failure.
+ */
+ public function expire($key)
+ {
+ /* Only report success from master. */
+ $master = $success = true;
+
+ foreach (array_reverse($this->_stack) as $val) {
+ $result = $val->expire($id);
+ if ($master && ($result === false)) {
+ $success = false;
+ }
+ $master = false;
+ }
+
+ return $success;
+ }
+
+}
<file name="Mock.php" role="php" />
<file name="Null.php" role="php" />
<file name="Sql.php" role="php" />
+ <file name="Stack.php" role="php" />
<file name="Xcache.php" role="php" />
<file name="Zps4.php" role="php" />
</dir> <!-- /lib/Horde/Cache -->
<name>Log</name>
<channel>pear.horde.org</channel>
</package>
+ <package>
+ <name>Memcache</name>
+ <channel>pear.horde.org</channel>
+ </package>
<extension>
<name>apc</name>
</extension>
<extension>
<name>eaccelerator</name>
</extension>
- <extension>
- <name>memcache</name>
- </extension>
</optional>
</dependencies>
<phprelease>
<install name="lib/Horde/Cache/Mock.php" as="Horde/Cache/Mock.php" />
<install name="lib/Horde/Cache/Null.php" as="Horde/Cache/Null.php" />
<install name="lib/Horde/Cache/Sql.php" as="Horde/Cache/Sql.php" />
+ <install name="lib/Horde/Cache/Stack.php" as="Horde/Cache/Stack.php" />
<install name="lib/Horde/Cache/Xcache.php" as="Horde/Cache/Xcache.php" />
<install name="lib/Horde/Cache/Zps4.php" as="Horde/Cache/Zps4.php" />
<install name="lib/Horde/Cache.php" as="Horde/Cache.php" />
{
public function create(Horde_Injector $injector)
{
- return $this->_getCacheInstance($GLOBALS['conf']['cache']['driver'], $injector);
- }
-
- protected function _getCacheInstance($driver, $injector)
- {
- if (empty($driver) || (strcasecmp($driver, 'None') === 0)) {
+ $driver = empty($GLOBALS['conf']['cache']['driver'])
+ ? 'Null'
+ : $GLOBALS['conf']['cache']['driver'];
+ if (strcasecmp($driver, 'None') === 0) {
$driver = 'Null';
}
$params = Horde::getDriverConfig('cache', $driver);
+ if (isset($GLOBALS['conf']['cache']['default_lifetime'])) {
+ $params['lifetime'] = $GLOBALS['conf']['cache']['default_lifetime'];
+ }
+
+ $logger = $injector->getInstance('Horde_Log_Logger');
if (strcasecmp($driver, 'Memcache') === 0) {
$params['memcache'] = $injector->getInstance('Horde_Memcache');
- } elseif (strcasecmp($driver, 'Sql') === 0) {
- $params['db'] = $injector->getInstance('Horde_Db_Adapter_Base');
+ } else {
+ if (strcasecmp($driver, 'Sql') === 0) {
+ $params['db'] = $injector->getInstance('Horde_Db_Adapter_Base');
+ }
if (!empty($params['use_memorycache'])) {
- $params['use_memorycache'] = $this->_getCacheInstance($params['use_memorycache'], $injector);
+ $params = array(
+ 'stack' => array(
+ array(
+ 'driver' => 'Memcache',
+ 'params' => array_merge($params, array(
+ 'logger' => $logger,
+ 'memcache' => $injector->getInstance('Horde_Memcache')
+ ))
+ ),
+ array(
+ 'driver' => $driver,
+ 'params' => array_merge($params, array(
+ 'logger' => $logger
+ ))
+ )
+ )
+ );
+ $driver = 'Stack';
}
}
- if (isset($GLOBALS['conf']['cache']['default_lifetime'])) {
- $params['lifetime'] = $GLOBALS['conf']['cache']['default_lifetime'];
- }
-
$params['logger'] = $injector->getInstance('Horde_Log_Logger');
return Horde_Cache::factory($driver, $params);