3 * @copyright Copyright (C) 2010-2021, the Friendica project
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 $this->redis->del($cachekey);
143 // Redis doesn't have an error state for del()
150 public function clear($outdated = true)
155 return $this->redis->flushAll();
162 public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
164 $cachekey = $this->getCacheKey($key);
165 $cached = serialize($value);
167 return $this->redis->setnx($cachekey, $cached);
173 public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
175 $cachekey = $this->getCacheKey($key);
177 $newCached = serialize($newValue);
179 $this->redis->watch($cachekey);
180 // If the old value isn't what we expected, somebody else changed the key meanwhile
181 if ($this->get($key) === $oldValue) {
183 $result = $this->redis->multi()
184 ->setex($cachekey, $ttl, $newCached)
187 $result = $this->redis->multi()
188 ->set($cachekey, $newCached)
191 return $result !== false;
193 $this->redis->unwatch();
200 public function compareDelete($key, $value)
202 $cachekey = $this->getCacheKey($key);
204 $this->redis->watch($cachekey);
205 // If the old value isn't what we expected, somebody else changed the key meanwhile
206 if ($this->get($key) === $value) {
207 $result = $this->redis->multi()
210 return $result !== false;
212 $this->redis->unwatch();
219 public function getName()