Skip to content

Commit 4acf9ea

Browse files
author
Mathieu Rochette
committed
Initial commit
0 parents  commit 4acf9ea

File tree

8 files changed

+219
-0
lines changed

8 files changed

+219
-0
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
composer.lock
2+
/vendor/

Diff for: .travis.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
language: php
2+
3+
php:
4+
- 5.4
5+
- 5.5
6+
- 5.6
7+
- hhvm
8+
9+
before_script:
10+
- composer install -n
11+
12+
script:
13+
- vendor/bin/phpspec run -f pretty

Diff for: composer.json

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "texthtml/php-lock",
3+
"description" : "ressource lock",
4+
"license": "aGPLv3",
5+
"type": "library",
6+
"autoload": {
7+
"psr-4": { "TH\\Lock\\": "src" }
8+
},
9+
"authors": [
10+
{
11+
"name": "Mathieu Rochette",
12+
"email": "[email protected]"
13+
}
14+
],
15+
"require-dev": {
16+
"phpspec/phpspec": "~2.0",
17+
"php-vfs/php-vfs": "~1.1"
18+
},
19+
"require": {
20+
"psr/log": "~1.0"
21+
}
22+
}

Diff for: spec/TH/Lock/FileFactorySpec.php

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace spec\TH\Lock;
4+
5+
use VirtualFileSystem\FileSystem;
6+
use Psr\Log\LoggerInterface;
7+
use PhpSpec\ObjectBehavior;
8+
use Prophecy\Argument;
9+
10+
class FileFactorySpec extends ObjectBehavior
11+
{
12+
private $fs;
13+
private $lock_dir;
14+
15+
public function let(LoggerInterface $logger)
16+
{
17+
$this->fs = new FileSystem;
18+
$this->lock_dir = $this->fs->path('/path/to/lock_dir');
19+
20+
$this->beConstructedWith($logger, $this->lock_dir, 'sha256');
21+
}
22+
23+
public function it_is_initializable()
24+
{
25+
$this->shouldHaveType('TH\Lock\FileFactory');
26+
$this->shouldImplement('TH\Lock\LockFactory');
27+
}
28+
29+
public function it_should_create_a_file_lock()
30+
{
31+
$this->create('some resource identifier')->shouldhaveType('TH\Lock\FileLock');
32+
}
33+
}

Diff for: src/FileFactory.php

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace TH\Lock;
4+
5+
use Psr\Log\LoggerInterface;
6+
use Psr\Log\NullLogger;
7+
8+
class FileFactory implements LockFactory
9+
{
10+
private $lock_dir;
11+
private $logger;
12+
private $hash_algo;
13+
14+
public function __construct(LoggerInterface $logger, $lock_dir, $hash_algo = 'sha256')
15+
{
16+
$this->logger = $logger;
17+
$this->lock_dir = $lock_dir;
18+
$this->hash_algo = $hash_algo;
19+
}
20+
21+
public function create($resource, $owner = null, $operation = LOCK_EX)
22+
{
23+
if (!is_dir($this->lock_dir)) {
24+
mkdir($this->lock_dir, 0777, true);
25+
}
26+
27+
$path = $this->lock_dir.'/'.hash($this->hash_algo, serialize($resource)).'.lock';
28+
29+
$lock = new FileLock($path, $resource, $owner, $operation);
30+
31+
$lock->setLogger($this->logger);
32+
33+
return $lock;
34+
}
35+
}

Diff for: src/FileLock.php

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace TH\Lock;
4+
5+
use Psr\Log\LoggerInterface;
6+
use Psr\Log\NullLogger;
7+
use Exception;
8+
9+
class FileLock implements Lock
10+
{
11+
private $identifier;
12+
private $lock_file;
13+
private $owner;
14+
private $operation;
15+
private $fh;
16+
17+
public function __construct($lock_file, $identifier = null, $owner = null, $operation = LOCK_EX, $blocking = false)
18+
{
19+
$this->identifier = $identifier?:$lock_file;
20+
$this->lock_file = $lock_file;
21+
$this->owner = $owner === null ? '' : $owner.': ';
22+
$this->operation = $operation | LOCK_NB;
23+
24+
if ($blocking) {
25+
$this->operation &= ~LOCK_NB;
26+
}
27+
28+
$this->logger = new NullLogger;
29+
}
30+
31+
public function acquire()
32+
{
33+
$blocking = !$this->operation & LOCK_NB;
34+
$exclusive = $this->operation & LOCK_EX;
35+
36+
if (!flock($this->fh(), $this->operation)) {
37+
$this->logger->debug(($exclusive ?
38+
'{owner} could not acquire exclusive lock on {identifier}':
39+
'{owner} could not acquire shared lock on {identifier}'
40+
), [
41+
'identifier' => $this->identifier,
42+
'owner' => $this->owner
43+
]);
44+
45+
throw new Exception(
46+
'Could not acquire exclusive lock on '.($this->identifier ? $this->identifier : $this->lock_file)
47+
);
48+
49+
}
50+
51+
$this->logger->debug(($exclusive ?
52+
'{owner} exclusive lock acquired on {identifier}':
53+
'{owner} shared lock acquired on {identifier}'
54+
), [
55+
'identifier' => $this->identifier,
56+
'owner' => $this->owner
57+
]);
58+
59+
return true;
60+
}
61+
62+
public function release()
63+
{
64+
if ($this->fh === null) {
65+
return;
66+
}
67+
68+
flock($this->fh, LOCK_UN);
69+
70+
$this->logger->debug(
71+
'{owner} lock released on {identifier}',
72+
[
73+
'identifier' => $this->identifier,
74+
'owner' => $this->owner
75+
]
76+
);
77+
}
78+
79+
public function setLogger(LoggerInterface $logger)
80+
{
81+
$this->logger = $logger;
82+
}
83+
84+
public function __destruct()
85+
{
86+
$this->release();
87+
}
88+
89+
private function fh()
90+
{
91+
if ($this->fh === null) {
92+
$this->fh = fopen($this->lock_file, 'c');
93+
}
94+
95+
return $this->fh;
96+
}
97+
}

Diff for: src/Lock.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace TH\Lock;
4+
5+
interface Lock
6+
{
7+
public function acquire();
8+
public function release();
9+
}

Diff for: src/LockFactory.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace TH\Lock;
4+
5+
interface LockFactory
6+
{
7+
public function create($resource, $owner = null);
8+
}

0 commit comments

Comments
 (0)