├── CHANGELOG.md ├── src ├── PgsqlMutexFactory.php └── PgsqlMutex.php ├── LICENSE.md ├── composer.json └── README.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Yii Postgres Mutex Change Log 2 | 3 | ## 1.1.1 under development 4 | 5 | - no changes in this release. 6 | 7 | ## 1.1.0 October 19, 2021 8 | 9 | - Chg #19: Update the version of the `yiisoft/mutex` package to `1.1` in the `require` section of `composer.json` (devanych) 10 | 11 | ## 1.0.0 August 18, 2021 12 | 13 | - Initial release. 14 | -------------------------------------------------------------------------------- /src/PgsqlMutexFactory.php: -------------------------------------------------------------------------------- 1 | connection = $connection; 24 | } 25 | 26 | public function create(string $name): MutexInterface 27 | { 28 | return new PgsqlMutex($name, $this->connection); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2008 by Yii Software (https://www.yiiframework.com/) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Yii Software nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/mutex-pdo-pgsql", 3 | "type": "library", 4 | "description": "Yii Mutex Library - Postgres PDO Driver", 5 | "keywords": [ 6 | "yii", 7 | "mutex" 8 | ], 9 | "homepage": "https://www.yiiframework.com/", 10 | "license": "BSD-3-Clause", 11 | "support": { 12 | "issues": "https://github.com/yiisoft/mutex-pdo-pgsql/issues?state=open", 13 | "source": "https://github.com/yiisoft/mutex-pdo-pgsql", 14 | "forum": "https://www.yiiframework.com/forum/", 15 | "wiki": "https://www.yiiframework.com/wiki/", 16 | "irc": "ircs://irc.libera.chat:6697/yii", 17 | "chat": "https://t.me/yii3en" 18 | }, 19 | "funding": [ 20 | { 21 | "type": "opencollective", 22 | "url": "https://opencollective.com/yiisoft" 23 | }, 24 | { 25 | "type": "github", 26 | "url": "https://github.com/sponsors/yiisoft" 27 | } 28 | ], 29 | "require": { 30 | "php": "^7.4|^8.0", 31 | "ext-pdo": "*", 32 | "yiisoft/mutex": "^1.1" 33 | }, 34 | "require-dev": { 35 | "phpunit/phpunit": "^9.5", 36 | "roave/infection-static-analysis-plugin": "^1.16", 37 | "spatie/phpunit-watcher": "^1.23", 38 | "vimeo/psalm": "^4.30|^5.3" 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "Yiisoft\\Mutex\\Pgsql\\": "src" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "Yiisoft\\Mutex\\Pgsql\\Tests\\": "tests" 48 | } 49 | }, 50 | "config": { 51 | "sort-packages": true, 52 | "allow-plugins": { 53 | "infection/extension-installer": true, 54 | "composer/package-versions-deprecated": true 55 | } 56 | }, 57 | "scripts": { 58 | "test": "phpunit --testdox --no-interaction", 59 | "test-watch": "phpunit-watcher watch" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/PgsqlMutex.php: -------------------------------------------------------------------------------- 1 | lockKeys = array_values(unpack('n2', sha1($name, true))); 31 | $this->connection = $connection; 32 | 33 | /** @var string $driverName */ 34 | $driverName = $connection->getAttribute(PDO::ATTR_DRIVER_NAME); 35 | 36 | if ($driverName !== 'pgsql') { 37 | throw new InvalidArgumentException("PostgreSQL connection instance should be passed. Got \"$driverName\"."); 38 | } 39 | 40 | parent::__construct(self::class, $name); 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | * 46 | * @see https://www.postgresql.org/docs/13/functions-admin.html 47 | */ 48 | protected function acquireLock(int $timeout = 0): bool 49 | { 50 | $statement = $this->connection->prepare('SELECT pg_try_advisory_lock(:key1, :key2)'); 51 | $statement->bindValue(':key1', $this->lockKeys[0]); 52 | $statement->bindValue(':key2', $this->lockKeys[1]); 53 | $statement->execute(); 54 | 55 | return (bool) $statement->fetchColumn(); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | * 61 | * @see https://www.postgresql.org/docs/13/functions-admin.html 62 | */ 63 | protected function releaseLock(): bool 64 | { 65 | $statement = $this->connection->prepare('SELECT pg_advisory_unlock(:key1, :key2)'); 66 | $statement->bindValue(':key1', $this->lockKeys[0]); 67 | $statement->bindValue(':key2', $this->lockKeys[1]); 68 | $statement->execute(); 69 | 70 | return (bool) $statement->fetchColumn(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Yii 4 | 5 |

Yii Mutex Library - PostgreSQL PDO Driver

6 |
7 |

8 | 9 | [![Latest Stable Version](https://poser.pugx.org/yiisoft/mutex-pdo-pgsql/v)](https://packagist.org/packages/yiisoft/mutex-pdo-pgsql) 10 | [![Total Downloads](https://poser.pugx.org/yiisoft/mutex-pdo-pgsql/downloads)](https://packagist.org/packages/yiisoft/mutex-pdo-pgsql) 11 | [![Build status](https://github.com/yiisoft/mutex-pdo-pgsql/actions/workflows/build.yml/badge.svg)](https://github.com/yiisoft/mutex-pdo-pgsql/actions/workflows/build.yml) 12 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yiisoft/mutex-pdo-pgsql/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/mutex-pdo-pgsql/?branch=master) 13 | [![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/mutex-pdo-pgsql/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/mutex-pdo-pgsql/?branch=master) 14 | [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Fmutex-pdo-pgsql%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/mutex-pdo-pgsql/master) 15 | [![static analysis](https://github.com/yiisoft/mutex-pdo-pgsql/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/mutex-pdo-pgsql/actions?query=workflow%3A%22static+analysis%22) 16 | [![type-coverage](https://shepherd.dev/github/yiisoft/mutex-pdo-pgsql/coverage.svg)](https://shepherd.dev/github/yiisoft/mutex-pdo-pgsql) 17 | 18 | This library provides a PostgreSQL mutex implementation for [yiisoft/mutex](https://github.com/yiisoft/mutex). 19 | 20 | ## Requirements 21 | 22 | - PHP 7.4 or higher. 23 | - `PDO` PHP extension. 24 | 25 | ## Installation 26 | 27 | The package could be installed with [Composer](https://getcomposer.org): 28 | 29 | ```shell 30 | composer require yiisoft/mutex-pdo-pgsql 31 | ``` 32 | 33 | ## General usage 34 | 35 | The package provides two classes implementing `MutexInterface` and `MutexFactoryInterface` 36 | from the [yiisoft/mutex](https://github.com/yiisoft/mutex) package: 37 | 38 | ```php 39 | /** 40 | * @var \PDO $connection Configured for PostgreSQL. 41 | */ 42 | 43 | $mutex = new \Yiisoft\Mutex\Pgsql\PgsqlMutex('mutex-name', $connection); 44 | 45 | $mutexFactory = new \Yiisoft\Mutex\Pgsql\PgsqlMutexFactory($connection); 46 | ``` 47 | 48 | There are multiple ways you can use the package. You can execute a callback in a synchronized mode i.e. only a 49 | single instance of the callback is executed at the same time: 50 | 51 | ```php 52 | $synchronizer = new \Yiisoft\Mutex\Synchronizer($mutexFactory); 53 | 54 | $newCount = $synchronizer->execute('critical', function () { 55 | return $counter->increase(); 56 | }, 10); 57 | ``` 58 | 59 | Another way is to manually open and close mutex: 60 | 61 | ```php 62 | $simpleMutex = \Yiisoft\Mutex\SimpleMutex($mutexFactory); 63 | 64 | if (!$simpleMutex->acquire('critical', 10)) { 65 | throw new \Yiisoft\Mutex\Exception\MutexLockedException('Unable to acquire the "critical" mutex.'); 66 | } 67 | 68 | $newCount = $counter->increase(); 69 | $simpleMutex->release('critical'); 70 | ``` 71 | 72 | It could be done on lower level: 73 | 74 | ```php 75 | $mutex = $mutexFactory->createAndAcquire('critical', 10); 76 | $newCount = $counter->increase(); 77 | $mutex->release(); 78 | ``` 79 | 80 | And if you want even more control, you can acquire mutex manually: 81 | 82 | ```php 83 | $mutex = $mutexFactory->create('critical'); 84 | 85 | if (!$mutex->acquire(10)) { 86 | throw new \Yiisoft\Mutex\Exception\MutexLockedException('Unable to acquire the "critical" mutex.'); 87 | } 88 | 89 | $newCount = $counter->increase(); 90 | $mutex->release(); 91 | ``` 92 | 93 | The `PgsqlMutex` supports the "wait for a lock for a certain time" functionality. Using the `withRetryDelay()` 94 | method, you can override the number of milliseconds between each try until specified timeout times out: 95 | 96 | ```php 97 | $mutex = $mutex->withRetryDelay(100); 98 | ``` 99 | 100 | By default, it is 50 milliseconds - it means that we may try to acquire lock up to 20 times per second. 101 | 102 | ## Documentation 103 | 104 | - [Internals](docs/internals.md) 105 | 106 | If you need help or have a question, the [Yii Forum](https://forum.yiiframework.com/c/yii-3-0/63) is a good place for that. 107 | You may also check out other [Yii Community Resources](https://www.yiiframework.com/community). 108 | 109 | ## License 110 | 111 | The Yii Mutex Library - PostgreSQL PDO Driver is free software. It is released under the terms of the BSD License. 112 | Please see [`LICENSE`](./LICENSE.md) for more information. 113 | 114 | Maintained by [Yii Software](https://www.yiiframework.com/). 115 | 116 | ## Support the project 117 | 118 | [![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective&logoColor=7eadf1&labelColor=555555)](https://opencollective.com/yiisoft) 119 | 120 | ## Follow updates 121 | 122 | [![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/) 123 | [![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter&logoColor=1DA1F2&labelColor=555555?style=flat)](https://twitter.com/yiiframework) 124 | [![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat&logo=telegram)](https://t.me/yii3en) 125 | [![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat&logo=facebook&logoColor=ffffff)](https://www.facebook.com/groups/yiitalk) 126 | [![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat&logo=slack)](https://yiiframework.com/go/slack) 127 | --------------------------------------------------------------------------------