fff079e7823115724713dc2e4c98f12916aee8e5
[friendica.git/.git] / src / Core / Cache / RedisCacheDriver.php
1 <?php
2
3 namespace Friendica\Core\Cache;
4
5 use Friendica\Core\Cache;
6
7 use Exception;
8 use Redis;
9
10 /**
11  * Redis Cache Driver. This driver is based on Memcache driver
12  *
13  * @author Hypolite Petovan <mrpetovan@gmail.com>
14  * @author Roland Haeder <roland@mxchange.org>
15  */
16 class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
17 {
18         /**
19          * @var Redis
20          */
21         private $redis;
22
23         public function __construct($redis_host, $redis_port)
24         {
25                 if (!class_exists('Redis', false)) {
26                         throw new Exception('Redis class isn\'t available');
27                 }
28
29                 $this->redis = new Redis();
30
31                 if (!$this->redis->connect($redis_host, $redis_port)) {
32                         throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
33                 }
34         }
35
36         public function get($key)
37         {
38                 $return = null;
39                 $cachekey = $this->getCacheKey($key);
40
41                 $cached = $this->redis->get($cachekey);
42                 if ($cached === false && !$this->redis->exists($cachekey)) {
43                         return null;
44                 }
45
46                 $value = unserialize($cached);
47
48                 // Only return a value if the serialized value is valid.
49                 // We also check if the db entry is a serialized
50                 // boolean 'false' value (which we want to return).
51                 if ($cached === serialize(false) || $value !== false) {
52                         $return = $value;
53                 }
54
55                 return $return;
56         }
57
58         public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
59         {
60                 $cachekey = $this->getCacheKey($key);
61
62                 $cached = serialize($value);
63
64                 if ($ttl > 0) {
65                         return $this->redis->setex(
66                                 $cachekey,
67                                 $ttl,
68                                 $cached
69                         );
70                 } else {
71                         return $this->redis->set(
72                                 $cachekey,
73                                 $cached
74                         );
75                 }
76         }
77
78         public function delete($key)
79         {
80                 $cachekey = $this->getCacheKey($key);
81                 return ($this->redis->delete($cachekey) > 0);
82         }
83
84         public function clear($outdated = true)
85         {
86                 if ($outdated) {
87                         return true;
88                 } else {
89                         return $this->redis->flushAll();
90                 }
91         }
92
93         /**
94          * (@inheritdoc)
95          */
96         public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
97         {
98                 $cachekey = $this->getCacheKey($key);
99                 $cached = serialize($value);
100
101                 return $this->redis->setnx($cachekey, $cached);
102         }
103
104         /**
105          * (@inheritdoc)
106          */
107         public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
108         {
109                 $cachekey = $this->getCacheKey($key);
110
111                 $newCached = serialize($newValue);
112
113                 $this->redis->watch($cachekey);
114                 // If the old value isn't what we expected, somebody else changed the key meanwhile
115                 if ($this->get($key) === $oldValue) {
116                         if ($ttl > 0) {
117                                 $result = $this->redis->multi()
118                                         ->setex($cachekey, $ttl, $newCached)
119                                         ->exec();
120                         } else {
121                                 $result = $this->redis->multi()
122                                         ->set($cachekey, $newValue)
123                                         ->exec();
124                         }
125                         return $result !== false;
126                 }
127                 $this->redis->unwatch();
128                 return false;
129         }
130         /**
131          * (@inheritdoc)
132          */
133         public function compareDelete($key, $value)
134         {
135                 $cachekey = $this->getCacheKey($key);
136
137                 $this->redis->watch($cachekey);
138                 // If the old value isn't what we expected, somebody else changed the key meanwhile
139                 if ($this->get($key) === $value) {
140                         $result = $this->redis->multi()
141                                 ->del($cachekey)
142                                 ->exec();
143                         return $result !== false;
144                 }
145                 $this->redis->unwatch();
146                 return false;
147         }
148 }