Final Class Yiisoft\Mutex\File\FileMutex
| Inheritance | Yiisoft\Mutex\File\FileMutex » Yiisoft\Mutex\Mutex |
|---|
FileMutex implements mutex "lock" mechanism via local file system files.
This component relies on PHP {@see \Yiisoft\Mutex\File\flock()} function.
Note: this component can maintain the locks only for the single web server, it probably will not suffice in case you are using cloud server solution.
Warning: due to {@see \Yiisoft\Mutex\File\flock()} function nature this component is unreliable when using a multithreaded server API like ISAPI.
Public Methods
| Method | Description | Defined By |
|---|---|---|
| __construct() | Yiisoft\Mutex\File\FileMutex |
Protected Methods
| Method | Description | Defined By |
|---|---|---|
| acquireLock() | Yiisoft\Mutex\File\FileMutex | |
| releaseLock() | Yiisoft\Mutex\File\FileMutex |
Method Details
| public mixed __construct ( string $name, string $mutexPath, integer $directoryMode = 0775, integer|null $fileMode = null ) | ||
| $name | string |
Mutex name. |
| $mutexPath | string |
The directory to store mutex files. |
| $directoryMode | integer |
The permission to be set for newly created directories. This value will be used by PHP {@see \Yiisoft\Mutex\File\chmod()} function. No umask will be applied. Defaults to 0775, meaning the directory is read-writable by owner and group, but read-only for other users. |
| $fileMode | integer|null |
The permission to be set for newly created mutex files. This value will be used by PHP {@see \Yiisoft\Mutex\File\chmod()} function. No umask will be applied. |
public function __construct(string $name, string $mutexPath, int $directoryMode = 0775, ?int $fileMode = null)
{
FileHelper::ensureDirectory($mutexPath, $directoryMode);
$this->lockFilePath = $mutexPath . DIRECTORY_SEPARATOR . md5($name) . '.lock';
$this->fileMode = $fileMode;
parent::__construct(self::class, $name);
}
| protected boolean acquireLock ( integer $timeout = 0 ) | ||
| $timeout | integer | |
protected function acquireLock(int $timeout = 0): bool
{
$resource = fopen($this->lockFilePath, 'wb+');
if ($resource === false) {
return false;
}
if ($this->fileMode !== null) {
@chmod($this->lockFilePath, $this->fileMode);
}
if (!flock($resource, LOCK_EX | LOCK_NB)) {
fclose($resource);
return false;
}
/**
* Under unix, we delete the lock file before releasing the related handle. Thus, it's possible that we've
* acquired a lock on a non-existing file here (race condition). We must compare the inode of the lock file
* handle with the inode of the actual lock file.
* If they do not match we simply continue the loop since we can assume the inodes will be equal on the
* next try.
* Example of race condition without inode-comparison:
* Script A: locks file
* Script B: opens file
* Script A: unlinks and unlocks file
* Script B: locks handle of *unlinked* file
* Script C: opens and locks *new* file
* In this case we would have acquired two locks for the same file path.
*
* @psalm-suppress PossiblyInvalidArrayAccess We assume that `$resource` is a correct file system pointer
* resource, so `fstat()` always returns array.
*/
if (DIRECTORY_SEPARATOR !== '\\' && fstat($resource)['ino'] !== @fileinode($this->lockFilePath)) {
clearstatcache(true, $this->lockFilePath);
flock($resource, LOCK_UN);
fclose($resource);
return false;
}
$this->lockResource = $resource;
return true;
}
| protected boolean releaseLock ( ) |
protected function releaseLock(): bool
{
if (!is_resource($this->lockResource)) {
return false;
}
if (DIRECTORY_SEPARATOR === '\\') {
// Under windows, it's not possible to delete a file opened via fopen (either by own or other process).
// That's why we must first unlock and close the handle and then *try* to delete the lock file.
flock($this->lockResource, LOCK_UN);
fclose($this->lockResource);
@unlink($this->lockFilePath);
} else {
// Under unix, it's possible to delete a file opened via fopen (either by own or other process).
// That's why we must unlink (the currently locked) lock file first and then unlock and close the handle.
@unlink($this->lockFilePath);
flock($this->lockResource, LOCK_UN);
fclose($this->lockResource);
}
$this->lockResource = null;
return true;
}
Signup or Login in order to comment.