3 * @copyright Copyright (C) 2020, Friendica
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Core\Cache;
25 use Friendica\Core\BaseCache;
26 use Friendica\Core\Config\IConfig;
30 * Redis Cache. This driver is based on Memcache driver
32 class RedisCache extends BaseCache implements IMemoryCache
42 public function __construct(string $hostname, IConfig $config)
44 if (!class_exists('Redis', false)) {
45 throw new Exception('Redis class isn\'t available');
48 parent::__construct($hostname);
50 $this->redis = new Redis();
52 $redis_host = $config->get('system', 'redis_host');
53 $redis_port = $config->get('system', 'redis_port');
54 $redis_pw = $config->get('system', 'redis_password');
55 $redis_db = $config->get('system', 'redis_db', 0);
57 if (isset($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) {
58 throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
59 } elseif (!@$this->redis->connect($redis_host)) {
60 throw new Exception('Expected Redis server at ' . $redis_host . ' isn\'t available');
63 if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
64 throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
67 if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
68 throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
75 public function getAllKeys($prefix = null)
80 $search = $prefix . '*';
83 $list = $this->redis->keys($this->getCacheKey($search));
85 return $this->getOriginalKeys($list);
91 public function get($key)
94 $cachekey = $this->getCacheKey($key);
96 $cached = $this->redis->get($cachekey);
97 if ($cached === false && !$this->redis->exists($cachekey)) {
101 $value = unserialize($cached);
103 // Only return a value if the serialized value is valid.
104 // We also check if the db entry is a serialized
105 // boolean 'false' value (which we want to return).
106 if ($cached === serialize(false) || $value !== false) {
116 public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
118 $cachekey = $this->getCacheKey($key);
120 $cached = serialize($value);
123 return $this->redis->setex(
129 return $this->redis->set(
139 public function delete($key)
141 $cachekey = $this->getCacheKey($key);
142 return ($this->redis->del($cachekey) > 0);
148 public function clear($outdated = true)
153 return $this->redis->flushAll();
160 public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
162 $cachekey = $this->getCacheKey($key);
163 $cached = serialize($value);
165 return $this->redis->setnx($cachekey, $cached);
171 public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
173 $cachekey = $this->getCacheKey($key);
175 $newCached = serialize($newValue);
177 $this->redis->watch($cachekey);
178 // If the old value isn't what we expected, somebody else changed the key meanwhile
179 if ($this->get($key) === $oldValue) {
181 $result = $this->redis->multi()
182 ->setex($cachekey, $ttl, $newCached)
185 $result = $this->redis->multi()
186 ->set($cachekey, $newCached)
189 return $result !== false;
191 $this->redis->unwatch();
198 public function compareDelete($key, $value)
200 $cachekey = $this->getCacheKey($key);
202 $this->redis->watch($cachekey);
203 // If the old value isn't what we expected, somebody else changed the key meanwhile
204 if ($this->get($key) === $value) {
205 $result = $this->redis->multi()
208 return $result !== false;
210 $this->redis->unwatch();
217 public function getName()