Completed
Push — master ( 65b5b4...2290e5 )
by Arne
05:25
created

AbstractLockAdapter::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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