Completed
Push — pr21 ( ec1d9e )
by Kamil
02:27
created

LockAbstract   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Test Coverage

Coverage 84.38%

Importance

Changes 0
Metric Value
wmc 16
c 0
b 0
f 0
lcom 2
cbo 3
dl 0
loc 110
ccs 27
cts 32
cp 0.8438
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __clone() 0 4 1
getLock() 0 1 ?
A __construct() 0 4 2
A getLockInformation() 0 4 1
A getLockInformationProvider() 0 4 1
A setLockInformationProvider() 0 4 1
A __destruct() 0 12 3
B acquireLock() 0 18 7
1
<?php
2
/**
3
 * This file is part of ninja-mutex.
4
 *
5
 * (C) Kamil Dziedzic <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace NinjaMutex\Lock;
11
12
use NinjaMutex\UnrecoverableMutexException;
13
14
/**
15
 * Abstract lock implementor
16
 *
17
 * @author Kamil Dziedzic <[email protected]>
18
 */
19
abstract class LockAbstract implements LockInterface
20
{
21
    const USLEEP_TIME = 100;
22
23
    /**
24
     * Provides information which allows to track down process which acquired lock
25
     *
26
     * @var LockInformationProviderInterface
27
     */
28
    protected $lockInformationProvider;
29
30
    /**
31
     * @var array
32
     */
33
    protected $locks = array();
34
35 1
    public function __construct(LockInformationProviderInterface $informationProvider = null)
36
    {
37 1
        $this->lockInformationProvider = $informationProvider ? : new BasicLockInformationProvider();
38 1
    }
39
40 55
    public function __clone()
41
    {
42 55
        $this->locks = array();
43 55
    }
44
45
    /**
46
     * Try to release any obtained locks when object is destroyed
47
     *
48
     * This is a safe guard for cases when your php script dies unexpectedly.
49
     * It's not guaranteed it will work either.
50
     *
51
     * You should not depend on __destruct() to release your locks,
52
     * instead release them with `$released = $this->releaseLock()`A
53
     * and check `$released` if lock was properly released
54
     */
55 49
    public function __destruct()
56
    {
57 49
        foreach ($this->locks as $name => $v) {
58 12
            $released = $this->releaseLock($name);
59 12
            if (!$released) {
60 3
                throw new UnrecoverableMutexException(sprintf(
61 3
                    'Cannot release lock in __destruct(): %s',
62 12
                    $name
63
                ));
64
            }
65
        }
66 46
    }
67
68
    /**
69
     * Acquire lock
70
     *
71
     * @param  string   $name    name of lock
72
     * @param  null|int $timeout 1. null if you want blocking lock
73
     *                           2. 0 if you want just lock and go
74
     *                           3. $timeout > 0 if you want to wait for lock some time (in milliseconds)
75
     * @return bool
76
     */
77 180
    public function acquireLock($name, $timeout = null)
78
    {
79 180
        $blocking = $timeout === null;
80 180
        $start = microtime(true);
81 180
        $end = $start + $timeout / 1000;
82 180
        $locked = false;
83 180
        while (!(empty($this->locks[$name]) && $locked = $this->getLock($name, $blocking)) && ($blocking || ($timeout > 0 && microtime(true) < $end))) {
84 11
            usleep(static::USLEEP_TIME);
85
        }
86
87 180
        if ($locked) {
88 180
            $this->locks[$name] = true;
89
90 180
            return true;
91
        }
92
93 80
        return false;
94
    }
95
96
    /**
97
     * @param  string $name
98
     * @param  bool   $blocking
99
     * @return bool
100
     */
101
    abstract protected function getLock($name, $blocking);
102
103
    /**
104
     * Information returned by this method allow to track down process which acquired lock
105
     * .
106
     * @return array
107
     */
108 100
    protected function getLockInformation()
109
    {
110 100
        return $this->lockInformationProvider->getLockInformation();
111
    }
112
113
    /**
114
     * @return LockInformationProviderInterface
115
     */
116
    public function getLockInformationProvider()
117
    {
118
        return $this->lockInformationProvider;
119
    }
120
121
    /**
122
     * @param LockInformationProviderInterface $lockInformationProvider
123
     */
124
    public function setLockInformationProvider($lockInformationProvider)
125
    {
126
        $this->lockInformationProvider = $lockInformationProvider;
127
    }
128
}
129