Refactoring Core class structures ...
This commit is contained in:
parent
57b4c008cb
commit
b216317477
130 changed files with 1625 additions and 1397 deletions
|
@ -19,23 +19,22 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Core\Lock;
|
||||
namespace Friendica\Core\Lock\Capability;
|
||||
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Lock\Exception\LockPersistenceException;
|
||||
|
||||
/**
|
||||
* Lock Interface
|
||||
*/
|
||||
interface ILock
|
||||
interface ICanLock
|
||||
{
|
||||
/**
|
||||
* Checks, if a key is currently locked to a or my process
|
||||
*
|
||||
* @param string $key The name of the lock
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocked($key);
|
||||
public function isLocked(string $key): bool;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -45,9 +44,9 @@ interface ILock
|
|||
* @param integer $timeout Seconds until we give up
|
||||
* @param integer $ttl Seconds The lock lifespan, must be one of the Cache constants
|
||||
*
|
||||
* @return boolean Was the lock successful?
|
||||
* @throws LockPersistenceException In case the underlying persistence throws errors
|
||||
*/
|
||||
public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES);
|
||||
public function acquire(string $key, int $timeout = 120, int $ttl = Duration::FIVE_MINUTES): bool;
|
||||
|
||||
/**
|
||||
* Releases a lock if it was set by us
|
||||
|
@ -55,32 +54,36 @@ interface ILock
|
|||
* @param string $key The Name of the lock
|
||||
* @param bool $override Overrides the lock to get released
|
||||
*
|
||||
* @return boolean Was the unlock successful?
|
||||
* @return bool Was the unlock successful?
|
||||
*
|
||||
* @throws LockPersistenceException In case the underlying persistence throws errors
|
||||
*/
|
||||
public function release($key, $override = false);
|
||||
public function release(string $key, bool $override = false): bool;
|
||||
|
||||
/**
|
||||
* Releases all lock that were set by us
|
||||
*
|
||||
* @param bool $override Override to release all locks
|
||||
*
|
||||
* @return boolean Was the unlock of all locks successful?
|
||||
* @return bool Was the unlock of all locks successful?
|
||||
*
|
||||
* @throws LockPersistenceException In case the underlying persistence throws errors
|
||||
*/
|
||||
public function releaseAll($override = false);
|
||||
public function releaseAll(bool $override = false): bool;
|
||||
|
||||
/**
|
||||
* Returns the name of the current lock
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Lists all locks
|
||||
*
|
||||
* @param string prefix optional a prefix to search
|
||||
*
|
||||
* @return array Empty if it isn't supported by the cache driver
|
||||
* @return string[] Empty if it isn't supported by the cache driver
|
||||
*
|
||||
* @throws LockPersistenceException In case the underlying persistence throws errors
|
||||
*/
|
||||
public function getLocks(string $prefix = '');
|
||||
public function getLocks(string $prefix = ''): array;
|
||||
}
|
13
src/Core/Lock/Exception/InvalidLockDriverException.php
Normal file
13
src/Core/Lock/Exception/InvalidLockDriverException.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Lock\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InvalidLockDriverException extends \RuntimeException
|
||||
{
|
||||
public function __construct($message = "", Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, 500, $previous);
|
||||
}
|
||||
}
|
13
src/Core/Lock/Exception/LockPersistenceException.php
Normal file
13
src/Core/Lock/Exception/LockPersistenceException.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Lock\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class LockPersistenceException extends \RuntimeException
|
||||
{
|
||||
public function __construct($message = "", Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, 500, $previous);
|
||||
}
|
||||
}
|
|
@ -21,11 +21,12 @@
|
|||
|
||||
namespace Friendica\Core\Lock\Factory;
|
||||
|
||||
use Friendica\Core\Cache\Factory\CacheFactory;
|
||||
use Friendica\Core\Cache\IMemoryCache;
|
||||
use Friendica\Core\Cache\Enum\Type;
|
||||
use Friendica\Core\Config\IConfig;
|
||||
use Friendica\Core\Lock;
|
||||
use Friendica\Core\Cache\Factory\Cache;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Enum;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type;
|
||||
use Friendica\Database\Database;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
@ -36,7 +37,7 @@ use Psr\Log\LoggerInterface;
|
|||
*
|
||||
* A basic class to generate a LockDriver
|
||||
*/
|
||||
class LockFactory
|
||||
class Lock
|
||||
{
|
||||
/**
|
||||
* @var string The default driver for caching
|
||||
|
@ -44,7 +45,7 @@ class LockFactory
|
|||
const DEFAULT_DRIVER = 'default';
|
||||
|
||||
/**
|
||||
* @var IConfig The configuration to read parameters out of the config
|
||||
* @var IManageConfigValues The configuration to read parameters out of the config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
|
@ -54,7 +55,7 @@ class LockFactory
|
|||
private $dba;
|
||||
|
||||
/**
|
||||
* @var CacheFactory The memory cache driver in case we use it
|
||||
* @var Cache The memory cache driver in case we use it
|
||||
*/
|
||||
private $cacheFactory;
|
||||
|
||||
|
@ -63,7 +64,7 @@ class LockFactory
|
|||
*/
|
||||
private $logger;
|
||||
|
||||
public function __construct(CacheFactory $cacheFactory, IConfig $config, Database $dba, LoggerInterface $logger)
|
||||
public function __construct(Cache $cacheFactory, IManageConfigValues $config, Database $dba, LoggerInterface $logger)
|
||||
{
|
||||
$this->cacheFactory = $cacheFactory;
|
||||
$this->config = $config;
|
||||
|
@ -77,24 +78,24 @@ class LockFactory
|
|||
|
||||
try {
|
||||
switch ($lock_type) {
|
||||
case Type::MEMCACHE:
|
||||
case Type::MEMCACHED:
|
||||
case Type::REDIS:
|
||||
case Type::APCU:
|
||||
case Enum\Type::MEMCACHE:
|
||||
case Enum\Type::MEMCACHED:
|
||||
case Enum\Type::REDIS:
|
||||
case Enum\Type::APCU:
|
||||
$cache = $this->cacheFactory->create($lock_type);
|
||||
if ($cache instanceof IMemoryCache) {
|
||||
return new Lock\Type\CacheLock($cache);
|
||||
if ($cache instanceof ICanCacheInMemory) {
|
||||
return new Type\CacheLock($cache);
|
||||
} else {
|
||||
throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'database':
|
||||
return new Lock\Type\DatabaseLock($this->dba);
|
||||
return new Type\DatabaseLock($this->dba);
|
||||
break;
|
||||
|
||||
case 'semaphore':
|
||||
return new Lock\Type\SemaphoreLock();
|
||||
return new Type\SemaphoreLock();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -114,14 +115,14 @@ class LockFactory
|
|||
* 2. Cache Locking
|
||||
* 3. Database Locking
|
||||
*
|
||||
* @return Lock\ILock
|
||||
* @return ICanLock
|
||||
*/
|
||||
private function useAutoDriver()
|
||||
{
|
||||
// 1. Try to use Semaphores for - local - locking
|
||||
if (function_exists('sem_get')) {
|
||||
try {
|
||||
return new Lock\Type\SemaphoreLock();
|
||||
return new Type\SemaphoreLock();
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->warning('Using Semaphore driver for locking failed.', ['exception' => $exception]);
|
||||
}
|
||||
|
@ -129,11 +130,11 @@ class LockFactory
|
|||
|
||||
// 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
|
||||
$cache_type = $this->config->get('system', 'cache_driver', 'database');
|
||||
if ($cache_type != Type::DATABASE) {
|
||||
if ($cache_type != Enum\Type::DATABASE) {
|
||||
try {
|
||||
$cache = $this->cacheFactory->create($cache_type);
|
||||
if ($cache instanceof IMemoryCache) {
|
||||
return new Lock\Type\CacheLock($cache);
|
||||
if ($cache instanceof ICanCacheInMemory) {
|
||||
return new Type\CacheLock($cache);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->warning('Using Cache driver for locking failed.', ['exception' => $exception]);
|
||||
|
@ -141,6 +142,6 @@ class LockFactory
|
|||
}
|
||||
|
||||
// 3. Use Database Locking as a Fallback
|
||||
return new Lock\Type\DatabaseLock($this->dba);
|
||||
return new Type\DatabaseLock($this->dba);
|
||||
}
|
||||
}
|
|
@ -21,12 +21,12 @@
|
|||
|
||||
namespace Friendica\Core\Lock\Type;
|
||||
|
||||
use Friendica\Core\Lock\ILock;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
|
||||
/**
|
||||
* Basic class for Locking with common functions (local acquired locks, releaseAll, ..)
|
||||
*/
|
||||
abstract class BaseLock implements ILock
|
||||
abstract class AbstractLock implements ICanLock
|
||||
{
|
||||
/**
|
||||
* @var array The local acquired locks
|
||||
|
@ -40,7 +40,7 @@ abstract class BaseLock implements ILock
|
|||
*
|
||||
* @return bool Returns true if the lock is set
|
||||
*/
|
||||
protected function hasAcquiredLock($key)
|
||||
protected function hasAcquiredLock(string $key): bool
|
||||
{
|
||||
return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ abstract class BaseLock implements ILock
|
|||
*
|
||||
* @param string $key The Name of the lock
|
||||
*/
|
||||
protected function markAcquire($key)
|
||||
protected function markAcquire(string $key)
|
||||
{
|
||||
$this->acquiredLocks[$key] = true;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ abstract class BaseLock implements ILock
|
|||
*
|
||||
* @param string $key The Name of the lock
|
||||
*/
|
||||
protected function markRelease($key)
|
||||
protected function markRelease(string $key)
|
||||
{
|
||||
unset($this->acquiredLocks[$key]);
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ abstract class BaseLock implements ILock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function releaseAll($override = false)
|
||||
public function releaseAll(bool $override = false): bool
|
||||
{
|
||||
$return = true;
|
||||
|
|
@ -21,10 +21,13 @@
|
|||
|
||||
namespace Friendica\Core\Lock\Type;
|
||||
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Cache\IMemoryCache;
|
||||
use Friendica\Core\Cache\Exception\CachePersistenceException;
|
||||
use Friendica\Core\Lock\Exception\LockPersistenceException;
|
||||
|
||||
class CacheLock extends BaseLock
|
||||
class CacheLock extends AbstractLock
|
||||
{
|
||||
/**
|
||||
* @var string The static prefix of all locks inside the cache
|
||||
|
@ -32,16 +35,16 @@ class CacheLock extends BaseLock
|
|||
const CACHE_PREFIX = 'lock:';
|
||||
|
||||
/**
|
||||
* @var \Friendica\Core\Cache\ICache;
|
||||
* @var ICanCache;
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* CacheLock constructor.
|
||||
*
|
||||
* @param IMemoryCache $cache The CacheDriver for this type of lock
|
||||
* @param ICanCacheInMemory $cache The CacheDriver for this type of lock
|
||||
*/
|
||||
public function __construct(IMemoryCache $cache)
|
||||
public function __construct(ICanCacheInMemory $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
@ -49,35 +52,39 @@ class CacheLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES)
|
||||
public function acquire(string $key, int $timeout = 120, int $ttl = Duration::FIVE_MINUTES): bool
|
||||
{
|
||||
$got_lock = false;
|
||||
$start = time();
|
||||
|
||||
$cachekey = self::getLockKey($key);
|
||||
$lockKey = self::getLockKey($key);
|
||||
|
||||
do {
|
||||
$lock = $this->cache->get($cachekey);
|
||||
// When we do want to lock something that was already locked by us.
|
||||
if ((int)$lock == getmypid()) {
|
||||
$got_lock = true;
|
||||
}
|
||||
|
||||
// When we do want to lock something new
|
||||
if (is_null($lock)) {
|
||||
// At first initialize it with "0"
|
||||
$this->cache->add($cachekey, 0);
|
||||
// Now the value has to be "0" because otherwise the key was used by another process meanwhile
|
||||
if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
|
||||
try {
|
||||
do {
|
||||
$lock = $this->cache->get($lockKey);
|
||||
// When we do want to lock something that was already locked by us.
|
||||
if ((int)$lock == getmypid()) {
|
||||
$got_lock = true;
|
||||
$this->markAcquire($key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$got_lock && ($timeout > 0)) {
|
||||
usleep(rand(10000, 200000));
|
||||
}
|
||||
} while (!$got_lock && ((time() - $start) < $timeout));
|
||||
// When we do want to lock something new
|
||||
if (is_null($lock)) {
|
||||
// At first initialize it with "0"
|
||||
$this->cache->add($lockKey, 0);
|
||||
// Now the value has to be "0" because otherwise the key was used by another process meanwhile
|
||||
if ($this->cache->compareSet($lockKey, 0, getmypid(), $ttl)) {
|
||||
$got_lock = true;
|
||||
$this->markAcquire($key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$got_lock && ($timeout > 0)) {
|
||||
usleep(rand(10000, 200000));
|
||||
}
|
||||
} while (!$got_lock && ((time() - $start) < $timeout));
|
||||
} catch (CachePersistenceException $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot acquire lock for key %s', $key), $exception);
|
||||
}
|
||||
|
||||
return $got_lock;
|
||||
}
|
||||
|
@ -85,14 +92,18 @@ class CacheLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function release($key, $override = false)
|
||||
public function release(string $key, bool $override = false): bool
|
||||
{
|
||||
$cachekey = self::getLockKey($key);
|
||||
$lockKey = self::getLockKey($key);
|
||||
|
||||
if ($override) {
|
||||
$return = $this->cache->delete($cachekey);
|
||||
} else {
|
||||
$return = $this->cache->compareDelete($cachekey, getmypid());
|
||||
try {
|
||||
if ($override) {
|
||||
$return = $this->cache->delete($lockKey);
|
||||
} else {
|
||||
$return = $this->cache->compareDelete($lockKey, getmypid());
|
||||
}
|
||||
} catch (CachePersistenceException $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot release lock for key %s (override %b)', $key, $override), $exception);
|
||||
}
|
||||
$this->markRelease($key);
|
||||
|
||||
|
@ -102,17 +113,21 @@ class CacheLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function isLocked($key)
|
||||
public function isLocked(string $key): bool
|
||||
{
|
||||
$cachekey = self::getLockKey($key);
|
||||
$lock = $this->cache->get($cachekey);
|
||||
$lockKey = self::getLockKey($key);
|
||||
try {
|
||||
$lock = $this->cache->get($lockKey);
|
||||
} catch (CachePersistenceException $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot check lock state for key %s', $key), $exception);
|
||||
}
|
||||
return isset($lock) && ($lock !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->cache->getName();
|
||||
}
|
||||
|
@ -120,11 +135,15 @@ class CacheLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getLocks(string $prefix = '')
|
||||
public function getLocks(string $prefix = ''): array
|
||||
{
|
||||
$locks = $this->cache->getAllKeys(self::CACHE_PREFIX . $prefix);
|
||||
try {
|
||||
$locks = $this->cache->getAllKeys(self::CACHE_PREFIX . $prefix);
|
||||
} catch (CachePersistenceException $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot get locks with prefix %s', $prefix), $exception);
|
||||
}
|
||||
|
||||
array_walk($locks, function (&$lock, $key) {
|
||||
array_walk($locks, function (&$lock) {
|
||||
$lock = substr($lock, strlen(self::CACHE_PREFIX));
|
||||
});
|
||||
|
||||
|
@ -134,7 +153,7 @@ class CacheLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function releaseAll($override = false)
|
||||
public function releaseAll(bool $override = false): bool
|
||||
{
|
||||
$success = parent::releaseAll($override);
|
||||
|
||||
|
@ -154,7 +173,7 @@ class CacheLock extends BaseLock
|
|||
*
|
||||
* @return string The cache key used for the cache
|
||||
*/
|
||||
private static function getLockKey($key)
|
||||
private static function getLockKey(string $key): string
|
||||
{
|
||||
return self::CACHE_PREFIX . $key;
|
||||
}
|
||||
|
|
|
@ -23,13 +23,14 @@ namespace Friendica\Core\Lock\Type;
|
|||
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Lock\Enum\Type;
|
||||
use Friendica\Core\Lock\Exception\LockPersistenceException;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
* Locking driver that stores the locks in the database
|
||||
*/
|
||||
class DatabaseLock extends BaseLock
|
||||
class DatabaseLock extends AbstractLock
|
||||
{
|
||||
/**
|
||||
* The current ID of the process
|
||||
|
@ -44,49 +45,63 @@ class DatabaseLock extends BaseLock
|
|||
private $dba;
|
||||
|
||||
/**
|
||||
* @param null|int $pid The Id of the current process (null means determine automatically)
|
||||
* @param int|null $pid The id of the current process (null means determine automatically)
|
||||
*/
|
||||
public function __construct(Database $dba, $pid = null)
|
||||
public function __construct(Database $dba, ?int $pid = null)
|
||||
{
|
||||
$this->dba = $dba;
|
||||
$this->pid = isset($pid) ? $pid : getmypid();
|
||||
$this->pid = $pid ?? getmypid();
|
||||
}
|
||||
|
||||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES)
|
||||
public function acquire(string $key, int $timeout = 120, int $ttl = Duration::FIVE_MINUTES): bool
|
||||
{
|
||||
$got_lock = false;
|
||||
$start = time();
|
||||
|
||||
do {
|
||||
$this->dba->lock('locks');
|
||||
$lock = $this->dba->selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
|
||||
try {
|
||||
do {
|
||||
$this->dba->lock('locks');
|
||||
$lock = $this->dba->selectFirst('locks', ['locked', 'pid'], [
|
||||
'`name` = ? AND `expires` >= ?', $key,DateTimeFormat::utcNow()
|
||||
]);
|
||||
|
||||
if ($this->dba->isResult($lock)) {
|
||||
if ($lock['locked']) {
|
||||
// We want to lock something that was already locked by us? So we got the lock.
|
||||
if ($lock['pid'] == $this->pid) {
|
||||
if ($this->dba->isResult($lock)) {
|
||||
if ($lock['locked']) {
|
||||
// We want to lock something that was already locked by us? So we got the lock.
|
||||
if ($lock['pid'] == $this->pid) {
|
||||
$got_lock = true;
|
||||
}
|
||||
}
|
||||
if (!$lock['locked']) {
|
||||
$this->dba->update('locks', [
|
||||
'locked' => true,
|
||||
'pid' => $this->pid,
|
||||
'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')
|
||||
], ['name' => $key]);
|
||||
$got_lock = true;
|
||||
}
|
||||
}
|
||||
if (!$lock['locked']) {
|
||||
$this->dba->update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]);
|
||||
} else {
|
||||
$this->dba->insert('locks', [
|
||||
'name' => $key,
|
||||
'locked' => true,
|
||||
'pid' => $this->pid,
|
||||
'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
|
||||
$got_lock = true;
|
||||
$this->markAcquire($key);
|
||||
}
|
||||
} else {
|
||||
$this->dba->insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
|
||||
$got_lock = true;
|
||||
$this->markAcquire($key);
|
||||
}
|
||||
|
||||
$this->dba->unlock();
|
||||
$this->dba->unlock();
|
||||
|
||||
if (!$got_lock && ($timeout > 0)) {
|
||||
usleep(rand(100000, 2000000));
|
||||
}
|
||||
} while (!$got_lock && ((time() - $start) < $timeout));
|
||||
if (!$got_lock && ($timeout > 0)) {
|
||||
usleep(rand(100000, 2000000));
|
||||
}
|
||||
} while (!$got_lock && ((time() - $start) < $timeout));
|
||||
} catch (\Exception $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot acquire lock for key %s', $key), $exception);
|
||||
}
|
||||
|
||||
return $got_lock;
|
||||
}
|
||||
|
@ -94,7 +109,7 @@ class DatabaseLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function release($key, $override = false)
|
||||
public function release(string $key, bool $override = false): bool
|
||||
{
|
||||
if ($override) {
|
||||
$where = ['name' => $key];
|
||||
|
@ -102,10 +117,14 @@ class DatabaseLock extends BaseLock
|
|||
$where = ['name' => $key, 'pid' => $this->pid];
|
||||
}
|
||||
|
||||
if ($this->dba->exists('locks', $where)) {
|
||||
$return = $this->dba->delete('locks', $where);
|
||||
} else {
|
||||
$return = false;
|
||||
try {
|
||||
if ($this->dba->exists('locks', $where)) {
|
||||
$return = $this->dba->delete('locks', $where);
|
||||
} else {
|
||||
$return = false;
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot release lock for key %s (override %b)', $key, $override), $exception);
|
||||
}
|
||||
|
||||
$this->markRelease($key);
|
||||
|
@ -116,7 +135,7 @@ class DatabaseLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function releaseAll($override = false)
|
||||
public function releaseAll(bool $override = false): bool
|
||||
{
|
||||
$success = parent::releaseAll($override);
|
||||
|
||||
|
@ -125,7 +144,12 @@ class DatabaseLock extends BaseLock
|
|||
} else {
|
||||
$where = ['pid' => $this->pid];
|
||||
}
|
||||
$return = $this->dba->delete('locks', $where);
|
||||
|
||||
try {
|
||||
$return = $this->dba->delete('locks', $where);
|
||||
} catch (\Exception $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot release all lock (override %b)', $override), $exception);
|
||||
}
|
||||
|
||||
$this->acquiredLocks = [];
|
||||
|
||||
|
@ -135,9 +159,14 @@ class DatabaseLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function isLocked($key)
|
||||
public function isLocked(string $key): bool
|
||||
{
|
||||
$lock = $this->dba->selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
|
||||
try {
|
||||
$lock = $this->dba->selectFirst('locks', ['locked'], [
|
||||
'`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
|
||||
} catch (\Exception $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot check lock state for key %s', $key), $exception);
|
||||
}
|
||||
|
||||
if ($this->dba->isResult($lock)) {
|
||||
return $lock['locked'] !== false;
|
||||
|
@ -149,7 +178,7 @@ class DatabaseLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return Type::DATABASE;
|
||||
}
|
||||
|
@ -157,21 +186,26 @@ class DatabaseLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getLocks(string $prefix = '')
|
||||
public function getLocks(string $prefix = ''): array
|
||||
{
|
||||
if (empty($prefix)) {
|
||||
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
||||
} else {
|
||||
$where = ['`expires` >= ? AND `name` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
|
||||
}
|
||||
try {
|
||||
if (empty($prefix)) {
|
||||
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
||||
} else {
|
||||
$where = ['`expires` >= ? AND `name` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
|
||||
}
|
||||
|
||||
$stmt = $this->dba->select('locks', ['name'], $where);
|
||||
$stmt = $this->dba->select('locks', ['name'], $where);
|
||||
|
||||
$keys = [];
|
||||
while ($key = $this->dba->fetch($stmt)) {
|
||||
array_push($keys, $key['name']);
|
||||
$keys = [];
|
||||
while ($key = $this->dba->fetch($stmt)) {
|
||||
array_push($keys, $key['name']);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
throw new LockPersistenceException(sprintf('Cannot get lock with prefix %s', $prefix), $exception);
|
||||
} finally {
|
||||
$this->dba->close($stmt);
|
||||
}
|
||||
$this->dba->close($stmt);
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
|
|
@ -23,16 +23,17 @@ namespace Friendica\Core\Lock\Type;
|
|||
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Lock\Enum\Type;
|
||||
use Friendica\Core\Lock\Exception\InvalidLockDriverException;
|
||||
use function get_temppath;
|
||||
|
||||
class SemaphoreLock extends BaseLock
|
||||
class SemaphoreLock extends AbstractLock
|
||||
{
|
||||
private static $semaphore = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (!function_exists('sem_get')) {
|
||||
throw new \Exception('Semaphore lock not supported');
|
||||
throw new InvalidLockDriverException('Semaphore lock not supported');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,11 +58,11 @@ class SemaphoreLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES)
|
||||
public function acquire(string $key, int $timeout = 120, int $ttl = Duration::FIVE_MINUTES): bool
|
||||
{
|
||||
self::$semaphore[$key] = sem_get(self::semaphoreKey($key));
|
||||
if (!empty(self::$semaphore[$key])) {
|
||||
if ((bool)sem_acquire(self::$semaphore[$key], ($timeout === 0))) {
|
||||
if (sem_acquire(self::$semaphore[$key], ($timeout === 0))) {
|
||||
$this->markAcquire($key);
|
||||
return true;
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ class SemaphoreLock extends BaseLock
|
|||
* @param bool $override not necessary parameter for semaphore locks since the lock lives as long as the execution
|
||||
* of the using function
|
||||
*/
|
||||
public function release($key, $override = false)
|
||||
public function release(string $key, bool $override = false): bool
|
||||
{
|
||||
$success = false;
|
||||
|
||||
|
@ -96,7 +97,7 @@ class SemaphoreLock extends BaseLock
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function isLocked($key)
|
||||
public function isLocked(string $key): bool
|
||||
{
|
||||
return isset(self::$semaphore[$key]);
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ class SemaphoreLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return Type::SEMAPHORE;
|
||||
}
|
||||
|
@ -112,7 +113,7 @@ class SemaphoreLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getLocks(string $prefix = '')
|
||||
public function getLocks(string $prefix = ''): array
|
||||
{
|
||||
// We can just return our own semaphore keys, since we don't know
|
||||
// the state of other semaphores, even if the .sem files exists
|
||||
|
@ -136,7 +137,7 @@ class SemaphoreLock extends BaseLock
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function releaseAll($override = false)
|
||||
public function releaseAll(bool $override = false): bool
|
||||
{
|
||||
// Semaphores are just alive during a run, so there is no need to release
|
||||
// You can just release your own locks
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue