Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Cache/ApcuBackend.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Core\Cache; | |
4 | |
5 /** | |
6 * Stores cache items in the Alternative PHP Cache User Cache (APCu). | |
7 */ | |
8 class ApcuBackend implements CacheBackendInterface { | |
9 | |
10 /** | |
11 * The name of the cache bin to use. | |
12 * | |
13 * @var string | |
14 */ | |
15 protected $bin; | |
16 | |
17 /** | |
18 * Prefix for all keys in the storage that belong to this site. | |
19 * | |
20 * @var string | |
21 */ | |
22 protected $sitePrefix; | |
23 | |
24 /** | |
25 * Prefix for all keys in this cache bin. | |
26 * | |
27 * Includes the site-specific prefix in $sitePrefix. | |
28 * | |
29 * @var string | |
30 */ | |
31 protected $binPrefix; | |
32 | |
33 /** | |
34 * The cache tags checksum provider. | |
35 * | |
36 * @var \Drupal\Core\Cache\CacheTagsChecksumInterface | |
37 */ | |
38 protected $checksumProvider; | |
39 | |
40 /** | |
41 * Constructs a new ApcuBackend instance. | |
42 * | |
43 * @param string $bin | |
44 * The name of the cache bin. | |
45 * @param string $site_prefix | |
46 * The prefix to use for all keys in the storage that belong to this site. | |
47 * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider | |
48 * The cache tags checksum provider. | |
49 */ | |
50 public function __construct($bin, $site_prefix, CacheTagsChecksumInterface $checksum_provider) { | |
51 $this->bin = $bin; | |
52 $this->sitePrefix = $site_prefix; | |
53 $this->checksumProvider = $checksum_provider; | |
54 $this->binPrefix = $this->sitePrefix . '::' . $this->bin . '::'; | |
55 } | |
56 | |
57 /** | |
58 * Prepends the APCu user variable prefix for this bin to a cache item ID. | |
59 * | |
60 * @param string $cid | |
61 * The cache item ID to prefix. | |
62 * | |
63 * @return string | |
64 * The APCu key for the cache item ID. | |
65 */ | |
66 public function getApcuKey($cid) { | |
67 return $this->binPrefix . $cid; | |
68 } | |
69 | |
70 /** | |
71 * {@inheritdoc} | |
72 */ | |
73 public function get($cid, $allow_invalid = FALSE) { | |
74 $cache = apcu_fetch($this->getApcuKey($cid)); | |
75 return $this->prepareItem($cache, $allow_invalid); | |
76 } | |
77 | |
78 /** | |
79 * {@inheritdoc} | |
80 */ | |
81 public function getMultiple(&$cids, $allow_invalid = FALSE) { | |
82 // Translate the requested cache item IDs to APCu keys. | |
83 $map = []; | |
84 foreach ($cids as $cid) { | |
85 $map[$this->getApcuKey($cid)] = $cid; | |
86 } | |
87 | |
88 $result = apcu_fetch(array_keys($map)); | |
89 $cache = []; | |
90 if ($result) { | |
91 foreach ($result as $key => $item) { | |
92 $item = $this->prepareItem($item, $allow_invalid); | |
93 if ($item) { | |
94 $cache[$map[$key]] = $item; | |
95 } | |
96 } | |
97 } | |
98 unset($result); | |
99 | |
100 $cids = array_diff($cids, array_keys($cache)); | |
101 return $cache; | |
102 } | |
103 | |
104 /** | |
105 * Returns all cached items, optionally limited by a cache ID prefix. | |
106 * | |
107 * APCu is a memory cache, shared across all server processes. To prevent | |
108 * cache item clashes with other applications/installations, every cache item | |
109 * is prefixed with a unique string for this site. Therefore, functions like | |
110 * apcu_clear_cache() cannot be used, and instead, a list of all cache items | |
111 * belonging to this application need to be retrieved through this method | |
112 * instead. | |
113 * | |
114 * @param string $prefix | |
115 * (optional) A cache ID prefix to limit the result to. | |
116 * | |
117 * @return \APCUIterator | |
118 * An APCUIterator containing matched items. | |
119 */ | |
120 protected function getAll($prefix = '') { | |
121 return $this->getIterator('/^' . preg_quote($this->getApcuKey($prefix), '/') . '/'); | |
122 } | |
123 | |
124 /** | |
125 * Prepares a cached item. | |
126 * | |
127 * Checks that the item is either permanent or did not expire. | |
128 * | |
129 * @param \stdClass $cache | |
130 * An item loaded from cache_get() or cache_get_multiple(). | |
131 * @param bool $allow_invalid | |
132 * If TRUE, a cache item may be returned even if it is expired or has been | |
133 * invalidated. See ::get(). | |
134 * | |
135 * @return mixed | |
136 * The cache item or FALSE if the item expired. | |
137 */ | |
138 protected function prepareItem($cache, $allow_invalid) { | |
139 if (!isset($cache->data)) { | |
140 return FALSE; | |
141 } | |
142 | |
143 $cache->tags = $cache->tags ? explode(' ', $cache->tags) : []; | |
144 | |
145 // Check expire time. | |
146 $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; | |
147 | |
148 // Check if invalidateTags() has been called with any of the entry's tags. | |
149 if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) { | |
150 $cache->valid = FALSE; | |
151 } | |
152 | |
153 if (!$allow_invalid && !$cache->valid) { | |
154 return FALSE; | |
155 } | |
156 | |
157 return $cache; | |
158 } | |
159 | |
160 /** | |
161 * {@inheritdoc} | |
162 */ | |
163 public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT, array $tags = []) { | |
164 assert('\Drupal\Component\Assertion\Inspector::assertAllStrings($tags)', 'Cache tags must be strings.'); | |
165 $tags = array_unique($tags); | |
166 $cache = new \stdClass(); | |
167 $cache->cid = $cid; | |
168 $cache->created = round(microtime(TRUE), 3); | |
169 $cache->expire = $expire; | |
170 $cache->tags = implode(' ', $tags); | |
171 $cache->checksum = $this->checksumProvider->getCurrentChecksum($tags); | |
172 // APCu serializes/unserializes any structure itself. | |
173 $cache->serialized = 0; | |
174 $cache->data = $data; | |
175 | |
176 // Expiration is handled by our own prepareItem(), not APCu. | |
177 apcu_store($this->getApcuKey($cid), $cache); | |
178 } | |
179 | |
180 /** | |
181 * {@inheritdoc} | |
182 */ | |
183 public function setMultiple(array $items = []) { | |
184 foreach ($items as $cid => $item) { | |
185 $this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT, isset($item['tags']) ? $item['tags'] : []); | |
186 } | |
187 } | |
188 | |
189 /** | |
190 * {@inheritdoc} | |
191 */ | |
192 public function delete($cid) { | |
193 apcu_delete($this->getApcuKey($cid)); | |
194 } | |
195 | |
196 /** | |
197 * {@inheritdoc} | |
198 */ | |
199 public function deleteMultiple(array $cids) { | |
200 apcu_delete(array_map([$this, 'getApcuKey'], $cids)); | |
201 } | |
202 | |
203 /** | |
204 * {@inheritdoc} | |
205 */ | |
206 public function deleteAll() { | |
207 apcu_delete($this->getIterator('/^' . preg_quote($this->binPrefix, '/') . '/')); | |
208 } | |
209 | |
210 /** | |
211 * {@inheritdoc} | |
212 */ | |
213 public function garbageCollection() { | |
214 // APCu performs garbage collection automatically. | |
215 } | |
216 | |
217 /** | |
218 * {@inheritdoc} | |
219 */ | |
220 public function removeBin() { | |
221 apcu_delete($this->getIterator('/^' . preg_quote($this->binPrefix, '/') . '/')); | |
222 } | |
223 | |
224 /** | |
225 * {@inheritdoc} | |
226 */ | |
227 public function invalidate($cid) { | |
228 $this->invalidateMultiple([$cid]); | |
229 } | |
230 | |
231 /** | |
232 * {@inheritdoc} | |
233 */ | |
234 public function invalidateMultiple(array $cids) { | |
235 foreach ($this->getMultiple($cids) as $cache) { | |
236 $this->set($cache->cid, $cache, REQUEST_TIME - 1); | |
237 } | |
238 } | |
239 | |
240 /** | |
241 * {@inheritdoc} | |
242 */ | |
243 public function invalidateAll() { | |
244 foreach ($this->getAll() as $data) { | |
245 $cid = str_replace($this->binPrefix, '', $data['key']); | |
246 $this->set($cid, $data['value'], REQUEST_TIME - 1); | |
247 } | |
248 } | |
249 | |
250 /** | |
251 * Instantiates and returns the APCUIterator class. | |
252 * | |
253 * @param mixed $search | |
254 * A PCRE regular expression that matches against APC key names, either as a | |
255 * string for a single regular expression, or as an array of regular | |
256 * expressions. Or, optionally pass in NULL to skip the search. | |
257 * @param int $format | |
258 * The desired format, as configured with one or more of the APC_ITER_* | |
259 * constants. | |
260 * @param int $chunk_size | |
261 * The chunk size. Must be a value greater than 0. The default value is 100. | |
262 * @param int $list | |
263 * The type to list. Either pass in APC_LIST_ACTIVE or APC_LIST_DELETED. | |
264 * | |
265 * @return \APCUIterator | |
266 */ | |
267 protected function getIterator($search = NULL, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE) { | |
268 return new \APCUIterator($search, $format, $chunk_size, $list); | |
269 } | |
270 | |
271 } |