Skip to content

Commit eca5e37

Browse files
committed
#36337: Respect serialization and compression of phpredis during locking
- Support phpredis serialization when locking (none, php, json, igbinary, msgpack). - Support phpredis compression when locking (none, lzf, zstd, lz4).
1 parent b69db31 commit eca5e37

File tree

2 files changed

+415
-1
lines changed

2 files changed

+415
-1
lines changed

src/Illuminate/Cache/RedisLock.php

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Illuminate\Cache;
44

5+
use UnexpectedValueException;
6+
57
class RedisLock extends Lock
68
{
79
/**
@@ -48,7 +50,42 @@ public function acquire()
4850
*/
4951
public function release()
5052
{
51-
return (bool) $this->redis->eval(LuaScripts::releaseLock(), 1, $this->name, $this->owner);
53+
$owner = $this->owner;
54+
55+
/* If a serialization mode such as "php" or "igbinary" and/or a
56+
* compression mode such as "lzf" or "zstd" is enabled, the owner
57+
* must be serialized and/or compressed by us, because phpredis does
58+
* not do this for the eval command.
59+
*
60+
* Name must not be modified!
61+
*/
62+
if ($this->isPhpRedis()) {
63+
$owner = $this->redis->client()->_serialize($owner);
64+
65+
// Check first whether enabled at all before checking each as most likely it is not used.
66+
if ($this->isPhpRedisCompressionEnabled()) {
67+
if ($this->isPhpRedisLzfEnabled()) {
68+
$owner = \lzf_compress($owner);
69+
} elseif ($this->isPhpRedisZstdEnabled()) {
70+
$owner = \zstd_compress(
71+
$owner,
72+
$this->redis->client()->getOption(constant('Redis::OPT_COMPRESSION_LEVEL'))
73+
);
74+
} elseif ($this->isPhpRedisLz4Enabled()) {
75+
$owner = \lz4_compress(
76+
$owner,
77+
$this->redis->client()->getOption(constant('Redis::OPT_COMPRESSION_LEVEL'))
78+
);
79+
} else {
80+
throw new UnexpectedValueException(sprintf(
81+
'Unknown phpredis compression in use (%d). Unable to release lock.',
82+
$this->redis->client()->getOption(constant('Redis::OPT_COMPRESSION'))
83+
));
84+
}
85+
}
86+
}
87+
88+
return (bool) $this->redis->eval(LuaScripts::releaseLock(), 1, $this->name, $owner);
5289
}
5390

5491
/**
@@ -80,4 +117,104 @@ public function getConnectionName()
80117
{
81118
return $this->redis->getName();
82119
}
120+
121+
/**
122+
* Determines whether compression is enabled for the phpredis connection.
123+
*
124+
* @return bool
125+
*/
126+
private function isPhpRedisCompressionEnabled()
127+
{
128+
$compressionOpt = constant('Redis::OPT_COMPRESSION');
129+
$compressionNone = constant('Redis::COMPRESSION_NONE');
130+
131+
if ($this->redis->client()->getOption($compressionOpt) === $compressionNone) {
132+
return false;
133+
}
134+
135+
return true;
136+
}
137+
138+
/**
139+
* Determines whether lzf compression is enabled for the phpredis connection.
140+
*
141+
* @return bool
142+
*/
143+
private function isPhpRedisLzfEnabled()
144+
{
145+
$lzfConst = 'Redis::COMPRESSION_LZF';
146+
if (! defined($lzfConst)) {
147+
return false;
148+
}
149+
150+
$lzfCompression = constant($lzfConst);
151+
$compressionOpt = constant('Redis::OPT_COMPRESSION');
152+
153+
if ($this->redis->client()->getOption($compressionOpt) === $lzfCompression) {
154+
return true;
155+
}
156+
157+
return false;
158+
}
159+
160+
/**
161+
* Determines whether zstd compression is enabled for the phpredis connection.
162+
*
163+
* @return bool
164+
*/
165+
private function isPhpRedisZstdEnabled()
166+
{
167+
$zstdConst = 'Redis::COMPRESSION_ZSTD';
168+
if (! defined($zstdConst)) {
169+
return false;
170+
}
171+
172+
$zstdCompression = constant($zstdConst);
173+
$compressionOpt = constant('Redis::OPT_COMPRESSION');
174+
175+
if ($this->redis->client()->getOption($compressionOpt) === $zstdCompression) {
176+
return true;
177+
}
178+
179+
return false;
180+
}
181+
182+
/**
183+
* Determines whether lz4 compression is enabled for the phpredis connection.
184+
*
185+
* @return bool
186+
*/
187+
private function isPhpRedisLz4Enabled()
188+
{
189+
$lz4Const = 'Redis::COMPRESSION_LZ4';
190+
if (! defined($lz4Const)) {
191+
return false;
192+
}
193+
194+
$lz4Compression = constant($lz4Const);
195+
$compressionOpt = constant('Redis::OPT_COMPRESSION');
196+
197+
if ($this->redis->client()->getOption($compressionOpt) === $lz4Compression) {
198+
return true;
199+
}
200+
201+
return false;
202+
}
203+
204+
/**
205+
* Determines whether the client used to connect to redis is one from the
206+
* phpredis extension.
207+
*
208+
* @return bool
209+
*/
210+
private function isPhpRedis()
211+
{
212+
$client = $this->redis->client();
213+
$clientClass = get_class($client);
214+
if ($clientClass === 'Redis' || $clientClass === 'RedisCluster') {
215+
return true;
216+
}
217+
218+
return false;
219+
}
83220
}

0 commit comments

Comments
 (0)