Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 66b84b2

Browse files
feature #19524 [Cache] Add generic TagAwareAdapter wrapper (replaces TagAwareRedisAdapter) (nicolas-grekas)
This PR was merged into the 3.2-dev branch. Discussion ---------- [Cache] Add generic TagAwareAdapter wrapper (replaces TagAwareRedisAdapter) | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | symfony/symfony-docs#6858 This PR replaces TagAwareRedisAdapter introduced in #19047 by a generic `TagAwareAdapter` that works with any two adapters. Commits ------- 288308b [Cache] Add generic TagAwareAdapter wrapper (replaces TagAwareRedisAdapter)
2 parents 673cec7 + 288308b commit 66b84b2

9 files changed

+448
-565
lines changed

src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php

Lines changed: 0 additions & 217 deletions
This file was deleted.

src/Symfony/Component/Cache/Adapter/RedisAdapter.php

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Predis\Connection\Factory;
15+
use Predis\Connection\Aggregate\PredisCluster;
16+
use Predis\Connection\Aggregate\RedisCluster;
1517
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1618

1719
/**
@@ -20,23 +22,29 @@
2022
*/
2123
class RedisAdapter extends AbstractAdapter
2224
{
23-
use RedisAdapterTrait;
24-
2525
private static $defaultConnectionOptions = array(
2626
'class' => null,
2727
'persistent' => 0,
2828
'timeout' => 0,
2929
'read_timeout' => 0,
3030
'retry_interval' => 0,
3131
);
32+
private $redis;
3233

3334
/**
3435
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
3536
*/
3637
public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
3738
{
3839
parent::__construct($namespace, $defaultLifetime);
39-
$this->setRedis($redisClient, $namespace);
40+
41+
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
42+
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
43+
}
44+
if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client) {
45+
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient)));
46+
}
47+
$this->redis = $redisClient;
4048
}
4149

4250
/**
@@ -149,6 +157,71 @@ protected function doHave($id)
149157
return (bool) $this->redis->exists($id);
150158
}
151159

160+
/**
161+
* {@inheritdoc}
162+
*/
163+
protected function doClear($namespace)
164+
{
165+
// When using a native Redis cluster, clearing the cache cannot work and always returns false.
166+
// Clearing the cache should then be done by any other means (e.g. by restarting the cluster).
167+
168+
$cleared = true;
169+
$hosts = array($this->redis);
170+
$evalArgs = array(array($namespace), 0);
171+
172+
if ($this->redis instanceof \Predis\Client) {
173+
$evalArgs = array(0, $namespace);
174+
175+
$connection = $this->redis->getConnection();
176+
if ($connection instanceof PredisCluster) {
177+
$hosts = array();
178+
foreach ($connection as $c) {
179+
$hosts[] = new \Predis\Client($c);
180+
}
181+
} elseif ($connection instanceof RedisCluster) {
182+
return false;
183+
}
184+
} elseif ($this->redis instanceof \RedisArray) {
185+
$hosts = array();
186+
foreach ($this->redis->_hosts() as $host) {
187+
$hosts[] = $this->redis->_instance($host);
188+
}
189+
} elseif ($this->redis instanceof \RedisCluster) {
190+
return false;
191+
}
192+
foreach ($hosts as $host) {
193+
if (!isset($namespace[0])) {
194+
$cleared = $host->flushDb() && $cleared;
195+
continue;
196+
}
197+
198+
$info = $host->info('Server');
199+
$info = isset($info['Server']) ? $info['Server'] : $info;
200+
201+
if (!version_compare($info['redis_version'], '2.8', '>=')) {
202+
// As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
203+
// can hang your server when it is executed against large databases (millions of items).
204+
// Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above.
205+
$cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $evalArgs[0], $evalArgs[1]) && $cleared;
206+
continue;
207+
}
208+
209+
$cursor = null;
210+
do {
211+
$keys = $host instanceof \Predis\Client ? $host->scan($cursor, 'MATCH', $namespace.'*', 'COUNT', 1000) : $host->scan($cursor, $namespace.'*', 1000);
212+
if (isset($keys[1]) && is_array($keys[1])) {
213+
$cursor = $keys[0];
214+
$keys = $keys[1];
215+
}
216+
if ($keys) {
217+
$host->del($keys);
218+
}
219+
} while ($cursor = (int) $cursor);
220+
}
221+
222+
return $cleared;
223+
}
224+
152225
/**
153226
* {@inheritdoc}
154227
*/
@@ -195,4 +268,47 @@ protected function doSave(array $values, $lifetime)
195268

196269
return $failed;
197270
}
271+
272+
private function execute($command, $id, array $args, $redis = null)
273+
{
274+
array_unshift($args, $id);
275+
call_user_func_array(array($redis ?: $this->redis, $command), $args);
276+
}
277+
278+
private function pipeline(\Closure $callback)
279+
{
280+
$redis = $this->redis;
281+
282+
try {
283+
if ($redis instanceof \Predis\Client) {
284+
$redis->pipeline(function ($pipe) use ($callback) {
285+
$this->redis = $pipe;
286+
$callback(array($this, 'execute'));
287+
});
288+
} elseif ($redis instanceof \RedisArray) {
289+
$connections = array();
290+
$callback(function ($command, $id, $args) use (&$connections) {
291+
if (!isset($connections[$h = $this->redis->_target($id)])) {
292+
$connections[$h] = $this->redis->_instance($h);
293+
$connections[$h]->multi(\Redis::PIPELINE);
294+
}
295+
$this->execute($command, $id, $args, $connections[$h]);
296+
});
297+
foreach ($connections as $c) {
298+
$c->exec();
299+
}
300+
} else {
301+
$pipe = $redis->multi(\Redis::PIPELINE);
302+
try {
303+
$callback(array($this, 'execute'));
304+
} finally {
305+
if ($pipe) {
306+
$redis->exec();
307+
}
308+
}
309+
}
310+
} finally {
311+
$this->redis = $redis;
312+
}
313+
}
198314
}

0 commit comments

Comments
 (0)