]> git.mxchange.org Git - friendica.git/blob - src/Core/Cache/RedisCacheDriver.php
Merge pull request #7255 from annando/issue-7223
[friendica.git] / src / Core / Cache / RedisCacheDriver.php
1 <?php
2
3 namespace Friendica\Core\Cache;
4
5 use Exception;
6 use Friendica\Core\Cache;
7 use Redis;
8
9 /**
10  * Redis Cache Driver. This driver is based on Memcache driver
11  *
12  * @author Hypolite Petovan <hypolite@mrpetovan.com>
13  * @author Roland Haeder <roland@mxchange.org>
14  */
15 class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
16 {
17         /**
18          * @var Redis
19          */
20         private $redis;
21
22         /**
23          * @param string  $redis_host
24          * @param int     $redis_port
25          * @param int     $redis_db (Default = 0, maximum is 15)
26          * @param string? $redis_pw
27          * @throws Exception
28          */
29         public function __construct($redis_host, $redis_port, $redis_db = 0, $redis_pw = null)
30         {
31                 if (!class_exists('Redis', false)) {
32                         throw new Exception('Redis class isn\'t available');
33                 }
34
35                 $this->redis = new Redis();
36
37                 if (!$this->redis->connect($redis_host, $redis_port)) {
38                         throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
39                 }
40
41                 if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
42                         throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
43                 }
44
45                 if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
46                         throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
47                 }
48         }
49
50         /**
51          * (@inheritdoc)
52          */
53         public function getAllKeys($prefix = null)
54         {
55                 if (empty($prefix)) {
56                         $search = '*';
57                 } else {
58                         $search = $prefix . '*';
59                 }
60
61                 $list = $this->redis->keys($this->getCacheKey($search));
62
63                 return $this->getOriginalKeys($list);
64         }
65
66         /**
67          * (@inheritdoc)
68          */
69         public function get($key)
70         {
71                 $return = null;
72                 $cachekey = $this->getCacheKey($key);
73
74                 $cached = $this->redis->get($cachekey);
75                 if ($cached === false && !$this->redis->exists($cachekey)) {
76                         return null;
77                 }
78
79                 $value = unserialize($cached);
80
81                 // Only return a value if the serialized value is valid.
82                 // We also check if the db entry is a serialized
83                 // boolean 'false' value (which we want to return).
84                 if ($cached === serialize(false) || $value !== false) {
85                         $return = $value;
86                 }
87
88                 return $return;
89         }
90
91         /**
92          * (@inheritdoc)
93          */
94         public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
95         {
96                 $cachekey = $this->getCacheKey($key);
97
98                 $cached = serialize($value);
99
100                 if ($ttl > 0) {
101                         return $this->redis->setex(
102                                 $cachekey,
103                                 $ttl,
104                                 $cached
105                         );
106                 } else {
107                         return $this->redis->set(
108                                 $cachekey,
109                                 $cached
110                         );
111                 }
112         }
113
114         /**
115          * (@inheritdoc)
116          */
117         public function delete($key)
118         {
119                 $cachekey = $this->getCacheKey($key);
120                 return ($this->redis->delete($cachekey) > 0);
121         }
122
123         /**
124          * (@inheritdoc)
125          */
126         public function clear($outdated = true)
127         {
128                 if ($outdated) {
129                         return true;
130                 } else {
131                         return $this->redis->flushAll();
132                 }
133         }
134
135         /**
136          * (@inheritdoc)
137          */
138         public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
139         {
140                 $cachekey = $this->getCacheKey($key);
141                 $cached = serialize($value);
142
143                 return $this->redis->setnx($cachekey, $cached);
144         }
145
146         /**
147          * (@inheritdoc)
148          */
149         public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
150         {
151                 $cachekey = $this->getCacheKey($key);
152
153                 $newCached = serialize($newValue);
154
155                 $this->redis->watch($cachekey);
156                 // If the old value isn't what we expected, somebody else changed the key meanwhile
157                 if ($this->get($key) === $oldValue) {
158                         if ($ttl > 0) {
159                                 $result = $this->redis->multi()
160                                         ->setex($cachekey, $ttl, $newCached)
161                                         ->exec();
162                         } else {
163                                 $result = $this->redis->multi()
164                                         ->set($cachekey, $newCached)
165                                         ->exec();
166                         }
167                         return $result !== false;
168                 }
169                 $this->redis->unwatch();
170                 return false;
171         }
172
173         /**
174          * (@inheritdoc)
175          */
176         public function compareDelete($key, $value)
177         {
178                 $cachekey = $this->getCacheKey($key);
179
180                 $this->redis->watch($cachekey);
181                 // If the old value isn't what we expected, somebody else changed the key meanwhile
182                 if ($this->get($key) === $value) {
183                         $result = $this->redis->multi()
184                                 ->del($cachekey)
185                                 ->exec();
186                         return $result !== false;
187                 }
188                 $this->redis->unwatch();
189                 return false;
190         }
191 }