You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 line
3.6KB

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