11
11
12
12
namespace Symfony \Component \Cache \Adapter ;
13
13
14
+ use Symfony \Component \Cache \Exception \InvalidArgumentException ;
15
+
14
16
/**
15
17
* @author Aurimas Niekis <[email protected] >
16
18
*/
17
19
class RedisAdapter extends AbstractAdapter
18
20
{
19
- /**
20
- * @var \Redis
21
- */
22
21
private $ redis ;
23
22
24
- /**
25
- * @param \Redis $redisConnection
26
- * @param string $namespace
27
- * @param int $defaultLifetime
28
- */
29
23
public function __construct (\Redis $ redisConnection , $ namespace = '' , $ defaultLifetime = 0 )
30
24
{
31
25
$ this ->redis = $ redisConnection ;
32
26
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
+
33
31
parent ::__construct ($ namespace , $ defaultLifetime );
34
32
}
35
33
@@ -39,18 +37,13 @@ public function __construct(\Redis $redisConnection, $namespace = '', $defaultLi
39
37
protected function doFetch (array $ ids )
40
38
{
41
39
$ values = $ this ->redis ->mget ($ ids );
42
-
43
40
$ index = 0 ;
44
41
$ result = [];
45
42
46
43
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 );
51
46
}
52
-
53
- $ result [$ id ] = unserialize ($ value );
54
47
}
55
48
56
49
return $ result ;
@@ -67,9 +60,19 @@ protected function doHave($id)
67
60
/**
68
61
* {@inheritdoc}
69
62
*/
70
- protected function doClear ()
63
+ protected function doClear ($ namespace )
71
64
{
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 ;
73
76
}
74
77
75
78
/**
@@ -87,21 +90,26 @@ protected function doDelete(array $ids)
87
90
*/
88
91
protected function doSave (array $ values , $ lifetime )
89
92
{
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 ;
98
100
}
101
+ }
102
+
103
+ if (!$ this ->redis ->mSet ($ values )) {
104
+ return false ;
105
+ }
99
106
100
- if (false === $ response ) {
101
- $ failed [] = $ key ;
107
+ if ($ lifetime >= 1 ) {
108
+ foreach ($ values as $ id => $ v ) {
109
+ $ this ->redis ->expire ($ id , $ lifetime );
102
110
}
103
111
}
104
112
105
- return count ( $ failed) > 0 ? $ failed : true ;
113
+ return $ failed ;
106
114
}
107
115
}
0 commit comments