Test Failed
Pull Request — master (#12)
by Evgeniy
12:20 queued 10:09
created

OracleMutex   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
wmc 10
eloc 49
c 3
b 2
f 0
dl 0
loc 124
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A isReleased() 0 3 1
A acquire() 0 32 4
A release() 0 21 3
A __construct() 0 18 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Mutex;
6
7
use InvalidArgumentException;
8
use PDO;
9
10
/**
11
 * OracleMutex implements mutex "lock" mechanism via Oracle locks.
12
 *
13
 * Application configuration example:
14
 *
15
 * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
16
 */
17
class OracleMutex extends Mutex
18
{
19
    /** available lock modes */
20
    public const MODE_X = 'X_MODE';
21
    public const MODE_NL = 'NL_MODE';
22
    public const MODE_S = 'S_MODE';
23
    public const MODE_SX = 'SX_MODE';
24
    public const MODE_SS = 'SS_MODE';
25
    public const MODE_SSX = 'SSX_MODE';
26
27
    protected PDO $connection;
28
    private bool $released = false;
29
30
    /**
31
     * @var string lock mode to be used.
32
     *
33
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#CHDBCFDI
34
     */
35
    private string $lockMode;
36
    /**
37
     * @var bool whether to release lock on commit.
38
     */
39
    private bool $releaseOnCommit;
40
41
    private string $name;
42
43
    /**
44
     * OracleMutex constructor.
45
     *
46
     * @param string $name Mutex name.
47
     * @param PDO $connection PDO connection instance to use.
48
     * @param string $lockMode Lock mode to be used.
49
     * @param bool $releaseOnCommit Whether to release lock on commit.
50
     */
51
    public function __construct(
52
        string $name,
53
        PDO $connection,
54
        string $lockMode = self::MODE_X,
55
        bool $releaseOnCommit = false
56
    ) {
57
        $this->name = $name;
58
        $this->connection = $connection;
59
60
        $driverName = $connection->getAttribute(PDO::ATTR_DRIVER_NAME);
61
        if (in_array($driverName, ['oci', 'obdb'])) {
62
            throw new InvalidArgumentException(
63
                'Connection must be configured to use Oracle database. Got ' . $driverName . '.'
64
            );
65
        }
66
67
        $this->lockMode = $lockMode;
68
        $this->releaseOnCommit = $releaseOnCommit;
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     *
74
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
75
     */
76
    public function acquire(int $timeout = 0): bool
77
    {
78
        $lockStatus = null;
79
80
        // clean vars before using
81
        $releaseOnCommit = $this->releaseOnCommit ? 'TRUE' : 'FALSE';
82
        $timeout = (int) abs($timeout);
83
84
        // inside pl/sql scopes pdo binding not working correctly :(
85
86
        $statement = $this->connection->prepare('DECLARE
87
            handle VARCHAR2(128);
88
        BEGIN
89
            DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle);
90
            :lockStatus := DBMS_LOCK.REQUEST(
91
                handle,
92
                DBMS_LOCK.' . $this->lockMode . ',
93
                ' . $timeout . ',
94
                ' . $releaseOnCommit . '
95
            );
96
        END;');
97
98
        $statement->bindValue(':name', $this->name);
99
        $statement->bindParam(':lockStatus', $lockStatus, PDO::PARAM_INT, 1);
100
        $statement->execute();
101
102
        if ($lockStatus === 0 || $lockStatus === '0') {
103
            $this->released = false;
104
            return true;
105
        }
106
107
        return false;
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     *
113
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
114
     */
115
    public function release(): void
116
    {
117
        $releaseStatus = null;
118
119
        $statement = $this->connection->prepare(
120
            'DECLARE
121
                handle VARCHAR2(128);
122
            BEGIN
123
                DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle);
124
                :result := DBMS_LOCK.RELEASE(handle);
125
            END;'
126
        );
127
        $statement->bindValue(':name', $this->name);
128
        $statement->bindParam(':result', $releaseStatus, PDO::PARAM_INT, 1);
129
        $statement->execute();
130
131
        if ($releaseStatus !== 0 && $releaseStatus !== '0') {
132
            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...
133
        }
134
135
        $this->released = true;
136
    }
137
138
    public function isReleased(): bool
139
    {
140
        return $this->released;
141
    }
142
}
143