package.xml 0000664 0001750 0001750 00000025202 12653740533 011310 0 ustar jan jan
* - collection: (string) The collection name.
* - mongo_db: [REQUIRED] (Horde_Mongo_Client) A MongoDB client object.
*
*/
public function __construct(array $params = array())
{
if (!isset($params['mongo_db'])) {
throw new InvalidArgumentException('Missing mongo_db parameter.');
}
parent::__construct(array_merge(array(
'collection' => 'horde_locks'
), $params));
$this->_db = $this->_params['mongo_db']->selectCollection(null, $this->_params['collection']);
}
/**
* Destructor.
*/
public function __destruct()
{
if (!rand(0, 999)) {
$this->gc();
}
}
/**
*/
public function getLockInfo($lockid)
{
$query = array(
self::LID => $lockid,
'$or' => array(
array(
self::EXPIRY_TS => array(
'$gte' => time()
),
),
array(
self::EXPIRY_TS => Horde_Lock::PERMANENT
)
)
);
try {
return $this->_mapFields($this->_db->findOne($query));
} catch (MongoException $e) {
throw new Horde_Lock_Exception($e);
}
}
/**
*/
public function getLocks($scope = null, $principal = null, $type = null)
{
$query = array(
'$or' => array(
array(
self::EXPIRY_TS => array(
'$gte' => time()
),
),
array(
self::EXPIRY_TS => Horde_Lock::PERMANENT
)
)
);
// Check to see if we need to filter the results
if (!empty($principal)) {
$query[self::PRINCIPAL] = $principal;
}
if (!empty($scope)) {
$query[self::SCOPE] = $scope;
}
if (!empty($type)) {
$query[self::TYPE] = $type;
}
try {
$result = $this->_db->find($query);
} catch (MongoException $e) {
throw new Horde_Lock_Exception($e);
}
$locks = array();
foreach ($result as $val) {
$locks[$val[self::LID]] = $this->_mapFields($val);
}
return $locks;
}
/**
*/
public function resetLock($lockid, $lifetime)
{
if (!$this->getLockInfo($lockid)) {
return false;
}
$now = time();
$expiration = ($lifetime == Horde_Lock::PERMANENT)
? Horde_Lock::PERMANENT
: ($now + $lifetime);
try {
$this->_db->update(array(
self::EXPIRY_TS => array(
'$ne' => Horde_Lock::PERMANENT
),
self::LID => $lockid
), array(
'$set' => array(
self::EXPIRY_TS => $expiration,
self::UPDATE_TS => $now
)
));
} catch (MongoException $e) {
throw new Horde_Lock_Exception($e);
}
return true;
}
/**
*/
public function setLock($requestor, $scope, $principal,
$lifetime = 1, $type = Horde_Lock::TYPE_SHARED)
{
$oldlocks = $this->getLocks(
$scope,
$principal,
($type == Horde_Lock::TYPE_SHARED) ? Horde_Lock::TYPE_EXCLUSIVE : null
);
if (count($oldlocks) != 0) {
// A lock exists. Deny the new request.
if ($this->_logger) {
$this->_logger->log(sprintf('Lock requested for %s denied due to existing lock.', $principal), 'NOTICE');
}
return false;
}
$lockid = strval(new Horde_Support_Uuid());
$now = time();
$expiration = ($lifetime == Horde_Lock::PERMANENT)
? Horde_Lock::PERMANENT
: ($now + $lifetime);
try {
$this->_db->insert(array(
self::EXPIRY_TS => $expiration,
self::LID => $lockid,
self::ORIGIN_TS => $now,
self::OWNER => $requestor,
self::PRINCIPAL => $principal,
self::SCOPE => $scope,
self::TYPE => $type,
self::UPDATE_TS => $now
));
} catch (MongoException $e) {
throw new Horde_Lock_Exception($e);
}
if ($this->_logger) {
$this->_logger->log(sprintf('Lock %s set successfully by %s in scope %s on "%s"', $lockid, $requestor, $scope, $principal), 'DEBUG');
}
return $lockid;
}
/**
*/
public function clearLock($lockid)
{
if (empty($lockid)) {
throw new Horde_Lock_Exception('Must supply a valid lock ID.');
}
try {
/* Since we're trying to clear the lock we don't care whether it
is still valid or not. Unconditionally remove it. */
$this->_db->remove(array(
self::LID => $lockid
));
} catch (MongoException $e) {
throw new Horde_Lock_Exception($e);
}
if ($this->_logger) {
$this->_logger->log(sprintf('Lock %s cleared successfully.', $lockid), 'DEBUG');
}
return true;
}
/**
* Do garbage collection needed for the driver.
*/
public function gc()
{
try {
$result = $this->_db->remove(array(
self::EXPIRY_TS => array(
'$lt' => time(),
'$ne' => Horde_Lock::PERMANENT
)
));
if ($this->_logger) {
$this->_logger->log(sprintf('Lock garbage collection cleared %d locks.', $result['n']), 'DEBUG');
}
} catch (MongoException $e) {}
}
/**
* Map return to SQL fields.
*
* @return array
*/
protected function _mapFields($res)
{
$out = array();
if ($res) {
foreach ($res as $key => $val) {
if (isset($this->_map[$key])) {
$out[$this->_map[$key]] = $val;
}
}
}
return $out;
}
}
Horde_Lock-2.1.2/lib/Horde/Lock/Null.php 0000664 0001750 0001750 00000011564 12653740533 015772 0 ustar jan jan
* @category Horde
* @package Lock
*/
class Horde_Lock_Null extends Horde_Lock
{
/**
* Return an array of information about the requested lock.
*
* @param string $lockid Lock ID to look up.
*
* @return array Lock information.
* @throws Horde_Lock_Exception
*/
public function getLockInfo($lockid)
{
return array();
}
/**
* Return a list of valid locks with the option to limit the results
* by principal, scope and/or type.
*
* @param string $scope The scope of the lock. Typically the name of
* the application requesting the lock or some
* other identifier used to group locks together.
* @param string $principal Principal for which to check for locks
* @param integer $type Only return locks of the given type.
* Defaults to null, or all locks
*
* @return array Array of locks with the ID as the key and the lock details
* as the value. If there are no current locks this will
* return an empty array.
* @throws Horde_Lock_Exception
*/
public function getLocks($scope = null, $principal = null, $type = null)
{
return array();
}
/**
* Extend the valid lifetime of a valid lock to now + $extend.
*
* @param string $lockid Lock ID to reset. Must be a valid, non-expired
* lock.
* @param integer $extend Extend lock this many seconds from now.
*
* @return boolean Returns true on success.
* @throws Horde_Lock_Exception
*/
public function resetLock($lockid, $extend)
{
return true;
}
/**
* Sets a lock on the requested principal and returns the generated lock
* ID. NOTE: No security checks are done in the Horde_Lock API. It is
* expected that the calling application has done all necessary security
* checks before requesting a lock be granted.
*
* @param string $requestor User ID of the lock requestor.
* @param string $scope The scope of the lock. Typically the name of
* the application requesting the lock or some
* other identifier used to group locks
* together.
* @param string $principal A principal on which a lock should be
* granted. The format can be any string but is
* suggested to be in URI form.
* @param integer $lifetime Time (in seconds) for which the lock will be
* considered valid.
* @param string exclusive One of Horde_Lock::TYPE_SHARED or
* Horde_Lock::TYPE_EXCLUSIVE.
* - An exclusive lock will be enforced strictly
* and must be interpreted to mean that the
* resource can not be modified. Only one
* exclusive lock per principal is allowed.
* - A shared lock is one that notifies other
* potential lock requestors that the resource
* is in use. This lock can be overridden
* (cleared or replaced with a subsequent
* call to setLock()) by other users. Multiple
* users may request (and will be granted) a
* shared lock on a given principal. All locks
* will be considered valid until they are
* cleared or expire.
*
* @return mixed A string lock ID.
* @throws Horde_Lock_Exception
*/
public function setLock($requestor, $scope, $principal, $lifetime = 1,
$exclusive = Horde_Lock::TYPE_SHARED)
{
return strval(new Horde_Support_Uuid());
}
/**
* Removes a lock given the lock ID.
* NOTE: No security checks are done in the Horde_Lock API. It is
* expected that the calling application has done all necessary security
* checks before requesting a lock be cleared.
*
* @param string $lockid The lock ID as generated by a previous call
* to setLock()
*
* @return boolean Returns true on success.
* @throws Horde_Lock_Exception
*/
public function clearLock($lockid)
{
return true;
}
}
Horde_Lock-2.1.2/lib/Horde/Lock/Sql.php 0000664 0001750 0001750 00000017730 12653740533 015620 0 ustar jan jan
* CREATE TABLE horde_locks (
* lock_id VARCHAR(36) NOT NULL,
* lock_owner VARCHAR(32) NOT NULL,
* lock_scope VARCHAR(32) NOT NULL,
* lock_principal VARCHAR(255) NOT NULL,
* lock_origin_timestamp BIGINT NOT NULL,
* lock_update_timestamp BIGINT NOT NULL,
* lock_expiry_timestamp BIGINT NOT NULL,
* lock_type TINYINT NOT NULL,
*
* PRIMARY KEY (lock_id)
* );
*
*
* Copyright 2008-2016 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Ben Klang
* 'db' - (Horde_Db_Adapter) [REQUIRED] The DB instance.
* 'table' - (string) The name of the lock table in 'database'.
* DEFAULT: 'horde_locks'
*
*
* @throws Horde_Lock_Exception
*/
public function __construct($params = array())
{
if (!isset($params['db'])) {
throw new Horde_Lock_Exception('Missing db parameter.');
}
$this->_db = $params['db'];
unset($params['db']);
$params = array_merge(array(
'table' => 'horde_locks'
), $params);
parent::__construct($params);
/* Only do garbage collection 0.1% of the time we create an object. */
if (substr(time(), -3) === '000') {
register_shutdown_function(array($this, 'doGC'));
}
}
/**
* Return an array of information about the requested lock.
*
* @see Horde_Lock_Base::getLockInfo()
*/
public function getLockInfo($lockid)
{
$now = time();
$sql = 'SELECT lock_id, lock_owner, lock_scope, lock_principal, '
. 'lock_origin_timestamp, lock_update_timestamp, '
. 'lock_expiry_timestamp, lock_type FROM '
. $this->_params['table']
. ' WHERE lock_id = ? AND '
. '(lock_expiry_timestamp >= ? OR lock_expiry_timestamp = ?)';
$values = array($lockid, $now, Horde_Lock::PERMANENT);
try {
return $this->_db->selectOne($sql, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_Lock_Exception($e);
}
}
/**
* Return a list of valid locks with the option to limit the results
* by principal, scope and/or type.
*
* @see Horde_Lock_Base::getLocks()
*/
public function getLocks($scope = null, $principal = null, $type = null)
{
$now = time();
$sql = 'SELECT lock_id, lock_owner, lock_scope, lock_principal, '
. 'lock_origin_timestamp, lock_update_timestamp, '
. 'lock_expiry_timestamp, lock_type FROM '
. $this->_params['table']
. ' WHERE (lock_expiry_timestamp >= ? OR lock_expiry_timestamp = ?)';
$values = array($now, Horde_Lock::PERMANENT);
// Check to see if we need to filter the results
if (!empty($principal)) {
$sql .= ' AND lock_principal = ?';
$values[] = $principal;
}
if (!empty($scope)) {
$sql .= ' AND lock_scope = ?';
$values[] = $scope;
}
if (!empty($type)) {
$sql .= ' AND lock_type = ?';
$values[] = $type;
}
try {
$result = $this->_db->selectAll($sql, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_Lock_Exception($e);
}
$locks = array();
foreach ($result as $row) {
$locks[$row['lock_id']] = $row;
}
return $locks;
}
/**
* Extend the valid lifetime of a valid lock to now + $lifetime.
*
* @see Horde_Lock_Base::resetLock()
*/
public function resetLock($lockid, $lifetime)
{
$now = time();
if (!$this->getLockInfo($lockid)) {
return false;
}
$expiration = $lifetime == Horde_Lock::PERMANENT ? Horde_Lock::PERMANENT : $now + $lifetime;
$sql = 'UPDATE ' . $this->_params['table'] . ' SET ' .
'lock_update_timestamp = ?, lock_expiry_timestamp = ? ' .
'WHERE lock_id = ? AND lock_expiry_timestamp <> ?';
$values = array($now, $expiration, $lockid, Horde_Lock::PERMANENT);
try {
$this->_db->update($sql, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_Lock_Exception($e);
}
return true;
}
/**
* Sets a lock on the requested principal and returns the generated lock
* ID.
*
* @see Horde_Lock_Base::setLock()
*/
public function setLock($requestor, $scope, $principal,
$lifetime = 1, $type = Horde_Lock::TYPE_SHARED)
{
$oldlocks = $this->getLocks(
$scope, $principal,
$type == Horde_Lock::TYPE_SHARED ? Horde_Lock::TYPE_EXCLUSIVE : null);
if (count($oldlocks) != 0) {
// A lock exists. Deny the new request.
if ($this->_logger) {
$this->_logger->log(sprintf('Lock requested for %s denied due to existing lock.', $principal), 'NOTICE');
}
return false;
}
$lockid = (string)new Horde_Support_Uuid();
$now = time();
$expiration = $lifetime == Horde_Lock::PERMANENT ? Horde_Lock::PERMANENT : $now + $lifetime;
$sql = 'INSERT INTO ' . $this->_params['table'] . ' (lock_id, lock_owner, lock_scope, lock_principal, lock_origin_timestamp, lock_update_timestamp, lock_expiry_timestamp, lock_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
$values = array($lockid, $requestor, $scope, $principal, $now, $now,
$expiration, $type);
try {
$this->_db->insert($sql, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_Lock_Exception($e);
}
if ($this->_logger) {
$this->_logger->log(sprintf('Lock %s set successfully by %s in scope %s on "%s"', $lockid, $requestor, $scope, $principal), 'DEBUG');
}
return $lockid;
}
/**
* Removes a lock given the lock ID.
*
* @see Horde_Lock_Base::clearLock()
*/
public function clearLock($lockid)
{
if (empty($lockid)) {
throw new Horde_Lock_Exception('Must supply a valid lock ID.');
}
// Since we're trying to clear the lock we don't care
// whether it is still valid or not. Unconditionally
// remove it.
$sql = 'DELETE FROM ' . $this->_params['table'] . ' WHERE lock_id = ?';
$values = array($lockid);
try {
$this->_db->delete($sql, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_Lock_Exception($e);
}
if ($this->_logger) {
$this->_logger->log(sprintf('Lock %s cleared successfully.', $lockid), 'DEBUG');
}
return true;
}
/**
* Do garbage collection needed for the driver.
*/
public function doGC()
{
$now = time();
$query = 'DELETE FROM ' . $this->_params['table'] . ' WHERE ' .
'lock_expiry_timestamp < ? AND lock_expiry_timestamp != ?';
$values = array($now, Horde_Lock::PERMANENT);
try {
$result = $this->_db->delete($query, $values);
if ($this->_logger) {
$this->_logger->log(sprintf('Lock garbage collection cleared %d locks.', $result), 'DEBUG');
}
} catch (Horde_Db_Exception $e) {}
}
}
Horde_Lock-2.1.2/lib/Horde/Lock.php 0000664 0001750 0001750 00000013065 12653740533 015056 0 ustar jan jan
* @category Horde
* @package Lock
*/
abstract class Horde_Lock
{
/* Class constants. */
const TYPE_EXCLUSIVE = 1;
const TYPE_SHARED = 2;
const PERMANENT = -1;
/**
* Driver parameters.
*
* @var array
*/
protected $_params;
/**
* Logger.
*
* @var Horde_Log_Logger
*/
protected $_logger;
/**
* Constructor.
*
* @param array $params Configuration parameters:
*
* 'logger' - (Horde_Log_Logger) A logger instance.
*
*/
public function __construct($params = array())
{
if (!empty($params['logger'])) {
$this->_logger = $params['logger'];
unset($params['logger']);
}
$this->_params = $params;
}
/**
* Return an array of information about the requested lock.
*
* @param string $lockid Lock ID to look up.
*
* @return array Lock information.
* @throws Horde_Lock_Exception
*/
abstract public function getLockInfo($lockid);
/**
* Return a list of valid locks with the option to limit the results
* by principal, scope and/or type.
*
* @param string $scope The scope of the lock. Typically the name of
* the application requesting the lock or some
* other identifier used to group locks together.
* @param string $principal Principal for which to check for locks
* @param integer $type Only return locks of the given type.
* Defaults to null, or all locks
*
* @return array Array of locks with the ID as the key and the lock details
* as the value. If there are no current locks this will
* return an empty array.
* @throws Horde_Lock_Exception
*/
abstract public function getLocks($scope = null, $principal = null,
$type = null);
/**
* Extend the valid lifetime of a valid lock to now + $extend.
*
* @param string $lockid Lock ID to reset. Must be a valid, non-expired
* lock.
* @param integer $extend Extend lock this many seconds from now.
*
* @return boolean Returns true on success.
* @throws Horde_Lock_Exception
*/
abstract public function resetLock($lockid, $extend);
/**
* Sets a lock on the requested principal and returns the generated lock
* ID. NOTE: No security checks are done in the Horde_Lock API. It is
* expected that the calling application has done all necessary security
* checks before requesting a lock be granted.
*
* @param string $requestor User ID of the lock requestor.
* @param string $scope The scope of the lock. Typically the name of
* the application requesting the lock or some
* other identifier used to group locks
* together.
* @param string $principal A principal on which a lock should be
* granted. The format can be any string but is
* suggested to be in URI form.
* @param integer $lifetime Time (in seconds) for which the lock will be
* considered valid.
* @param string exclusive One of Horde_Lock::TYPE_SHARED or
* Horde_Lock::TYPE_EXCLUSIVE.
* - An exclusive lock will be enforced strictly
* and must be interpreted to mean that the
* resource can not be modified. Only one
* exclusive lock per principal is allowed.
* - A shared lock is one that notifies other
* potential lock requestors that the resource
* is in use. This lock can be overridden
* (cleared or replaced with a subsequent
* call to setLock()) by other users. Multiple
* users may request (and will be granted) a
* shared lock on a given principal. All locks
* will be considered valid until they are
* cleared or expire.
*
* @return mixed A string lock ID.
* @throws Horde_Lock_Exception
*/
abstract public function setLock($requestor, $scope, $principal,
$lifetime = 1,
$exclusive = Horde_Lock::TYPE_SHARED);
/**
* Removes a lock given the lock ID.
* NOTE: No security checks are done in the Horde_Lock API. It is
* expected that the calling application has done all necessary security
* checks before requesting a lock be cleared.
*
* @param string $lockid The lock ID as generated by a previous call
* to setLock()
*
* @return boolean Returns true on success.
* @throws Horde_Lock_Exception
*/
abstract public function clearLock($lockid);
}
Horde_Lock-2.1.2/migration/Horde/Lock/1_horde_lock_base_tables.php 0000664 0001750 0001750 00000002053 12653740533 023151 0 ustar jan jan tables())) {
$t = $this->createTable('horde_locks', array('autoincrementKey' => array('lock_id')));
$t->column('lock_id', 'string', array('limit' => 36, 'null' => false));
$t->column('lock_owner', 'string', array('limit' => 32, 'null' => false));
$t->column('lock_scope', 'string', array('limit' => 32, 'null' => false));
$t->column('lock_principal', 'string', array('limit' => 255, 'null' => false));
$t->column('lock_origin_timestamp', 'bigint', array('null' => false));
$t->column('lock_update_timestamp', 'bigint', array('null' => false));
$t->column('lock_expiry_timestamp', 'bigint', array('null' => false));
$t->column('lock_type', 'smallint', array('null' => false, 'unsigned' => true));
$t->end();
}
}
public function down()
{
$this->dropTable('horde_locks');
}
}
Horde_Lock-2.1.2/migration/Horde/Lock/2_horde_lock_upgrade_column_types.php 0000664 0001750 0001750 00000000276 12653740533 025143 0 ustar jan jan changeColumn('horde_locks', 'lock_owner', 'string', array('limit' => 255, 'null' => false));
}
public function down()
{
$this->changeColumn('horde_locks', 'lock_owner', 'string', array('limit' => 32, 'null' => false));
}
}
Horde_Lock-2.1.2/test/Horde/Lock/Storage/MongoTest.php 0000664 0001750 0001750 00000002157 12653740533 020612 0 ustar jan jan
* @category Horde
* @ignore
* @license http://www.horde.org/licenses/lgpl21 LGPL
* @package Lock
* @subpackage UnitTests
*/
class Horde_Lock_Storage_MongoTest extends Horde_Lock_Storage_TestBase
{
private $_dbname = 'horde_lock_mongodbtest';
private $_mongo;
protected function _getBackend()
{
if (($config = self::getConfig('LOCK_MONGO_TEST_CONFIG', __DIR__ . '/..')) &&
isset($config['lock']['mongo'])) {
$factory = new Horde_Test_Factory_Mongo();
$this->_mongo = $factory->create(array(
'config' => $config['lock']['mongo'],
'dbname' => $this->_dbname
));
}
if (empty($this->_mongo)) {
$this->markTestSkipped('MongoDB not available.');
}
return new Horde_Lock_Mongo(array(
'mongo_db' => $this->_mongo,
));
}
public function tearDown()
{
if (!empty($this->_mongo)) {
$this->_mongo->selectDB(null)->drop();
}
parent::tearDown();
}
}
Horde_Lock-2.1.2/test/Horde/Lock/Storage/SqlTest.php 0000664 0001750 0001750 00000002344 12653740533 020270 0 ustar jan jan
* @category Horde
* @ignore
* @license http://www.horde.org/licenses/lgpl21 LGPL
* @package Lock
* @subpackage UnitTests
*/
class Horde_Lock_Storage_SqlTest extends Horde_Lock_Storage_TestBase
{
protected static $_migrationDir;
public static function setUpBeforeClass()
{
self::$_migrationDir = __DIR__ . '/../../../../migration/Horde/Lock';
if (!is_dir(self::$_migrationDir)) {
error_reporting(E_ALL & ~E_DEPRECATED);
self::$_migrationDir = PEAR_Config::singleton()
->get('data_dir', null, 'pear.horde.org')
. '/Horde_Lock/migration';
error_reporting(E_ALL | E_STRICT);
}
}
protected function _getBackend()
{
$factory_db = new Horde_Test_Factory_Db();
try {
$db = $factory_db->create(array(
'migrations' => array(
'migrationsPath' => self::$_migrationDir
)
));
} catch (Horde_Test_Exception $e) {
$this->markTestSkipped('Test DB not available.');
}
return new Horde_Lock_Sql(array(
'db' => $db
));
}
}
Horde_Lock-2.1.2/test/Horde/Lock/Storage/TestBase.php 0000664 0001750 0001750 00000017111 12653740533 020401 0 ustar jan jan
* @author Michael Slusarz