• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / lock / 17475241346

04 Sep 2025 07:59PM UTC coverage: 5.5%. Remained the same
17475241346

push

github

BenMorel
Apply coding standard

11 of 200 relevant lines covered (5.5%)

3.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Driver/PostgresLockDriver.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Lock\Driver;
6

7
use Brick\Lock\Database\ConnectionInterface;
8
use Brick\Lock\Database\QueryException;
9
use Brick\Lock\Exception\LockAcquireException;
10
use Brick\Lock\Exception\LockReleaseException;
11
use Brick\Lock\Internal\PostgresHasher;
12
use Brick\Lock\LockDriverInterface;
13
use Override;
14

15
use function is_bool;
16
use function microtime;
17
use function sprintf;
18
use function usleep;
19
use function var_export;
20

21
/**
22
 * PostgreSQL driver using pg_advisory_lock().
23
 *
24
 * Postgres does not support lock timeouts, so we use polling to emulate these.
25
 *
26
 * https://www.postgresql.org/docs/17/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
27
 */
28
final readonly class PostgresLockDriver implements LockDriverInterface
29
{
30
    /**
31
     * @param int $pollIntervalMs The interval in milliseconds between each poll when using tryAcquireWithTimeout().
32
     *                            Must be positive.
33
     */
34
    public function __construct(
35
        private ConnectionInterface $connection,
36
        private int $pollIntervalMs = 100,
37
    ) {
38
    }
×
39

40
    #[Override]
41
    public function acquire(string $lockName): void
42
    {
43
        try {
44
            $this->connection->querySingleValue('SELECT pg_advisory_lock(?, ?)', PostgresHasher::hashLockName($lockName));
×
45
        } catch (QueryException $e) {
×
46
            throw LockAcquireException::forLockName($lockName, 'Error while calling pg_advisory_lock()', $e);
×
47
        }
48
    }
49

50
    #[Override]
51
    public function tryAcquire(string $lockName): bool
52
    {
53
        return $this->doTryAcquire($lockName, PostgresHasher::hashLockName($lockName));
×
54
    }
55

56
    #[Override]
57
    public function tryAcquireWithTimeout(string $lockName, int $timeoutSeconds): bool
58
    {
59
        $startTime = microtime(true);
×
60
        $lockHash = PostgresHasher::hashLockName($lockName);
×
61

62
        while (true) {
×
63
            $result = $this->doTryAcquire($lockName, $lockHash);
×
64

65
            if ($result === true) {
×
66
                return true;
×
67
            }
68

69
            if (microtime(true) - $startTime >= $timeoutSeconds) {
×
70
                return false;
×
71
            }
72

73
            usleep($this->pollIntervalMs * 1000);
×
74
        }
75
    }
76

77
    #[Override]
78
    public function release(string $lockName): void
79
    {
80
        try {
81
            $result = $this->connection->querySingleValue('SELECT pg_advisory_unlock(?, ?)', PostgresHasher::hashLockName($lockName));
×
82
        } catch (QueryException $e) {
×
83
            throw LockReleaseException::forLockName($lockName, 'Error while calling pg_advisory_unlock()', $e);
×
84
        }
85

86
        if ($result === true) {
×
87
            return;
×
88
        }
89

90
        if ($result === false) {
×
91
            throw LockReleaseException::forLockName($lockName, 'The lock was not acquired.');
×
92
        }
93

94
        throw LockReleaseException::forLockName($lockName, sprintf(
×
95
            'Unexpected result from pg_advisory_unlock(): %s',
×
96
            var_export($result, true),
×
97
        ));
×
98
    }
99

100
    /**
101
     * @param array{int, int} $lockHash
102
     *
103
     * @throws LockAcquireException
104
     */
105
    private function doTryAcquire(string $lockName, array $lockHash): bool
106
    {
107
        try {
108
            $result = $this->connection->querySingleValue('SELECT pg_try_advisory_lock(?, ?)', $lockHash);
×
109
        } catch (QueryException $e) {
×
110
            throw LockAcquireException::forLockName($lockName, 'Error while calling pg_try_advisory_lock()', $e);
×
111
        }
112

113
        if (is_bool($result)) {
×
114
            return $result;
×
115
        }
116

117
        throw LockAcquireException::forLockName($lockName, sprintf(
×
118
            'Unexpected result from pg_try_advisory_lock(): %s',
×
119
            var_export($result, true),
×
120
        ));
×
121
    }
122
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc