Test Failed
Pull Request — master (#13)
by
unknown
02:24
created

PgsqlMutex::__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 PDO;
8
9
/**
10
 * PgsqlMutex implements mutex "lock" mechanism via PgSQL locks.
11
 */
12
final class PgsqlMutex implements MutexInterface
13
{
14
    use RetryAcquireTrait;
15
16
    private string $name;
17
    private PDO $connection;
18
    private bool $released = false;
19
20
    /**
21
     * @param string $name Mutex name.
22
     * @param PDO $connection PDO connection instance to use.
23
     */
24
    public function __construct(string $name, PDO $connection)
25
    {
26
        $this->name = $name;
27
        $this->connection = $connection;
28
        $driverName = $connection->getAttribute(PDO::ATTR_DRIVER_NAME);
29
        if ($driverName !== 'pgsql') {
30
            throw new \InvalidArgumentException(
31
                'Connection must be configured to use PgSQL database. Got ' . $driverName . '.'
32
            );
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://www.postgresql.org/docs/9.0/static/functions-admin.html
47
     */
48
    public function acquire(int $timeout = 0): bool
49
    {
50
        [$key1, $key2] = $this->getKeysFromName($this->name);
51
52
        return $this->retryAcquire($timeout, function () use ($key1, $key2) {
53
            $statement = $this->connection->prepare('SELECT pg_try_advisory_lock(:key1, :key2)');
54
            $statement->bindValue(':key1', $key1);
55
            $statement->bindValue(':key2', $key2);
56
            $statement->execute();
57
58
            if ($statement->fetchColumn()) {
59
                $this->released = false;
60
                return true;
61
            }
62
63
            return false;
64
        });
65
    }
66
67
    /**
68
     * {@inheritdoc}
69
     *
70
     * @see http://www.postgresql.org/docs/9.0/static/functions-admin.html
71
     */
72
    public function release(): void
73
    {
74
        [$key1, $key2] = $this->getKeysFromName($this->name);
75
76
        $statement = $this->connection->prepare('SELECT pg_advisory_unlock(:key1, :key2)');
77
        $statement->bindValue(':key1', $key1);
78
        $statement->bindValue(':key2', $key2);
79
        $statement->execute();
80
81
        if (!$statement->fetchColumn()) {
82
            throw new RuntimeExceptions("Unable to release lock \"$this->name\".");
0 ignored issues
show
Bug introduced by
The type Yiisoft\Mutex\RuntimeExceptions was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
83
        }
84
85
        $this->released = true;
86
    }
87
88
    /**
89
     * Converts a string into two 16 bit integer keys using the SHA1 hash function.
90
     *
91
     * @param string $name
92
     *
93
     * @return array contains two 16 bit integer keys
94
     */
95
    private function getKeysFromName(string $name): array
96
    {
97
        return array_values(unpack('n2', sha1($name, true)));
98
    }
99
}
100