Add Drone CI
[friendica.git/.git] / src / Core / Cache / MemcacheCache.php
1 <?php
2
3 namespace Friendica\Core\Cache;
4
5 use Exception;
6 use Friendica\Core\Config\Configuration;
7 use Memcache;
8
9 /**
10  * Memcache Cache
11  *
12  * @author Hypolite Petovan <hypolite@mrpetovan.com>
13  */
14 class MemcacheCache extends Cache implements IMemoryCache
15 {
16         use TraitCompareSet;
17         use TraitCompareDelete;
18
19         /**
20          * @var Memcache
21          */
22         private $memcache;
23
24         /**
25          * @throws Exception
26          */
27         public function __construct(string $hostname, Configuration $config)
28         {
29                 if (!class_exists('Memcache', false)) {
30                         throw new Exception('Memcache class isn\'t available');
31                 }
32
33                 parent::__construct($hostname);
34
35                 $this->memcache = new Memcache();
36
37                 $memcache_host = $config->get('system', 'memcache_host');
38                 $memcache_port = $config->get('system', 'memcache_port');
39
40                 if (!@$this->memcache->connect($memcache_host, $memcache_port)) {
41                         throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
42                 }
43         }
44
45         /**
46          * (@inheritdoc)
47          */
48         public function getAllKeys($prefix = null)
49         {
50                 $keys     = [];
51                 $allSlabs = $this->memcache->getExtendedStats('slabs');
52                 foreach ($allSlabs as $slabs) {
53                         foreach (array_keys($slabs) as $slabId) {
54                                 $cachedump = $this->memcache->getExtendedStats('cachedump', (int)$slabId);
55                                 foreach ($cachedump as $key => $arrVal) {
56                                         if (!is_array($arrVal)) {
57                                                 continue;
58                                         }
59                                         $keys = array_merge($keys, array_keys($arrVal));
60                                 }
61                         }
62                 }
63
64                 $keys = $this->getOriginalKeys($keys);
65
66                 return $this->filterArrayKeysByPrefix($keys, $prefix);
67         }
68
69         /**
70          * (@inheritdoc)
71          */
72         public function get($key)
73         {
74                 $return   = null;
75                 $cachekey = $this->getCacheKey($key);
76
77                 // We fetch with the hostname as key to avoid problems with other applications
78                 $cached = $this->memcache->get($cachekey);
79
80                 // @see http://php.net/manual/en/memcache.get.php#84275
81                 if (is_bool($cached) || is_double($cached) || is_long($cached)) {
82                         return $return;
83                 }
84
85                 $value = @unserialize($cached);
86
87                 // Only return a value if the serialized value is valid.
88                 // We also check if the db entry is a serialized
89                 // boolean 'false' value (which we want to return).
90                 if ($cached === serialize(false) || $value !== false) {
91                         $return = $value;
92                 }
93
94                 return $return;
95         }
96
97         /**
98          * (@inheritdoc)
99          */
100         public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
101         {
102                 $cachekey = $this->getCacheKey($key);
103
104                 // We store with the hostname as key to avoid problems with other applications
105                 if ($ttl > 0) {
106                         return $this->memcache->set(
107                                 $cachekey,
108                                 serialize($value),
109                                 MEMCACHE_COMPRESSED,
110                                 time() + $ttl
111                         );
112                 } else {
113                         return $this->memcache->set(
114                                 $cachekey,
115                                 serialize($value),
116                                 MEMCACHE_COMPRESSED
117                         );
118                 }
119         }
120
121         /**
122          * (@inheritdoc)
123          */
124         public function delete($key)
125         {
126                 $cachekey = $this->getCacheKey($key);
127                 return $this->memcache->delete($cachekey);
128         }
129
130         /**
131          * (@inheritdoc)
132          */
133         public function clear($outdated = true)
134         {
135                 if ($outdated) {
136                         return true;
137                 } else {
138                         return $this->memcache->flush();
139                 }
140         }
141
142         /**
143          * (@inheritdoc)
144          */
145         public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
146         {
147                 $cachekey = $this->getCacheKey($key);
148                 return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
149         }
150
151         /**
152          * {@inheritDoc}
153          */
154         public function getName()
155         {
156                 return self::TYPE_MEMCACHE;
157         }
158 }