Skip to content

Commit

Permalink
Merge pull request #13 from arvenil/issue12_add_expire_for_memcache
Browse files Browse the repository at this point in the history
#12: Add expiration time for memcache lock storage
  • Loading branch information
arvenil committed Jun 13, 2015
2 parents c11bd2a + d4f516f commit 6bc68b4
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 140 deletions.
2 changes: 2 additions & 0 deletions .travis.php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extension=memcache.so
extension=memcached.so
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ services:
- redis-server

before_script:
- ./tests/travis/memcache-setup.sh
- ./tests/travis/memcached-setup.sh
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then cat .travis.php.ini >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini ; echo "Loading additional config for version $TRAVIS_PHP_VERSION" ; fi
- ./tests/travis/composer-setup.sh
- ./tests/travis/mysql-setup.sh

Expand Down
29 changes: 29 additions & 0 deletions src/NinjaMutex/Lock/LockExpirationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
/**
* This file is part of ninja-mutex.
*
* (C) Kamil Dziedzic <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NinjaMutex\Lock;

/**
* Lock implementor
*
* @author Kamil Dziedzic <[email protected]>
*/
interface LockExpirationInterface
{
/**
* @param int $expiration Expiration time of the lock in seconds.
*/
public function setExpiration($expiration);

/**
* @param string $name
* @return bool
*/
public function clearLock($name);
}
98 changes: 96 additions & 2 deletions src/NinjaMutex/Lock/MemcacheLock.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,107 @@
*
* @author Kamil Dziedzic <[email protected]>
*/
class MemcacheLock extends MemcacheLockAbstract
class MemcacheLock extends LockAbstract implements LockExpirationInterface
{
/**
* Maximum expiration time in seconds (30 days)
* http://php.net/manual/en/memcache.add.php
*/
const MAX_EXPIRATION = 2592000;

/**
* Memcache connection
*
* @var Memcache
*/
protected $memcache;

/**
* @var int Expiration time of the lock in seconds
*/
protected $expiration = 0;

/**
* @param Memcache $memcache
*/
public function __construct(Memcache $memcache)
{
parent::__construct($memcache);
parent::__construct();

$this->memcache = $memcache;
}

/**
* @param int $expiration Expiration time of the lock in seconds. If it's equal to zero (default), the lock will never expire.
* Max 2592000s (30 days), if greater it will be capped to 2592000 without throwing an error.
* WARNING: Using value higher than 0 may lead to race conditions. If you set too low expiration time
* e.g. 30s and critical section will run for 31s another process will gain lock at the same time,
* leading to unpredicted behaviour. Use with caution.
*/
public function setExpiration($expiration)
{
if ($expiration > static::MAX_EXPIRATION) {
$expiration = static::MAX_EXPIRATION;
}
$this->expiration = $expiration;
}

/**
* Clear lock without releasing it
* Do not use this method unless you know what you do
*
* @param string $name name of lock
* @return bool
*/
public function clearLock($name)
{
if (!isset($this->locks[$name])) {
return false;
}

unset($this->locks[$name]);
return true;
}

/**
* @param string $name name of lock
* @param bool $blocking
* @return bool
*/
protected function getLock($name, $blocking)
{
if (!$this->memcache->add($name, serialize($this->getLockInformation()), 0, $this->expiration)) {
return false;
}

return true;
}

/**
* Release lock
*
* @param string $name name of lock
* @return bool
*/
public function releaseLock($name)
{
if (isset($this->locks[$name]) && $this->memcache->delete($name)) {
unset($this->locks[$name]);

return true;
}

return false;
}

/**
* Check if lock is locked
*
* @param string $name name of lock
* @return bool
*/
public function isLocked($name)
{
return false !== $this->memcache->get($name);
}
}
77 changes: 0 additions & 77 deletions src/NinjaMutex/Lock/MemcacheLockAbstract.php

This file was deleted.

101 changes: 98 additions & 3 deletions src/NinjaMutex/Lock/MemcachedLock.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,108 @@
*
* @author Kamil Dziedzic <[email protected]>
*/
class MemcachedLock extends MemcacheLockAbstract
class MemcachedLock extends LockAbstract implements LockExpirationInterface
{
/**
* Maximum expiration time in seconds (30 days)
* http://php.net/manual/en/memcached.add.php
*/
const MAX_EXPIRATION = 2592000;

/**
* Memcache connection
*
* @var Memcached
*/
protected $memcached;

/**
* @var int Expiration time of the lock in seconds
*/
protected $expiration = 0;

/**
* @param Memcached $memcached
*/
public function __construct(Memcached $memcached)
public function __construct($memcached)
{
parent::__construct();

$this->memcached = $memcached;
}

/**
* @param int $expiration Expiration time of the lock in seconds. If it's equal to zero (default), the lock will never expire.
* Max 2592000s (30 days), if greater it will be capped to 2592000 without throwing an error.
* WARNING: Using value higher than 0 may lead to race conditions. If you set too low expiration time
* e.g. 30s and critical section will run for 31s another process will gain lock at the same time,
* leading to unpredicted behaviour. Use with caution.
*/
public function setExpiration($expiration)
{
if ($expiration > static::MAX_EXPIRATION) {
$expiration = static::MAX_EXPIRATION;
}
$this->expiration = $expiration;
}

/**
* Clear lock without releasing it
* Do not use this method unless you know what you do
*
* @param string $name name of lock
* @return bool
*/
public function clearLock($name)
{
parent::__construct($memcached);
if (!isset($this->locks[$name])) {
return false;
}

unset($this->locks[$name]);
return true;
}

/**
* @param string $name name of lock
* @param bool $blocking
* @return bool
*/
protected function getLock($name, $blocking)
{
if (!$this->memcached->add($name, serialize($this->getLockInformation()), $this->expiration)) {
return false;
}

return true;
}

/**
* Release lock
*
* @param string $name name of lock
* @return bool
*/
public function releaseLock($name)
{
if (isset($this->locks[$name]) && $this->memcached->delete($name)) {
unset($this->locks[$name]);

return true;
}

return false;
}

/**
* Check if lock is locked
*
* @param string $name name of lock
* @return bool
*/
public function isLocked($name)
{
return false !== $this->memcached->get($name);
}
}

Loading

0 comments on commit 6bc68b4

Please sign in to comment.