Completed
Push — master ( 7d5317...877556 )
by Arne
02:32
created

AbstractLockAdapter   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 18
lcom 2
cbo 5
dl 0
loc 115
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A isLocked() 0 4 2
A hasLock() 0 4 1
A getLock() 0 4 1
A acquireLock() 0 30 5
A releaseLock() 0 22 3
A __destruct() 0 4 1
A releaseAcquiredLocks() 0 11 3
A getNewLockPayload() 0 4 1
doGetLock() 0 1 ?
doAcquireLock() 0 1 ?
doReleaseLock() 0 1 ?
1
<?php
2
3
namespace Storeman\LockAdapter;
4
5
use Psr\Log\LoggerAwareInterface;
6
use Psr\Log\LoggerAwareTrait;
7
use Psr\Log\NullLogger;
8
use Storeman\Config\Configuration;
9
10
abstract class AbstractLockAdapter implements LockAdapterInterface, LoggerAwareInterface
11
{
12
    use LoggerAwareTrait;
13
14
    /**
15
     * @var int[]
16
     */
17
    protected $lockDepthMap = [];
18
19
    /**
20
     * @var Configuration
21
     */
22
    protected $configuration;
23
24
    public function __construct(Configuration $configuration)
25
    {
26
        $this->configuration = $configuration;
27
        $this->logger = new NullLogger();
28
    }
29
30
    public function isLocked(string $name): bool
31
    {
32
        return $this->hasLock($name) || $this->doGetLock($name) !== null;
33
    }
34
35
    public function hasLock(string $name): bool
36
    {
37
        return array_key_exists($name, $this->lockDepthMap);
38
    }
39
40
    public function getLock(string $name): ?Lock
41
    {
42
        return $this->doGetLock($name);
43
    }
44
45
    public function acquireLock(string $name, int $timeout = null): bool
46
    {
47
        $this->logger->info(sprintf(
48
            "Lock '{$name}' with %s timeout requested. Current lock depth: %s",
49
            is_int($timeout) ? "{$timeout}s" : 'indefinite',
50
            array_key_exists($name, $this->lockDepthMap) ? $this->lockDepthMap[$name] : '0'
51
        ));
52
53
        if (!array_key_exists($name, $this->lockDepthMap))
54
        {
55
            $success = $this->doAcquireLock($name, $timeout);
56
57
            if (!$success)
58
            {
59
                $this->logger->notice("Failed to acquire lock '{$name}'");
60
61
                return false;
62
            }
63
64
            $this->logger->notice("Successfully acquired lock '{$name}'");
65
66
            $this->lockDepthMap[$name] = 0;
67
        }
68
69
        $this->lockDepthMap[$name]++;
70
71
        $this->logger->info("Lock depth for '{$name}' changed to {$this->lockDepthMap[$name]}");
72
73
        return true;
74
    }
75
76
    public function releaseLock(string $name): bool
77
    {
78
        if (array_key_exists($name, $this->lockDepthMap))
79
        {
80
            $this->logger->info("Lock release for '{$name}' requested. Current lock depth: {$this->lockDepthMap[$name]}");
81
82
            if (--$this->lockDepthMap[$name] === 0)
83
            {
84
                $this->logger->notice("Releasing lock '{$name}'...");
85
86
                $this->doReleaseLock($name);
87
88
                unset($this->lockDepthMap[$name]);
89
            }
90
        }
91
        else
92
        {
93
            $this->logger->info("Requested lock release for non-hold lock '{$name}'. Doing nothing.");
94
        }
95
96
        return true;
97
    }
98
99
    public function __destruct()
100
    {
101
        $this->releaseAcquiredLocks();
102
    }
103
104
    protected function releaseAcquiredLocks()
105
    {
106
        $this->logger->info("Releasing all acquired locks: " . ($this->lockDepthMap ? implode(',', array_keys($this->lockDepthMap)) : '-'));
107
108
        foreach (array_keys($this->lockDepthMap) as $lockName)
109
        {
110
            $this->doReleaseLock($lockName);
111
        }
112
113
        $this->lockDepthMap = [];
114
    }
115
116
    protected function getNewLockPayload(string $name): string
117
    {
118
        return (new Lock($name, $this->configuration->getIdentity()))->getPayload();
119
    }
120
121
    abstract protected function doGetLock(string $name): ?Lock;
122
    abstract protected function doAcquireLock(string $name, int $timeout = null): bool;
123
    abstract protected function doReleaseLock(string $name): void;
124
}
125