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