Your IP : 127.0.0.1
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Framework\Lock\Backend;
use Magento\Framework\Lock\LockManagerInterface;
use Magento\Framework\Filesystem\Driver\File as FileDriver;
use Magento\Framework\Exception\RuntimeException;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Phrase;
/**
* LockManager using the file system for locks
*/
class FileLock implements LockManagerInterface
{
/**
* The file driver instance
*
* @var FileDriver
*/
private $fileDriver;
/**
* The path to the locks storage folder
*
* @var string
*/
private $path;
/**
* How many microseconds to wait before re-try to acquire a lock
*
* @var int
*/
private $sleepCycle = 100000;
/**
* The mapping list of the path lock with the file resource
*
* @var array
*/
private $locks = [];
/**
* @param FileDriver $fileDriver The file driver
* @param string $path The path to the locks storage folder
* @throws RuntimeException Throws RuntimeException if $path is empty
* or cannot create the directory for locks
*/
public function __construct(FileDriver $fileDriver, string $path)
{
if (!$path) {
throw new RuntimeException(new Phrase('The path needs to be a non-empty string.'));
}
$this->fileDriver = $fileDriver;
$this->path = rtrim($path, '/') . '/';
try {
if (!$this->fileDriver->isExists($this->path)) {
$this->fileDriver->createDirectory($this->path);
}
} catch (FileSystemException $exception) {
throw new RuntimeException(
new Phrase('Cannot create the directory for locks: %1', [$this->path]),
$exception
);
}
}
/**
* Acquires a lock by name
*
* @param string $name The lock name
* @param int $timeout Timeout in seconds. A negative timeout value means infinite timeout
* @return bool Returns true if the lock is acquired, otherwise returns false
* @throws RuntimeException Throws RuntimeException if cannot acquires the lock because FS problems
*/
public function lock(string $name, int $timeout = -1): bool
{
try {
$lockFile = $this->getLockPath($name);
$fileResource = $this->fileDriver->fileOpen($lockFile, 'w+');
$skipDeadline = $timeout < 0;
$deadline = microtime(true) + $timeout;
while (!$this->tryToLock($fileResource)) {
if (!$skipDeadline && $deadline <= microtime(true)) {
$this->tryToUnlock($fileResource);
$this->fileDriver->fileClose($fileResource);
return false;
}
usleep($this->sleepCycle);
}
} catch (FileSystemException $exception) {
throw new RuntimeException(new Phrase('Cannot acquire a lock.'), $exception);
}
$this->locks[$lockFile] = $fileResource;
return true;
}
/**
* Checks if a lock exists by name
*
* @param string $name The lock name
* @return bool Returns true if the lock exists, otherwise returns false
* @throws RuntimeException Throws RuntimeException if cannot check that the lock exists
*/
public function isLocked(string $name): bool
{
$lockFile = $this->getLockPath($name);
$result = false;
try {
if ($this->fileDriver->isExists($lockFile)) {
$fileResource = $this->fileDriver->fileOpen($lockFile, 'w+');
if ($this->tryToLock($fileResource)) {
$result = false;
} else {
$result = true;
}
$this->tryToUnlock($fileResource);
$this->fileDriver->fileClose($fileResource);
}
} catch (FileSystemException $exception) {
throw new RuntimeException(new Phrase('Cannot verify that the lock exists.'), $exception);
}
return $result;
}
/**
* Remove the lock by name
*
* @param string $name The lock name
* @return bool If the lock is removed returns true, otherwise returns false
*/
public function unlock(string $name): bool
{
$lockFile = $this->getLockPath($name);
if (isset($this->locks[$lockFile]) && $this->tryToUnlock($this->locks[$lockFile])) {
unset($this->locks[$lockFile]);
return true;
}
return false;
}
/**
* Returns the full path to the lock file by name
*
* @param string $name The lock name
* @return string The path to the lock file
*/
private function getLockPath(string $name): string
{
return $this->path . $name;
}
/**
* Tries to lock a file resource
*
* @param resource $resource The file resource
* @return bool If the lock is acquired returns true, otherwise returns false
*/
private function tryToLock($resource): bool
{
try {
return $this->fileDriver->fileLock($resource, LOCK_EX | LOCK_NB);
} catch (FileSystemException $exception) {
return false;
}
}
/**
* Tries to unlock a file resource
*
* @param resource $resource The file resource
* @return bool If the lock is removed returns true, otherwise returns false
*/
private function tryToUnlock($resource): bool
{
try {
return $this->fileDriver->fileLock($resource, LOCK_UN | LOCK_NB);
} catch (FileSystemException $exception) {
return false;
}
}
}