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

brick / lock / 17010350856

16 Aug 2025 04:00PM UTC coverage: 5.5%. First build
17010350856

push

github

BenMorel
Allow a single lock name in MultiLock

0 of 2 new or added lines in 1 file covered. (0.0%)

11 of 200 relevant lines covered (5.5%)

3.42 hits per line

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

0.0
/src/MultiLock.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Lock;
6

7
use Brick\Lock\Exception\LockAcquireException;
8
use Brick\Lock\Exception\LockReleaseException;
9
use InvalidArgumentException;
10
use Override;
11

12
final readonly class MultiLock extends AbstractLock
13
{
14
    /**
15
     * @var list<string>
16
     */
17
    private array $lockNames;
18

19
    /**
20
     * @param string[] $lockNames
21
     *
22
     * @throws InvalidArgumentException
23
     */
24
    public function __construct(
25
        private LockDriverInterface $store,
26
        array                       $lockNames,
27
    ) {
NEW
28
        if (count($lockNames) === 0) {
×
NEW
29
            throw new InvalidArgumentException('At least one lock name must be provided.');
×
30
        }
31

32
        // sort lock names to minimize deadlock risk
33
        sort($lockNames);
×
34
        $this->lockNames = $lockNames;
×
35
    }
36

37
    #[Override]
38
    public function acquire(): void
39
    {
40
        foreach ($this->lockNames as $lockName) {
×
41
            $this->store->acquire($lockName);
×
42
        }
43
    }
44

45
    #[Override]
46
    public function tryAcquire(): bool
47
    {
48
        $acquiredLockNames = [];
×
49

50
        foreach ($this->lockNames as $lockName) {
×
51
            if ($this->store->tryAcquire($lockName)) {
×
52
                $acquiredLockNames[] = $lockName;
×
53
            } else {
54
                try {
55
                    foreach ($acquiredLockNames as $acquiredLockName) {
×
56
                        $this->store->release($acquiredLockName);
×
57
                    }
58
                } catch (LockReleaseException $e) {
×
59
                    throw LockAcquireException::forMultiLock('Failed to release previously acquired lock', $e);
×
60
                }
61

62
                return false;
×
63
            }
64
        }
65

66
        return true;
×
67
    }
68

69
    #[Override]
70
    public function tryAcquireWithTimeout(int $seconds): bool
71
    {
72
        if ($seconds <= 0) {
×
73
            throw new InvalidArgumentException('Timeout must be a positive integer.');
×
74
        }
75

76
        $acquiredLockNames = [];
×
77
        $startTime = microtime(true);
×
78

79
        foreach ($this->lockNames as $lockName) {
×
80
            $elapsedSeconds = (int) (microtime(true) - $startTime); // rounds down
×
81
            $secondsLeft = max(0, $seconds - $elapsedSeconds); // zero or more
×
82

83
            $lockAcquired = ($secondsLeft === 0)
×
84
                ? $this->store->tryAcquire($lockName)
×
85
                : $this->store->tryAcquireWithTimeout($lockName, $secondsLeft);
×
86

87
            if ($lockAcquired) {
×
88
                $acquiredLockNames[] = $lockName;
×
89
            } else {
90
                try {
91
                    foreach ($acquiredLockNames as $acquiredLockName) {
×
92
                        $this->store->release($acquiredLockName);
×
93
                    }
94
                } catch (LockReleaseException $e) {
×
95
                    throw LockAcquireException::forMultiLock('Failed to release previously acquired lock', $e);
×
96
                }
97

98
                return false;
×
99
            }
100
        }
101

102
        return true;
×
103
    }
104

105
    #[Override]
106
    public function release(): void
107
    {
108
        foreach ($this->lockNames as $lockName) {
×
109
            $this->store->release($lockName);
×
110
        }
111
    }
112
}
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