package.xml 0000664 0001750 0001750 00000027307 12762047301 011312 0 ustar jan jan
* - logger: (Horde_Log_Logger) Logger object.
* - prefix: (string) Prefix to use for key storage.
*
*
* @throws Horde_HashTable_Exception
*/
public function __construct(array $params = array())
{
$this->_params = array_merge($this->_params, $params);
$this->_init();
}
/**
* Do initialization.
*
* @throws Horde_HashTable_Exception
*/
protected function _init()
{
}
/**
*/
public function __set($name, $val)
{
switch ($name) {
case 'prefix':
$this->_params['prefix'] = $val;
break;
}
}
/**
*/
public function __get($name)
{
switch ($name) {
case 'locking':
return ($this instanceof Horde_HashTable_Lock);
case 'persistent':
return $this->_persistent;
}
}
/**
* Delete a key(s).
*
* @param mixed $keys The key or an array of keys to delete.
*
* @return boolean True on success.
*/
public function delete($keys)
{
if (!is_array($keys)) {
$keys = array($keys);
}
if ($todo = array_diff($keys, array_keys($this->_noexist))) {
$to_delete = array_fill_keys(array_map(array($this, 'hkey'), $todo), $todo);
if (!$this->_delete(array_keys($to_delete))) {
return false;
}
if (!empty($this->_params['logger'])) {
$this->_params['logger']->debug(sprintf(
'%s: Deleted keys (%s)',
get_class($this),
implode(',', array_keys($to_delete))
));
}
$this->_noexist = array_merge($this->_noexist, array_fill_keys(array_values($todo), true));
}
return true;
}
/**
* Delete keys.
*
* @param array $key An array of keys to delete.
*
* @return boolean True on success.
*/
abstract protected function _delete($keys);
/**
* Do the keys exists?
*
* @param mixed $keys The key or an array of keys.
*
* @return mixed A boolean/array of booleans indicating existence (return
* type is the type of $keys).
*/
public function exists($keys)
{
return $this->_getExists($keys, array($this, '_exists'));
}
/**
* Get data associated with keys.
*
* @param array $keys An array of keys.
*
* @return array Existence check. Values are boolean true/false.
*/
abstract protected function _exists($keys);
/**
* Get data associated with a key(s).
*
* @param mixed $keys The key or an array of keys.
*
* @return mixed The string/array on success (return type is the type of
* $keys); false value(s) on failure.
*/
public function get($keys)
{
return $this->_getExists($keys, array($this, '_get'));
}
/**
* Get data associated with keys.
*
* @param array $keys An array of keys.
*
* @return array The retrieved keys. Non-existent keys should return
* false as the value.
*/
abstract protected function _get($keys);
/**
* Does a get/exists action on a set of keys.
*
* @param mixed $keys The key or an array of keys.
* @param callable $callback The internal callback action.
*
* @return mixed The results.
*/
protected function _getExists($keys, $callback)
{
$noexist = $out = $todo = array();
if (!($ret_array = is_array($keys))) {
$keys = array($keys);
}
foreach ($keys as $val) {
if (isset($this->_noexist[$val])) {
$out[$val] = false;
$noexist[] = $val;
} else {
$todo[$this->hkey($val)] = $val;
}
}
if (!empty($todo)) {
foreach (call_user_func($callback, array_keys($todo)) as $key => $val) {
if ($val === false) {
$this->_noexist[$todo[$key]] = true;
$noexist[] = $todo[$key];
}
$out[$todo[$key]] = $val;
}
}
if (!empty($this->_params['logger'])) {
if ($tmp = array_diff(array_keys($out), $noexist)) {
$this->_params['logger']->debug(sprintf(
'%s: Retrieved keys (%s)',
get_class($this),
implode(',', $tmp)
));
}
if (!empty($noexist)) {
$this->_params['logger']->debug(sprintf(
'%s: Non-existent keys (%s)',
get_class($this),
implode(',', $noexist)
));
}
}
return $ret_array
? $out
: reset($out);
}
/**
* Set the value of a key.
*
* @param string $key The key.
* @param string $val The string to store.
* @param array $opts Additional options:
*
* - expire: (integer) Expiration time in seconds.
* DEFAULT: Doesn't expire.
* - replace: (boolean) Replace the value of key. If key doesn't exist,
* returns false.
* DEFAULT: false
*
*
* @return boolean True on success, false on error.
*/
public function set($key, $val, array $opts = array())
{
if (!empty($opts['replace']) && isset($this->_noexist[$key])) {
return false;
}
/* @todo BC: 'timeout' == 'expire' usage. */
if (isset($opts['timeout']) && !isset($opts['expire'])) {
$opts['expire'] = $opts['timeout'];
}
if ($this->_set($this->hkey($key), $val, $opts)) {
unset($this->_noexist[$key]);
$res = true;
} else {
$res = false;
}
if (!empty($this->_params['logger'])) {
$this->_params['logger']->debug(sprintf(
'%s: Set key %s(%s)',
get_class($this),
$res ? '' : 'FAILED ',
$key
));
}
return $res;
}
/**
* Set the value of a key.
*
* @param string $key The key.
* @param string $val The string to store.
* @param array $opts Additional options (see set()).
*
* @return boolean True on success.
*/
abstract protected function _set($key, $val, $opts);
/**
* Clear all hash table entries.
*/
abstract public function clear();
/**
* Add local prefix to beginning of key.
*
* @param string $key Key name.
*
* @return string Hash table key identifier.
*/
public function hkey($key)
{
return $this->_params['prefix'] . $key;
}
/* ArrayAccess methods. */
/**
*/
public function offsetExists($offset)
{
return $this->exists($offset);
}
/**
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
*/
public function offsetSet($offset, $value)
{
return $this->set($offset, $value);
}
/**
*/
public function offsetUnset($offset)
{
return $this->delete($offset);
}
/* Serializable methods. */
/**
*/
public function serialize()
{
return serialize($this->_params);
}
/**
*/
public function unserialize($data)
{
$this->_params = @unserialize($data);
$this->_init();
}
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Exception.php 0000664 0001750 0001750 00000001565 12762047301 020722 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
class Horde_HashTable_Exception extends Horde_Exception_Wrapped
{
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Lock.php 0000664 0001750 0001750 00000001702 12762047301 017645 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
interface Horde_HashTable_Lock
{
/**
* Obtain lock on a key.
*
* @param string $key The key to lock.
*/
public function lock($key);
/**
* Release lock on a key.
*
* @param string $key The key to lock.
*/
public function unlock($key);
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Memcache.php 0000664 0001750 0001750 00000005546 12762047301 020471 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
class Horde_HashTable_Memcache
extends Horde_HashTable_Base
implements Horde_HashTable_Lock
{
/**
* Memcache object.
*
* @var Horde_Memcache
*/
protected $_memcache;
/**
* @param array $params Additional configuration parameters:
*
* - memcache: (Horde_Memcache) [REQUIRED] Memcache object.
*
*/
public function __construct(array $params = array())
{
if (!isset($params['memcache'])) {
throw new InvalidArgumentException('Missing memcache parameter.');
}
parent::__construct($params);
}
/**
*/
protected function _init()
{
$this->_memcache = $this->_params['memcache'];
}
/**
*/
protected function _delete($keys)
{
$ret = true;
foreach ($keys as $val) {
if (!$this->_memcache->delete($val)) {
$ret = false;
}
}
return $ret;
}
/**
*/
protected function _exists($keys)
{
$out = array();
foreach ($this->_get($keys) as $key => $val) {
$out[$key] = ($val !== false);
}
return $out;
}
/**
*/
protected function _get($keys)
{
return (($res = $this->_memcache->get($keys)) === false)
? array_fill_keys($keys, false)
: $res;
}
/**
*/
protected function _set($key, $val, $opts)
{
return empty($opts['replace'])
? $this->_memcache->set($key, $val, isset($opts['expire']) ? $opts['expire'] : 0)
: $this->_memcache->replace($key, $val, isset($opts['expire']) ? $opts['expire'] : 0);
}
/**
*/
public function lock($key)
{
$this->_memcache->lock($key);
}
/**
*/
public function unlock($key)
{
$this->_memcache->unlock($key);
}
/**
*/
public function clear()
{
// No way to delete keys via memcache - have to drop entire DB.
$this->_memcache->flush();
}
/* Unique driver methods. */
/**
* Get the statistics output from the current memcache pool.
*
* @see Horde_Memcache#stats()
*/
public function stats()
{
return $this->_memcache->stats();
}
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Memory.php 0000664 0001750 0001750 00000004532 12762047301 020231 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
class Horde_HashTable_Memory
extends Horde_HashTable_Base
implements Horde_HashTable_Lock
{
/**
* Data.
*
* @var array
*/
protected $_data = array();
/**
*/
protected function _delete($keys)
{
foreach ($keys as $val) {
unset($this->_data[$val]);
}
return true;
}
/**
*/
protected function _exists($keys)
{
$curr = time();
$out = array();
foreach ($keys as $val) {
if (isset($this->_data[$val]) &&
(!isset($this->_data[$val]['l']) ||
($this->_data[$val]['l'] >= $curr))) {
$out[$val] = true;
} else {
$out[$val] = false;
$this->delete($val);
}
}
return $out;
}
/**
*/
protected function _get($keys)
{
$exists = $this->_exists($keys);
$out = array();
foreach ($keys as $val) {
$out[$val] = $exists[$val]
? $this->_data[$val]['v']
: false;
}
return $out;
}
/**
*/
protected function _set($key, $val, $opts)
{
if (!empty($opts['replace'])) {
$exists = $this->_exists(array($key));
if (!$exists[$key]) {
return false;
}
}
$this->_data[$key] = array_filter(array(
'l' => empty($opts['expire']) ? null : (time() + $opts['expire']),
'v' => $val
));
return true;
}
/**
*/
public function clear()
{
$this->_data = array();
}
/**
*/
public function lock($key)
{
}
/**
*/
public function unlock($key)
{
}
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Null.php 0000664 0001750 0001750 00000002405 12762047301 017670 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
class Horde_HashTable_Null
extends Horde_HashTable_Base
implements Horde_HashTable_Lock
{
/**
*/
protected function _delete($keys)
{
return true;
}
/**
*/
protected function _exists($keys)
{
return false;
}
/**
*/
protected function _get($keys)
{
return array_fill_keys($keys, false);
}
/**
*/
protected function _set($key, $val, $opts)
{
return empty($opts['replace']);
}
/**
*/
public function clear()
{
}
/**
*/
public function lock($key)
{
}
/**
*/
public function unlock($key)
{
}
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Predis.php 0000664 0001750 0001750 00000011046 12762047301 020205 0 ustar jan jan
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
*/
class Horde_HashTable_Predis
extends Horde_HashTable_Base
implements Horde_HashTable_Lock
{
/* Suffix added to key to create the lock entry. */
const LOCK_SUFFIX = '_l';
/* Lock timeout (in seconds). */
const LOCK_TIMEOUT = 30;
/**
* Locked keys.
*
* @var array
*/
protected $_locks = array();
/**
* Predis client object.
*
* @var Predis\Client
*/
protected $_predis;
/**
* @param array $params Additional configuration parameters:
*
* - predis: (Predis\Client) [REQUIRED] Predis client object.
*
*/
public function __construct(array $params = array())
{
if (!isset($params['predis'])) {
throw InvalidArgumentException('Missing predis parameter.');
}
parent::__construct($params);
register_shutdown_function(array($this, 'shutdown'));
}
/**
*/
protected function _init()
{
$this->_predis = $this->_params['predis'];
}
/**
* Shutdown function.
*/
public function shutdown()
{
foreach (array_keys($this->_locks) as $key) {
$this->unlock($key);
}
}
/**
*/
protected function _delete($keys)
{
return (count($keys) == $this->_predis->del($keys));
}
/**
*/
protected function _exists($keys)
{
$pipeline = $this->_predis->pipeline();
foreach ($keys as $val) {
$pipeline->exists($val);
}
$exists = array();
foreach ($pipeline->execute() as $key => $val) {
$exists[$keys[$key]] = (bool)$val;
}
return $exists;
}
/**
*/
protected function _get($keys)
{
$keys = array_values($keys);
$out = array();
try {
$data = $this->_predis->mget($keys);
} catch (Exception $e) {
/* MGET doesn't work on clusters. */
$data = array();
foreach ($keys as $key) {
$data[$key] = $this->_predis->get($key);
}
}
foreach ($data as $key => $val) {
$out[$keys[$key]] = is_null($val)
? false
: $val;
}
return $out;
}
/**
*/
protected function _set($key, $val, $opts)
{
if (!empty($opts['replace']) && !$this->_predis->exists($key)) {
return false;
}
/* Can't use SETEX, since 2.0 server is not guaranteed. */
if (!$this->_predis->set($key, $val)) {
return false;
}
if (!empty($opts['expire'])) {
$this->_predis->expire($key, $opts['expire']);
}
return true;
}
/**
*/
public function clear()
{
try {
$res = $this->_predis->keys(addcslashes(strval($this->_params['prefix']), '?*') . '*');
/* Before 2.0, KEYS returns a space-delimited string. */
if (is_string($res)) {
$res = explode(' ', $res);
}
if ($res) {
$this->_predis->del($res);
}
} catch (Exception $e) {
}
}
/**
*/
public function hkey($key)
{
/* Key is MD5 encoded. But don't MD5 encode the prefix part, or else
* clear() won't work properly. */
return $this->_params['prefix'] . hash('md5', $key);
}
/**
*/
public function lock($key)
{
$hkey = $this->hkey($key) . self::LOCK_SUFFIX;
$i = 0;
while (!$this->_predis->setnx($hkey, 1)) {
usleep(min(pow(2, $i++) * 10000, 100000));
}
$this->_predis->expire($hkey, self::LOCK_TIMEOUT);
$this->_locks[$key] = true;
}
/**
*/
public function unlock($key)
{
$this->_predis->del($this->hkey($key) . self::LOCK_SUFFIX);
unset($this->_locks[$key]);
}
}
Horde_HashTable-1.2.6/lib/Horde/HashTable/Vfs.php 0000664 0001750 0001750 00000006017 12762047301 017517 0 ustar jan jan
* @category Horde
* @copyright 2014-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
* @since 1.2.0
*/
class Horde_HashTable_Vfs
extends Horde_HashTable_Base
{
/**
*/
protected $_persistent = true;
/**
* The VFS object.
*
* @var Horde_Vfs_Base
*/
protected $_vfs;
/**
* @param array $params Additional configuration parameters:
*
* - vfs: (Horde_Vfs_Base) [REQUIRED] VFS object.
* - vfspath: (string) VFS path to use.
*
*/
public function __construct(array $params = array())
{
if (!isset($params['vfs'])) {
throw new InvalidArgumentException('Missing vfs parameter.');
}
parent::__construct(array_merge(array(
'vfspath' => 'hashtable_vfs'
), $params));
}
/**
*/
protected function _init()
{
$this->_vfs = $this->_params['vfs'];
}
/**
*/
protected function _delete($keys)
{
$ret = true;
foreach ($keys as $key) {
try {
$this->_vfs->deleteFile($this->_params['vfspath'], $key);
} catch (Horde_Vfs_Exception $e) {
$ret = false;
}
}
return $ret;
}
/**
*/
protected function _exists($keys)
{
$out = array();
foreach ($keys as $key) {
$out[$key] = $this->_vfs->exists($this->_params['vfspath'], $key);
}
return $out;
}
/**
*/
protected function _get($keys)
{
$out = array();
foreach ($keys as $key) {
try {
$out[$key] = $this->_vfs->read($this->_params['vfspath'], $key);
} catch (Horde_Vfs_Exception $e) {
$out[$key] = false;
}
}
return $out;
}
/**
*/
protected function _set($key, $val, $opts)
{
try {
$this->_vfs->writeData($this->_params['vfspath'], $key, $val, true);
} catch (Horde_Vfs_Exception $e) {
return false;
}
return true;
}
/**
*/
public function clear()
{
try {
$this->_vfs->emptyFolder($this->_params['vfspath']);
} catch (Horde_Vfs_Exception $e) {}
}
/**
*/
public function hkey($key)
{
/* Key is SHA-1 encoded (can't use FNV1-32 here, since key must be
* the same if upgrading from PHP 5.3 -> 5.4+). */
return hash('sha1', $this->_params['prefix'] . $key);
}
}
Horde_HashTable-1.2.6/test/Horde/HashTable/Driver/MemcacheTest.php 0000664 0001750 0001750 00000002671 12762047301 022771 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
* @subpackage UnitTests
*/
/**
* Tests for the HashTable memcache storage driver.
*
* @author Jan Schneider