From 503c1b5c0a2a2657bf52383c665b1c6b40a17181 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 11 Mar 2024 05:06:03 +0100 Subject: [PATCH] Add KeyedFileMutex (#62) * Add KeyedFileMutex * Rebase and update * Style fix * Swap prefix for directory --------- Co-authored-by: Aaron Piotrowski --- src/KeyedFileMutex.php | 75 +++++++++++++++++++++++++++++++++++++ test/KeyedFileMutexTest.php | 27 +++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/KeyedFileMutex.php create mode 100644 test/KeyedFileMutexTest.php diff --git a/src/KeyedFileMutex.php b/src/KeyedFileMutex.php new file mode 100644 index 0000000..da646f8 --- /dev/null +++ b/src/KeyedFileMutex.php @@ -0,0 +1,75 @@ +filesystem = $filesystem ?? filesystem(); + $this->directory = \rtrim($directory, "/\\"); + + if (!$this->filesystem->isDirectory($this->directory)) { + throw new ValueError(\sprintf('Directory "%s" does not exist', $this->directory)); + } + } + + public function acquire(string $key): Lock + { + $filename = $this->getFilename($key); + + // 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 = $this->filesystem->openFile($filename, 'x'); + + // Return a lock object that can be used to release the lock on the mutex. + $lock = new Lock(fn () => $this->release($filename)); + + $file->close(); + + return $lock; + } catch (FilesystemException) { + delay(self::LATENCY_TIMEOUT); + } + } + } + + /** + * Releases the lock on the mutex. + * + * @throws SyncException + */ + private function release(string $filename): void + { + try { + $this->filesystem->deleteFile($filename); + } catch (\Throwable $exception) { + throw new SyncException( + 'Failed to unlock the mutex file: ' . $filename, + previous: $exception, + ); + } + } + + private function getFilename(string $key): string + { + return $this->directory . '/' . \hash('sha256', $key) . '.lock'; + } +} diff --git a/test/KeyedFileMutexTest.php b/test/KeyedFileMutexTest.php new file mode 100644 index 0000000..2852721 --- /dev/null +++ b/test/KeyedFileMutexTest.php @@ -0,0 +1,27 @@ +