1
0
mirror of https://github.com/danog/file.git synced 2025-01-22 13:21:13 +01:00

Add AsyncFileMutex (#43)

This commit is contained in:
Jáchym Toušek 2020-05-02 11:14:21 +02:00 committed by GitHub
parent 01e2a91e34
commit 289a723d5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 5 deletions

View File

@ -31,9 +31,9 @@ before_install:
install:
- if [ "$TRAVIS_PHP_VERSION" = "nightly" ]; then
composer update -n --prefer-dist --ignore-platform-reqs;
composer update -n --ignore-platform-reqs;
else
composer update -n --prefer-dist;
composer update -n;
fi
- composer show

View File

@ -35,7 +35,8 @@
"php": ">=7.1",
"amphp/amp": "^2.2",
"amphp/byte-stream": "^1.6.1",
"amphp/parallel": "^1.2"
"amphp/parallel": "^1.2",
"amphp/sync": "^1.3"
},
"require-dev": {
"ext-eio": "^2",
@ -52,7 +53,13 @@
},
"autoload-dev": {
"psr-4": {
"Amp\\File\\Test\\": "test"
"Amp\\File\\Test\\": "test",
"Amp\\Sync\\Test\\": "vendor/amphp/sync/test"
}
},
"config": {
"preferred-install": {
"amphp/sync": "source"
}
},
"extra": {

View File

@ -0,0 +1,84 @@
<?php
namespace Amp\File\Sync;
use Amp\Coroutine;
use Amp\Delayed;
use Amp\File\FilesystemException;
use Amp\Promise;
use Amp\Sync\Lock;
use Amp\Sync\Mutex;
use Amp\Sync\SyncException;
use function Amp\File\open;
use function Amp\File\unlink;
final class AsyncFileMutex implements Mutex
{
private const LATENCY_TIMEOUT = 10;
/** @var string The full path to the lock file. */
private $fileName;
/**
* @param string $fileName Name of temporary file to use as a mutex.
*/
public function __construct(string $fileName)
{
$this->fileName = $fileName;
}
/**
* {@inheritdoc}
*/
public function acquire(): Promise
{
return new Coroutine($this->doAcquire());
}
/**
* @coroutine
*
* @return \Generator
*/
private function doAcquire(): \Generator
{
// Try to create the lock file. If the file already exists, someone else
// has the lock, so set an asynchronous timer and try again.
while (true) {
try {
$file = yield open($this->fileName, 'x');
break;
} catch (FilesystemException $exception) {
yield new Delayed(self::LATENCY_TIMEOUT);
}
}
// Return a lock object that can be used to release the lock on the mutex.
$lock = new Lock(0, function (): void {
$this->release();
});
yield $file->close();
return $lock;
}
/**
* Releases the lock on the mutex.
*/
private function release(): void
{
unlink($this->fileName)->onResolve(
function (?\Throwable $exception): void {
if ($exception !== null) {
throw new SyncException(
'Failed to unlock the mutex file: ' . $this->fileName,
0,
$exception
);
}
}
);
}
}

View File

@ -57,7 +57,7 @@ final class UvDriver implements Driver
$openArr = [$mode, $path, $deferred];
\uv_fs_open($this->loop, $path, $flags, $chmod, function ($fh) use ($openArr): void {
if ($fh) {
if (\is_resource($fh)) {
$this->onOpenHandle($fh, $openArr);
} else {
[, $path, $deferred] = $openArr;

View File

@ -0,0 +1,15 @@
<?php declare(strict_types = 1);
namespace Amp\File\Test\Sync;
use Amp\File\Sync\AsyncFileMutex;
use Amp\Sync\Mutex;
use Amp\Sync\Test\AbstractMutexTest;
final class AsyncFileMutexTest extends AbstractMutexTest
{
public function createMutex(): Mutex
{
return new AsyncFileMutex(\tempnam(\sys_get_temp_dir(), 'mutex-') . '.lock');
}
}