-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMysqlAdvisoryLocker.php
77 lines (59 loc) · 1.75 KB
/
MysqlAdvisoryLocker.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php
namespace Fervo\AdvisoryLocker;
use Doctrine\DBAL\Connection;
/**
*
*/
class MysqlAdvisoryLocker implements AdvisoryLockerInterface
{
use PerformTrait;
protected $conn;
protected $databaseScope;
public function __construct(Connection $conn, bool $databaseScope = false)
{
$this->conn = $conn;
$this->databaseScope = $databaseScope;
}
public function acquire(string $name)
{
$this->doAcquireLock($name, 0);
}
public function doAcquireLock(string $name, int $wait)
{
$quotedName = $this->lockName($name);
$rs = $this->conn->query("SELECT GET_LOCK($quotedName, $wait);");
if ($rs->fetchColumn(0) !== '1') {
throw new Exception\AcquireFailedException();
}
}
public function release(string $name)
{
$quotedName = $this->lockName($name);
$rs = $this->conn->query("SELECT RELEASE_LOCK($quotedName);");
if ($rs->fetchColumn(0) !== '1') {
throw new Exception\ReleaseFailedException();
}
}
public function performSpinlocked(string $name, callable $callable, int $waitMillis = 100, int $retries = 5)
{
$totalWaitTime = round($waitMillis * $retries / 1000);
$this->doAcquireLock($name, $totalWaitTime);
try {
$callable();
} finally {
$this->release($name);
}
}
private function lockName(string $name)
{
$newName = $name;
if ($this->databaseScope) {
$newName = $this->conn->getDatabase().'-'.$newName;
}
$newName = $this->conn->quote($newName, \PDO::PARAM_STR);
if (strlen($newName) > 64) {
$newName = crc32($newName);
}
return $newName;
}
}