Skip to content

Commit cce6154

Browse files
committed
first commit
0 parents  commit cce6154

17 files changed

+1246
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.idea/
2+
/vendor/
3+
composer.lock

.travis.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
language: php
2+
php:
3+
- '5.5'
4+
- '5.6'
5+
- '7.0'
6+
- '7.1'
7+
- hhvm
8+
9+
matrix:
10+
allow_failures:
11+
- php: hhvm
12+
13+
before_install:
14+
- PHP_INI=~/.phpenv/versions/$(phpenv version-name)/etc/php.ini;
15+
- |
16+
if [[ $TRAVIS_PHP_VERSION =~ 5.[56] ]]; then
17+
echo "extension = memcached.so" >> $PHP_INI;
18+
phpenv config-rm xdebug.ini;
19+
fi;
20+
- |
21+
if [[ $TRAVIS_PHP_VERSION =~ 7.[10] ]]; then
22+
apt-get install -y php-memcached;
23+
echo "extension = memcached.so" >> $PHP_INI;
24+
fi;
25+
- |
26+
if [[ $TRAVIS_PHP_VERSION =~ 7.[0] ]]; then
27+
phpenv config-rm xdebug.ini;
28+
fi;
29+
30+
install:
31+
- composer install
32+
33+
services:
34+
- memcached
35+
- redis

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2015 Alexander Cheprasov <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
2+
[![Latest Stable Version](https://poser.pugx.org/cheprasov/php-redis-lock/v/stable)](https://packagist.org/packages/cheprasov/php-redis-lock)
3+
[![Total Downloads](https://poser.pugx.org/cheprasov/php-redis-lock/downloads)](https://packagist.org/packages/cheprasov/php-redis-lock)
4+
5+
# RedisLock v1.0.0 for PHP >= 5.5
6+
7+
## About
8+
RedisLock for PHP is a synchronization mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution. A lock is designed to enforce a mutual exclusion concurrency control policy. Based on [redis](http://redis.io/).
9+
10+
11+
## Usage
12+
13+
### Create a new instance of RedisLock
14+
15+
```php
16+
<?php
17+
require 'vendor/autoload.php';
18+
19+
use RedisLock\RedisLock;
20+
use RedisClient\ClientFactory;
21+
use RedisClient\RedisClient;
22+
23+
// Create a new Redis instance
24+
$Redis = ClientFactory::create([
25+
'server' => 'tcp://127.0.0.1:6379'
26+
]);
27+
28+
$Lock = new RedisLock(
29+
$Redis, // Instance of RedisClient,
30+
'key', // Key in storage,
31+
);
32+
```
33+
34+
### Usage for lock a process
35+
36+
```php
37+
<?php
38+
require 'vendor/autoload.php';
39+
40+
use RedisLock\RedisLock;
41+
use RedisClient\ClientFactory;
42+
use RedisClient\RedisClient;
43+
44+
// Create a new Redis instance
45+
$Redis = ClientFactory::create([
46+
'server' => 'tcp://127.0.0.1:6379'
47+
]);
48+
49+
// ...
50+
51+
/**
52+
* Safe update json in Redis storage
53+
* @param Redis $Redis
54+
* @param string $key
55+
* @param array $array
56+
* @throws Exception
57+
*/
58+
function updateJsonInRedis(RedisClient $Redis, $key, array $array) {
59+
// Create new Lock instance
60+
$Lock = new RedisLock($Redis, 'Lock_'.$key, RedisLock::FLAG_CATCH_EXCEPTIONS);
61+
62+
// Acquire lock for 2 sec.
63+
// If lock has acquired in another thread then we will wait 3 second,
64+
// until another thread release the lock. Otherwise it throws a exception.
65+
if (!$Lock->acquire(2, 3)) {
66+
throw new Exception('Can\'t get a Lock');
67+
}
68+
69+
// Get value from storage
70+
$json = $Redis->get($key);
71+
if (!$json) {
72+
$jsonArray = [];
73+
} else {
74+
$jsonArray = json_decode($json, true);
75+
}
76+
77+
// Some operations with json
78+
$jsonArray = array_merge($jsonArray, $array);
79+
80+
$json = json_encode($jsonArray);
81+
// Update key in storage
82+
$Redis->set($key, $json);
83+
84+
// Release the lock
85+
// After $lock->release() another waiting thread (Lock) will be able to update json in storage
86+
$Lock->release();
87+
}
88+
89+
updateJsonInRedis($Redis, 'json-key', ['for' => 1, 'bar' => 2]);
90+
updateJsonInRedis($Redis, 'json-key', ['for' => 42, 'var' => 2016]);
91+
92+
```
93+
94+
## Methods
95+
96+
#### RedisLock :: __construct ( `\Redis` **$Redis** , `string` **$key** [, `int` **$flags** = 0 ] )
97+
---
98+
Create a new instance of RedisLock.
99+
100+
##### Method Pameters
101+
102+
1. \Redis **$Redis** - Instanse of [Redis](http://redis.io/)
103+
2. string **$key** - name of key in Redis storage. Only locks with the same name will compete with each other for lock.
104+
3. int **$flags**, default = 0
105+
* `RedisLock::FLAG_CATCH_EXCEPTIONS` - use this flag, if you don't want catch exceptions by yourself. Do not use this flag, if you want have a full control on situation with locks. Default behavior without this flag - all Exceptions will be thrown.
106+
107+
##### Example
108+
109+
```php
110+
$Lock = new RedisLock($Redis, 'lockName');
111+
// or
112+
$Lock = new RedisLock($Redis, 'lockName', RedisLock::FLAG_CATCH_EXCEPTIONS);
113+
114+
```
115+
116+
#### `bool` RedisLock :: acquire ( `int|float` **$lockTime** , [ `float` **$waitTime** = 0 [, `float` **$sleep** = 0.005 ] ] )
117+
---
118+
Try to acquire lock for `$lockTime` seconds.
119+
If lock has acquired in another thread then we will wait `$waitTime` seconds, until another thread release the lock.
120+
Otherwise method throws a exception (if `FLAG_CATCH_EXCEPTIONS` is not set) or result.
121+
Returns `true` on success or `false` on failure.
122+
123+
##### Method Pameters
124+
125+
1. int|float **$lockTime** - The time for lock in seconds, the value must be `>= 0.01`.
126+
2. float **$waitTime**, default = 0 - The time for waiting lock in seconds. Use `0` if you don't wait until lock release.
127+
3. float **$sleep**, default = 0.005 - The wait time between iterations to check the availability of the lock.
128+
129+
##### Example
130+
131+
```php
132+
$Lock = new RedisLock($Redis, 'lockName');
133+
$Lock->acquire(3, 4);
134+
// ... do something
135+
$Lock->release();
136+
```
137+
138+
#### `bool` RedisLock :: update ( `int|float` **$lockTime** )
139+
---
140+
Set a new time for lock if it is acquired already. Returns `true` on success or `false` on failure. Method can throw Exceptions.
141+
142+
##### Method Pameters
143+
1. int|float **$lockTime** - Please, see description for method `RedisLock :: acquire`
144+
145+
##### Example
146+
147+
```php
148+
$Lock = new RedisLock($Redis, 'lockName');
149+
$Lock->acquire(3, 4);
150+
// ... do something
151+
$Lock->update(3);
152+
// ... do something
153+
$Lock->release();
154+
```
155+
156+
#### `bool` RedisLock :: isAcquired ( )
157+
---
158+
Check this lock for acquired. Returns `true` on success or `false` on failure.
159+
160+
#### `bool` RedisLock :: isLocked ( )
161+
---
162+
Check this lock for acquired and not expired, and active yet. Returns `true` on success or `false` on failure. Method can throw Exceptions.
163+
164+
#### `bool` RedisLock :: isExists ()
165+
---
166+
Does lock exists or acquired anywhere? Returns `true` if lock is exists or `false` if is not.
167+
168+
## Installation
169+
170+
### Composer
171+
172+
Download composer:
173+
174+
wget -nc http://getcomposer.org/composer.phar
175+
176+
and add dependency to your project:
177+
178+
php composer.phar require cheprasov/php-redis-lock
179+
180+
## Running tests
181+
182+
To run tests type in console:
183+
184+
./vendor/bin/phpunit
185+
186+
## Something doesn't work
187+
188+
Feel free to fork project, fix bugs and finally request for pull

composer.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "cheprasov/php-redis-lock",
3+
"version": "1.0.0",
4+
"description": "RedisLock for PHP is a synchronization mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution. A lock is designed to enforce a mutual exclusion concurrency control policy.",
5+
"homepage": "http://github.com/cheprasov/php-redis-lock",
6+
"minimum-stability": "stable",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Alexander Cheprasov",
11+
"email": "[email protected]"
12+
}
13+
],
14+
"autoload": {
15+
"psr-0": {"": "src/"}
16+
},
17+
"require": {
18+
"php": ">=5.5",
19+
"cheprasov/php-redis-client" : "1.*"
20+
},
21+
"require-dev": {
22+
"phpunit/phpunit": "4.8.*",
23+
"cheprasov/php-parallel": "1.0.0"
24+
}
25+
}

example.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
require 'vendor/autoload.php';
3+
4+
use RedisLock\RedisLock;
5+
use RedisClient\ClientFactory;
6+
use RedisClient\RedisClient;
7+
8+
// Create a new Redis instance
9+
$Redis = ClientFactory::create([
10+
'server' => 'tcp://127.0.0.1:6379'
11+
]);
12+
13+
// ...
14+
15+
/**
16+
* Safe update json in Redis storage
17+
* @param Redis $Redis
18+
* @param string $key
19+
* @param array $array
20+
* @throws Exception
21+
*/
22+
function updateJsonInRedis(RedisClient $Redis, $key, array $array) {
23+
// Create new Lock instance
24+
$Lock = new RedisLock($Redis, 'Lock_'.$key, RedisLock::FLAG_CATCH_EXCEPTIONS);
25+
26+
// Acquire lock for 2 sec.
27+
// If lock has acquired in another thread then we will wait 3 second,
28+
// until another thread release the lock. Otherwise it throws a exception.
29+
if (!$Lock->acquire(2, 3)) {
30+
throw new Exception('Can\'t get a Lock');
31+
}
32+
33+
// Get value from storage
34+
$json = $Redis->get($key);
35+
if (!$json) {
36+
$jsonArray = [];
37+
} else {
38+
$jsonArray = json_decode($json, true);
39+
}
40+
41+
// Some operations with json
42+
$jsonArray = array_merge($jsonArray, $array);
43+
44+
$json = json_encode($jsonArray);
45+
// Update key in storage
46+
$Redis->set($key, $json);
47+
48+
// Release the lock
49+
// After $lock->release() another waiting thread (Lock) will be able to update json in storage
50+
$Lock->release();
51+
}
52+
53+
updateJsonInRedis($Redis, 'json-key', ['for' => 1, 'bar' => 2]);
54+
updateJsonInRedis($Redis, 'json-key', ['for' => 42, 'var' => 2016]);

phpunit.xml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
backupGlobals = "false"
4+
backupStaticAttributes = "false"
5+
colors = "true"
6+
convertErrorsToExceptions = "true"
7+
convertNoticesToExceptions = "true"
8+
convertWarningsToExceptions = "true"
9+
processIsolation = "false"
10+
stopOnFailure = "false"
11+
stopOnError = "false"
12+
stopOnIncomplete = "false"
13+
stopOnSkipped = "false"
14+
bootstrap = "vendor/autoload.php"
15+
syntaxCheck = "true"
16+
verbose = "true"
17+
beStrictAboutTestsThatDoNotTestAnything = "true"
18+
checkForUnintentionallyCoveredCode = "false"
19+
beStrictAboutOutputDuringTests = "true"
20+
beStrictAboutTestSize = "true"
21+
>
22+
23+
<php>
24+
<const name="REDIS_TEST_SERVER" value="tcp://127.0.0.1:6379" />
25+
<const name="MEMCACHED_TEST_SERVER" value="127.0.0.1:11211" />
26+
</php>
27+
28+
<testsuites>
29+
<testsuite name="All tests">
30+
<directory suffix="Test.php" >./test/</directory>
31+
</testsuite>
32+
</testsuites>
33+
34+
</phpunit>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/**
3+
* This file is part of RedisLock.
4+
* git: https://github.com/cheprasov/php-redis-lock
5+
*
6+
* (C) Alexander Cheprasov <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
namespace RedisLock\Exception;
12+
13+
class InvalidArgumentException extends LockException {
14+
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/**
3+
* This file is part of RedisLock.
4+
* git: https://github.com/cheprasov/php-redis-lock
5+
*
6+
* (C) Alexander Cheprasov <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
namespace RedisLock\Exception;
12+
13+
class LockException extends \Exception {
14+
15+
}

0 commit comments

Comments
 (0)