Completed
Push — master ( 073c6d...49d4ca )
by Dmitry
06:07
created

Lock::lock()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 0
cts 12
cp 0
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 12
1
<?php
2
3
namespace Basis;
4
5
use Exception;
6
use Predis\Client;
7
8
class Lock
9
{
10
    private $redis;
11
    private $locks = [];
12
13
    public function __construct(Client $redis)
14
    {
15
        $this->redis = $redis;
16
        register_shutdown_function([$this, 'releaseLocks']);
17
    }
18
19
    public function acquire($name, $ttl = 1)
20
    {
21
        while (!$this->lock($name, $ttl)) {
22
            $this->waitUnlock($name);
23
        }
24
        return true;
25
    }
26
27
    public function exists($name)
28
    {
29
        return $this->redis->get("lock-$name") !== null;
30
    }
31
32
    public function lock($name, $ttl = 1)
33
    {
34
        if (in_array($name, $this->locks)) {
35
            throw new Exception("Lock $name was already registered");
36
        }
37
        $result = $this->redis->set("lock-$name", 1, 'EX', $ttl, 'NX');
38
        if ($result) {
39
            $this->locks[] = $name;
40
            return true;
41
        }
42
        return false;
43
    }
44
45
    public function releaseLocks()
46
    {
47
        foreach ($this->locks as $name) {
48
            $this->unlock($name);
49
        }
50
    }
51
52
    public function unlock($name)
53
    {
54
        if (!in_array($name, $this->locks)) {
55
            throw new Exception("Lock $name was already registered");
56
        }
57
        
58
        foreach ($this->locks as $i => $candidate) {
59
            if ($candidate == $name) {
60
                unset($this->locks[$i]);
61
                $this->redis->del("lock-$name");
62
                break;
63
            }
64
        }
65
66
        $this->locks = array_values($this->locks);
67
    }
68
69
    public function waitUnlock($name)
70
    {
71
        while ($this->exists($name)) {
72
            usleep(100);
73
        }
74
        return true;
75
    }
76
}
77