1111
1212namespace Symfony \Component \Cache \Adapter ;
1313
14+ use Symfony \Component \Cache \Exception \InvalidArgumentException ;
15+
1416/**
1517 * @author Aurimas Niekis <[email protected] > 1618 */
1719class RedisAdapter extends AbstractAdapter
1820{
19- /**
20- * @var \Redis
21- */
2221 private $ redis ;
2322
24- /**
25- * @param \Redis $redisConnection
26- * @param string $namespace
27- * @param int $defaultLifetime
28- */
2923 public function __construct (\Redis $ redisConnection , $ namespace = '' , $ defaultLifetime = 0 )
3024 {
3125 $ this ->redis = $ redisConnection ;
3226
27+ if (preg_match ('#[^-+_.A-Za-z0-9]# ' , $ namespace , $ match )) {
28+ throw new InvalidArgumentException (sprintf ('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed. ' , $ match [0 ]));
29+ }
30+
3331 parent ::__construct ($ namespace , $ defaultLifetime );
3432 }
3533
@@ -39,18 +37,13 @@ public function __construct(\Redis $redisConnection, $namespace = '', $defaultLi
3937 protected function doFetch (array $ ids )
4038 {
4139 $ values = $ this ->redis ->mget ($ ids );
42-
4340 $ index = 0 ;
4441 $ result = [];
4542
4643 foreach ($ ids as $ id ) {
47- $ value = $ values [$ index ++];
48-
49- if (false === $ value ) {
50- continue ;
44+ if (false !== $ value = $ values [$ index ++]) {
45+ $ result [$ id ] = unserialize ($ value );
5146 }
52-
53- $ result [$ id ] = unserialize ($ value );
5447 }
5548
5649 return $ result ;
@@ -67,9 +60,19 @@ protected function doHave($id)
6760 /**
6861 * {@inheritdoc}
6962 */
70- protected function doClear ()
63+ protected function doClear ($ namespace )
7164 {
72- return $ this ->redis ->flushDB ();
65+ if (!isset ($ namespace [0 ])) {
66+ $ this ->redis ->flushDB ();
67+ } else {
68+ // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
69+ // can hang your server when it is executed against large databases (millions of items).
70+ // Whenever you hit this scale, it is advised to deploy one Redis instance per cache pool
71+ // instead of using namespaces, so that the above FLUSHDB is used instead.
72+ $ this ->redis ->eval (sprintf ("for _,k in ipairs(redis.call('KEYS','%s*')) do redis.call('DEL',k) end " , $ namespace ));
73+ }
74+
75+ return true ;
7376 }
7477
7578 /**
@@ -87,21 +90,26 @@ protected function doDelete(array $ids)
8790 */
8891 protected function doSave (array $ values , $ lifetime )
8992 {
90- $ failed = [];
91- foreach ($ values as $ key => $ value ) {
92- $ value = serialize ($ value );
93-
94- if ($ lifetime < 1 ) {
95- $ response = $ this ->redis ->set ($ key , $ value );
96- } else {
97- $ response = $ this ->redis ->setex ($ key , $ lifetime , $ value );
93+ $ failed = array ();
94+
95+ foreach ($ values as $ id => $ v ) {
96+ try {
97+ $ values [$ id ] = serialize ($ v );
98+ } catch (\Exception $ e ) {
99+ $ failed [] = $ id ;
98100 }
101+ }
102+
103+ if (!$ this ->redis ->mSet ($ values )) {
104+ return false ;
105+ }
99106
100- if (false === $ response ) {
101- $ failed [] = $ key ;
107+ if ($ lifetime >= 1 ) {
108+ foreach ($ values as $ id => $ v ) {
109+ $ this ->redis ->expire ($ id , $ lifetime );
102110 }
103111 }
104112
105- return count ( $ failed) > 0 ? $ failed : true ;
113+ return $ failed ;
106114 }
107115}
0 commit comments