OracleMutex.php 3.6 KB

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