package.xml 0000644 0001750 0000764 00000015517 12173542533 013205 0 ustar slusarz slusarz
* - 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;
}
$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)
{
$out = $todo = array();
if (!($ret_array = is_array($keys))) {
$keys = array($keys);
}
foreach ($keys as $val) {
if (isset($this->_noexist[$val])) {
$out[$val] = false;
} 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;
}
$out[$todo[$key]] = $val;
}
}
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:
*
* - replace: (boolean) Replace the value of key. If key doesn't exist,
* returns false.
* DEFAULT: false
* - timeout: (integer) Expiration time in seconds.
* DEFAULT: Doesn't expire.
*
*
* @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;
}
if ($this->_set($this->hkey($key), $val, $opts)) {
unset($this->_noexist[$key]);
return true;
}
return false;
}
/**
* 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.1.0/lib/Horde/HashTable/Exception.php 0000644 0001750 0000764 00000001541 12173542533 022600 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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.1.0/lib/Horde/HashTable/Lock.php 0000644 0001750 0000764 00000001663 12173542533 021537 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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.1.0/lib/Horde/HashTable/Memcache.php 0000644 0001750 0000764 00000005527 12173542533 022354 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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.1.0/lib/Horde/HashTable/Memory.php 0000644 0001750 0000764 00000004515 12173542533 022116 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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['timeout']) ? null : (time() + $opts['timeout']),
'v' => $val
));
return true;
}
/**
*/
public function clear()
{
$this->_data = array();
}
/**
*/
public function lock($key)
{
}
/**
*/
public function unlock($key)
{
}
}
Horde_HashTable-1.1.0/lib/Horde/HashTable/Null.php 0000644 0001750 0000764 00000002366 12173542533 021562 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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.1.0/lib/Horde/HashTable/Predis.php 0000644 0001750 0000764 00000010157 12173542533 022073 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 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);
}
return array_combine($keys, $pipeline->execute());
}
/**
*/
protected function _get($keys)
{
$keys = array_values($keys);
$out = array();
foreach ($this->_predis->mget($keys) 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);
}
$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->_prefix . hash('md5', $key);
}
/**
*/
public function lock($key)
{
$hkey = $this->hkey($key) . self::LOCK_SUFFIX;
while (!$this->_predis->setnx($hkey, 1)) {
/* Wait 0.1 secs before attempting again. */
usleep(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);
$this->_locks[$key] = false;
}
}
Horde_HashTable-1.1.0/test/Horde/HashTable/Driver/MemoryTest.php 0000644 0001750 0000764 00000001536 12173542533 024422 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 Horde LLC
* @ignore
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
* @subpackage UnitTests
*/
class Horde_HashTable_Driver_MemoryTest extends Horde_HashTable_Driver_TestBase
{
static public function setUpBeforeClass()
{
self::$_driver = new Horde_HashTable_Memory();
}
}
Horde_HashTable-1.1.0/test/Horde/HashTable/Driver/TestBase.php 0000644 0001750 0000764 00000004157 12173542533 024026 0 ustar slusarz slusarz
* @category Horde
* @copyright 2013 Horde LLC
* @ignore
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package HashTable
* @subpackage UnitTests
*/
abstract class Horde_HashTable_Driver_TestBase extends Horde_Test_Case
{
static protected $_driver;
public function testSet()
{
$this->assertTrue(self::$_driver->set('foo', 1));
/* This should immediately expire. */
$this->assertTrue(self::$_driver->set('foo2', 1, array('timeout' => -1)));
$this->assertFalse(self::$_driver->set('foo3', 1, array('replace' => true)));
$this->assertTrue(self::$_driver->set('foo3', 1));
$this->assertTrue(self::$_driver->set('foo3', 2, array('replace' => true)));
}
/**
* @depends testSet
*/
public function testExists()
{
$this->assertTrue(self::$_driver->exists('foo'));
$this->assertFalse(self::$_driver->exists('foo2'));
$this->assertTrue(self::$_driver->exists('foo3'));
}
/**
* @depends testSet
* @depends testExists
*/
public function testGet()
{
$this->assertEquals(
1,
self::$_driver->get('foo')
);
$this->assertFalse(self::$_driver->get('foo2'));
$this->assertEquals(
2,
self::$_driver->get('foo3')
);
}
/**
* @depends testExists
* @depends testSet
* @depends testGet
*/
public function testDelete()
{
$this->assertTrue(self::$_driver->delete('foo'));
$this->assertTrue(self::$_driver->delete('foo2'));
$this->assertTrue(self::$_driver->delete('foo3'));
}
}
Horde_HashTable-1.1.0/test/Horde/HashTable/AllTests.php 0000644 0001750 0000764 00000000132 12173542533 022601 0 ustar slusarz slusarz run();
Horde_HashTable-1.1.0/test/Horde/HashTable/bootstrap.php 0000644 0001750 0000764 00000000143 12173542533 023065 0 ustar slusarz slusarz