diff --git a/src/mutex/PgAdvisoryLockMutex.php b/src/mutex/PgAdvisoryLockMutex.php index 2e210861..406f7763 100644 --- a/src/mutex/PgAdvisoryLockMutex.php +++ b/src/mutex/PgAdvisoryLockMutex.php @@ -4,16 +4,15 @@ namespace malkusch\lock\mutex; +use malkusch\lock\util\LockUtil; + class PgAdvisoryLockMutex extends LockMutex { /** @var \PDO */ private $pdo; - /** @var int */ - private $key1; - - /** @var int */ - private $key2; + /** @var array{int, int} */ + private array $key; /** * @throws \RuntimeException @@ -22,12 +21,19 @@ public function __construct(\PDO $PDO, string $name) { $this->pdo = $PDO; - $hashed_name = hash('sha256', $name, true); + [$keyBytes1, $keyBytes2] = str_split(md5(LockUtil::getInstance()->getKeyPrefix() . ':' . $name, true), 4); + + // https://github.com/php/php-src/issues/17068 + $unpackToSignedIntLeFx = static function (string $v) { + $unpacked = unpack('va/Cb/cc', $v); - [$bytes1, $bytes2] = str_split($hashed_name, 4); + return $unpacked['a'] | ($unpacked['b'] << 16) | ($unpacked['c'] << 24); + }; - $this->key1 = unpack('i', $bytes1)[1]; - $this->key2 = unpack('i', $bytes2)[1]; + $this->key = [ + $unpackToSignedIntLeFx($keyBytes1), + $unpackToSignedIntLeFx($keyBytes2), + ]; } #[\Override] @@ -35,19 +41,13 @@ protected function lock(): void { $statement = $this->pdo->prepare('SELECT pg_advisory_lock(?, ?)'); - $statement->execute([ - $this->key1, - $this->key2, - ]); + $statement->execute($this->key); } #[\Override] protected function unlock(): void { $statement = $this->pdo->prepare('SELECT pg_advisory_unlock(?, ?)'); - $statement->execute([ - $this->key1, - $this->key2, - ]); + $statement->execute($this->key); } } diff --git a/tests/mutex/PgAdvisoryLockMutexTest.php b/tests/mutex/PgAdvisoryLockMutexTest.php index ba933b20..80ed20c1 100644 --- a/tests/mutex/PgAdvisoryLockMutexTest.php +++ b/tests/mutex/PgAdvisoryLockMutexTest.php @@ -24,7 +24,7 @@ protected function setUp(): void $this->pdo = $this->createMock(\PDO::class); - $this->mutex = new PgAdvisoryLockMutex($this->pdo, 'test'); + $this->mutex = new PgAdvisoryLockMutex($this->pdo, 'test-one-negative-key'); } private function isPhpunit9x(): bool @@ -52,11 +52,14 @@ public function testAcquireLock(): void } foreach ($arguments as $v) { + self::assertLessThan(1 << 32, $v); + self::assertGreaterThanOrEqual(-(1 << 32), $v); self::assertIsInt($v); } return true; - }) + }), + [533558444, -1716795572] )); \Closure::bind(static fn ($mutex) => $mutex->lock(), null, PgAdvisoryLockMutex::class)($this->mutex); @@ -83,12 +86,13 @@ public function testReleaseLock(): void foreach ($arguments as $v) { self::assertLessThan(1 << 32, $v); - self::assertGreaterThan(-(1 << 32), $v); + self::assertGreaterThanOrEqual(-(1 << 32), $v); self::assertIsInt($v); } return true; - }) + }), + [533558444, -1716795572] )); \Closure::bind(static fn ($mutex) => $mutex->unlock(), null, PgAdvisoryLockMutex::class)($this->mutex);