Test Failed
Pull Request — master (#16)
by
unknown
02:47 queued 34s
created

MysqlMutex::__destruct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Mutex;
6
7
use InvalidArgumentException;
8
use PDO;
9
use RuntimeException;
10
11
/**
12
 * MysqlMutex implements mutex "lock" mechanism via MySQL locks.
13
 */
14
final class MysqlMutex implements MutexInterface
15
{
16
    private string $name;
17
    private PDO $connection;
18
    private bool $released = false;
19
20
    /**
21
     * DbMutex constructor.
22
     *
23
     * @param string $name Mutex name.
24
     * @param PDO $connection PDO connection instance to use.
25
     */
26
    public function __construct(string $name, PDO $connection)
27
    {
28
        $this->name = $name;
29
        $this->connection = $connection;
30
        $driverName = $connection->getAttribute(PDO::ATTR_DRIVER_NAME);
31
        if ($driverName !== 'mysql') {
32
            throw new InvalidArgumentException('MySQL connection instance should be passed. Got ' . $driverName . '.');
33
        }
34
    }
35
36
    public function __destruct()
37
    {
38
        if (!$this->released) {
39
            $this->release();
40
        }
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     *
46
     * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock
47
     */
48
    public function acquire(int $timeout = 0): bool
49
    {
50
        $statement = $this->connection->prepare('SELECT GET_LOCK(:name, :timeout)');
51
        $statement->bindValue(':name', $this->hashLockName($this->name));
52
        $statement->bindValue(':timeout', $timeout);
53
        $statement->execute();
54
55
        if ($statement->fetchColumn()) {
56
            $this->released = false;
57
            return true;
58
        }
59
60
        return false;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     *
66
     * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock
67
     */
68
    public function release(): void
69
    {
70
        $statement = $this->connection->prepare('SELECT RELEASE_LOCK(:name)');
71
        $statement->bindValue(':name', $this->hashLockName($this->name));
72
        $statement->execute();
73
74
        if (!$statement->fetchColumn()) {
75
            throw new RuntimeException("Unable to release lock \"$this->name\".");
76
        }
77
78
        $this->released = true;
79
    }
80
81
    /**
82
     * Generate hash for lock name to avoid exceeding lock name length limit.
83
     *
84
     * @param string $name
85
     *
86
     * @return string
87
     *
88
     * @see https://github.com/yiisoft/yii2/pull/16836
89
     */
90
    private function hashLockName(string $name): string
91
    {
92
        return sha1($name);
93
    }
94
}
95