1 | <?php |
||
2 | /** |
||
3 | * @link https://www.yiiframework.com/ |
||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
5 | * @license https://www.yiiframework.com/license/ |
||
6 | */ |
||
7 | |||
8 | namespace yii\mutex; |
||
9 | |||
10 | use PDO; |
||
11 | use yii\base\InvalidConfigException; |
||
12 | |||
13 | /** |
||
14 | * OracleMutex implements mutex "lock" mechanism via Oracle locks. |
||
15 | * |
||
16 | * Application configuration example: |
||
17 | * |
||
18 | * ``` |
||
19 | * [ |
||
20 | * 'components' => [ |
||
21 | * 'db' => [ |
||
22 | * 'class' => 'yii\db\Connection', |
||
23 | * 'dsn' => 'oci:dbname=LOCAL_XE', |
||
24 | * ... |
||
25 | * ] |
||
26 | * 'mutex' => [ |
||
27 | * 'class' => 'yii\mutex\OracleMutex', |
||
28 | * 'lockMode' => 'NL_MODE', |
||
29 | * 'releaseOnCommit' => true, |
||
30 | * ... |
||
31 | * ], |
||
32 | * ], |
||
33 | * ] |
||
34 | * ``` |
||
35 | * |
||
36 | * @see https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#ARPLS021 |
||
37 | * @see Mutex |
||
38 | * |
||
39 | * @author Alexander Zlakomanov <[email protected]> |
||
40 | * @since 2.0.10 |
||
41 | */ |
||
42 | class OracleMutex extends DbMutex |
||
43 | { |
||
44 | /** available lock modes */ |
||
45 | const MODE_X = 'X_MODE'; |
||
46 | const MODE_NL = 'NL_MODE'; |
||
47 | const MODE_S = 'S_MODE'; |
||
48 | const MODE_SX = 'SX_MODE'; |
||
49 | const MODE_SS = 'SS_MODE'; |
||
50 | const MODE_SSX = 'SSX_MODE'; |
||
51 | |||
52 | /** |
||
53 | * @var string lock mode to be used. |
||
54 | * @see https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#ARPLS021#CHDBCFDI |
||
55 | */ |
||
56 | public $lockMode = self::MODE_X; |
||
57 | /** |
||
58 | * @var bool whether to release lock on commit. |
||
59 | */ |
||
60 | public $releaseOnCommit = false; |
||
61 | |||
62 | |||
63 | /** |
||
64 | * Initializes Oracle specific mutex component implementation. |
||
65 | * @throws InvalidConfigException if [[db]] is not Oracle connection. |
||
66 | */ |
||
67 | public function init() |
||
68 | { |
||
69 | parent::init(); |
||
70 | if (strncmp($this->db->driverName, 'oci', 3) !== 0 && strncmp($this->db->driverName, 'odbc', 4) !== 0) { |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
71 | throw new InvalidConfigException('In order to use OracleMutex connection must be configured to use Oracle database.'); |
||
72 | } |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Acquires lock by given name. |
||
77 | * @see https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#ARPLS021 |
||
78 | * @param string $name of the lock to be acquired. |
||
79 | * @param int $timeout time (in seconds) to wait for lock to become released. |
||
80 | * @return bool acquiring result. |
||
81 | */ |
||
82 | protected function acquireLock($name, $timeout = 0) |
||
83 | { |
||
84 | $lockStatus = null; |
||
85 | |||
86 | // clean vars before using |
||
87 | $releaseOnCommit = $this->releaseOnCommit ? 'TRUE' : 'FALSE'; |
||
88 | $timeout = abs((int) $timeout); |
||
89 | |||
90 | // inside pl/sql scopes pdo binding not working correctly :( |
||
91 | $this->db->useMaster(function ($db) use ($name, $timeout, $releaseOnCommit, &$lockStatus) { |
||
92 | /** @var \yii\db\Connection $db */ |
||
93 | $db->createCommand( |
||
94 | 'DECLARE |
||
95 | handle VARCHAR2(128); |
||
96 | BEGIN |
||
97 | DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle); |
||
98 | :lockStatus := DBMS_LOCK.REQUEST(handle, DBMS_LOCK.' . $this->lockMode . ', ' . $timeout . ', ' . $releaseOnCommit . '); |
||
99 | END;', |
||
100 | [':name' => $name] |
||
101 | ) |
||
102 | ->bindParam(':lockStatus', $lockStatus, PDO::PARAM_INT, 1) |
||
103 | ->execute(); |
||
104 | }); |
||
105 | |||
106 | return $lockStatus === 0 || $lockStatus === '0'; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Releases lock by given name. |
||
111 | * @param string $name of the lock to be released. |
||
112 | * @return bool release result. |
||
113 | * @see https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#ARPLS021 |
||
114 | */ |
||
115 | protected function releaseLock($name) |
||
116 | { |
||
117 | $releaseStatus = null; |
||
118 | $this->db->useMaster(function ($db) use ($name, &$releaseStatus) { |
||
119 | /** @var \yii\db\Connection $db */ |
||
120 | $db->createCommand( |
||
121 | 'DECLARE |
||
122 | handle VARCHAR2(128); |
||
123 | BEGIN |
||
124 | DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle); |
||
125 | :result := DBMS_LOCK.RELEASE(handle); |
||
126 | END;', |
||
127 | [':name' => $name] |
||
128 | ) |
||
129 | ->bindParam(':result', $releaseStatus, PDO::PARAM_INT, 1) |
||
130 | ->execute(); |
||
131 | }); |
||
132 | |||
133 | return $releaseStatus === 0 || $releaseStatus === '0'; |
||
134 | } |
||
135 | } |
||
136 |