143 linhas
4.0KB

  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 Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\helpers\FileHelper;
  11. /**
  12. * FileMutex implements mutex "lock" mechanism via local file system files.
  13. * This component relies on PHP `flock()` function.
  14. *
  15. * Application configuration example:
  16. *
  17. * ```
  18. * [
  19. * 'components' => [
  20. * 'mutex' => [
  21. * 'class' => 'yii\mutex\FileMutex'
  22. * ],
  23. * ],
  24. * ]
  25. * ```
  26. *
  27. * Note: this component can maintain the locks only for the single web server,
  28. * it probably will not suffice to your in case you are using cloud server solution.
  29. *
  30. * Warning: due to `flock()` function nature this component is unreliable when
  31. * using a multithreaded server API like ISAPI.
  32. *
  33. * @see Mutex
  34. *
  35. * @author resurtm <resurtm@gmail.com>
  36. * @since 2.0
  37. */
  38. class FileMutex extends Mutex
  39. {
  40. /**
  41. * @var string the directory to store mutex files. You may use path alias here.
  42. * Defaults to the "mutex" subdirectory under the application runtime path.
  43. */
  44. public $mutexPath = '@runtime/mutex';
  45. /**
  46. * @var integer the permission to be set for newly created mutex files.
  47. * This value will be used by PHP chmod() function. No umask will be applied.
  48. * If not set, the permission will be determined by the current environment.
  49. */
  50. public $fileMode;
  51. /**
  52. * @var integer the permission to be set for newly created directories.
  53. * This value will be used by PHP chmod() function. No umask will be applied.
  54. * Defaults to 0775, meaning the directory is read-writable by owner and group,
  55. * but read-only for other users.
  56. */
  57. public $dirMode = 0775;
  58. /**
  59. * @var resource[] stores all opened lock files. Keys are lock names and values are file handles.
  60. */
  61. private $_files = [];
  62. /**
  63. * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like
  64. * operating systems.
  65. * @throws InvalidConfigException
  66. */
  67. public function init()
  68. {
  69. if (DIRECTORY_SEPARATOR === '\\') {
  70. throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.');
  71. }
  72. $this->mutexPath = Yii::getAlias($this->mutexPath);
  73. if (!is_dir($this->mutexPath)) {
  74. FileHelper::createDirectory($this->mutexPath, $this->dirMode, true);
  75. }
  76. }
  77. /**
  78. * Acquires lock by given name.
  79. * @param string $name of the lock to be acquired.
  80. * @param integer $timeout to wait for lock to become released.
  81. * @return boolean acquiring result.
  82. */
  83. protected function acquireLock($name, $timeout = 0)
  84. {
  85. $file = fopen($this->getLockFilePath($name), 'w+');
  86. if ($file === false) {
  87. return false;
  88. }
  89. if ($this->fileMode !== null) {
  90. @chmod($this->getLockFilePath($name), $this->fileMode);
  91. }
  92. $waitTime = 0;
  93. while (!flock($file, LOCK_EX | LOCK_NB)) {
  94. $waitTime++;
  95. if ($waitTime > $timeout) {
  96. fclose($file);
  97. return false;
  98. }
  99. sleep(1);
  100. }
  101. $this->_files[$name] = $file;
  102. return true;
  103. }
  104. /**
  105. * Releases lock by given name.
  106. * @param string $name of the lock to be released.
  107. * @return boolean release result.
  108. */
  109. protected function releaseLock($name)
  110. {
  111. if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) {
  112. return false;
  113. } else {
  114. fclose($this->_files[$name]);
  115. unlink($this->getLockFilePath($name));
  116. unset($this->_files[$name]);
  117. return true;
  118. }
  119. }
  120. /**
  121. * Generate path for lock file.
  122. * @param string $name
  123. * @return string
  124. * @since 2.0.10
  125. */
  126. protected function getLockFilePath($name)
  127. {
  128. return $this->mutexPath . '/' . md5($name) . '.lock';
  129. }
  130. }