Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / memcache / src / MemcacheBackend.php
1 <?php
2
3 namespace Drupal\memcache;
4
5 use Drupal\Component\Assertion\Inspector;
6 use Drupal\Core\Cache\CacheBackendInterface;
7 use Drupal\Core\Cache\CacheTagsChecksumInterface;
8 use Drupal\memcache\Invalidator\TimestampInvalidatorInterface;
9
10 /**
11  * Defines a Memcache cache backend.
12  */
13 class MemcacheBackend implements CacheBackendInterface {
14
15   /**
16    * The cache bin to use.
17    *
18    * @var string
19    */
20   protected $bin;
21
22   /**
23    * The (micro)time the bin was last deleted.
24    *
25    * @var float
26    */
27   protected $lastBinDeletionTime;
28
29   /**
30    * The memcache wrapper object.
31    *
32    * @var \Drupal\memcache\DrupalMemcacheInterface
33    */
34   protected $memcache;
35
36   /**
37    * The cache tags checksum provider.
38    *
39    * @var \Drupal\Core\Cache\CacheTagsChecksumInterface|\Drupal\Core\Cache\CacheTagsInvalidatorInterface
40    */
41   protected $checksumProvider;
42
43   /**
44    * The timestamp invalidation provider.
45    *
46    * @var \Drupal\memcache\Invalidator\TimestampInvalidatorInterface
47    */
48   protected $timestampInvalidator;
49
50   /**
51    * Constructs a MemcacheBackend object.
52    *
53    * @param string $bin
54    *   The bin name.
55    * @param \Drupal\memcache\DrupalMemcacheInterface $memcache
56    *   The memcache object.
57    * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
58    *   The cache tags checksum service.
59    * @param \Drupal\memcache\Invalidator\TimestampInvalidatorInterface $timestamp_invalidator
60    *   The timestamp invalidation provider.
61    */
62   public function __construct($bin, DrupalMemcacheInterface $memcache, CacheTagsChecksumInterface $checksum_provider, TimestampInvalidatorInterface $timestamp_invalidator) {
63     $this->bin = $bin;
64     $this->memcache = $memcache;
65     $this->checksumProvider = $checksum_provider;
66     $this->timestampInvalidator = $timestamp_invalidator;
67
68     $this->ensureBinDeletionTimeIsSet();
69   }
70
71   /**
72    * {@inheritdoc}
73    */
74   public function get($cid, $allow_invalid = FALSE) {
75     $cids = [$cid];
76     $cache = $this->getMultiple($cids, $allow_invalid);
77     return reset($cache);
78   }
79
80   /**
81    * {@inheritdoc}
82    */
83   public function getMultiple(&$cids, $allow_invalid = FALSE) {
84     $cache = $this->memcache->getMulti($cids);
85     $fetched = [];
86
87     foreach ($cache as $result) {
88       if (!$this->timeIsGreaterThanBinDeletionTime($result->created)) {
89         continue;
90       }
91
92       if ($this->valid($result->cid, $result) || $allow_invalid) {
93         // Add it to the fetched items to diff later.
94         $fetched[$result->cid] = $result;
95       }
96     }
97
98     // Remove items from the referenced $cids array that we are returning,
99     // per comment in Drupal\Core\Cache\CacheBackendInterface::getMultiple().
100     $cids = array_diff($cids, array_keys($fetched));
101
102     return $fetched;
103   }
104
105   /**
106    * Determines if the cache item is valid.
107    *
108    * This also alters the valid property of the cache item itself.
109    *
110    * @param string $cid
111    *   The cache ID.
112    * @param \stdClass $cache
113    *   The cache item.
114    *
115    * @return bool
116    *   TRUE if valid, FALSE otherwise.
117    */
118   protected function valid($cid, \stdClass $cache) {
119     $cache->valid = TRUE;
120
121     // Items that have expired are invalid.
122     if ($cache->expire != CacheBackendInterface::CACHE_PERMANENT && $cache->expire <= REQUEST_TIME) {
123       $cache->valid = FALSE;
124     }
125
126     // Check if invalidateTags() has been called with any of the items's tags.
127     if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) {
128       $cache->valid = FALSE;
129     }
130
131     return $cache->valid;
132   }
133
134   /**
135    * {@inheritdoc}
136    */
137   public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT, array $tags = []) {
138     assert(Inspector::assertAllStrings($tags));
139
140     $tags[] = "memcache:$this->bin";
141     $tags = array_unique($tags);
142     // Sort the cache tags so that they are stored consistently.
143     sort($tags);
144
145     // Create new cache object.
146     $cache = new \stdClass();
147     $cache->cid = $cid;
148     $cache->data = $data;
149     $cache->created = round(microtime(TRUE), 3);
150     $cache->expire = $expire;
151     $cache->tags = $tags;
152     $cache->checksum = $this->checksumProvider->getCurrentChecksum($tags);
153
154     // Cache all items permanently. We handle expiration in our own logic.
155     return $this->memcache->set($cid, $cache);
156   }
157
158   /**
159    * {@inheritdoc}
160    */
161   public function setMultiple(array $items) {
162     foreach ($items as $cid => $item) {
163       $item += [
164         'expire' => CacheBackendInterface::CACHE_PERMANENT,
165         'tags' => [],
166       ];
167
168       $this->set($cid, $item['data'], $item['expire'], $item['tags']);
169     }
170   }
171
172   /**
173    * {@inheritdoc}
174    */
175   public function delete($cid) {
176     $this->memcache->delete($cid);
177   }
178
179   /**
180    * {@inheritdoc}
181    */
182   public function deleteMultiple(array $cids) {
183     foreach ($cids as $cid) {
184       $this->memcache->delete($cid);
185     }
186   }
187
188   /**
189    * {@inheritdoc}
190    */
191   public function deleteAll() {
192     $this->lastBinDeletionTime = $this->timestampInvalidator->invalidateTimestamp($this->bin);
193   }
194
195   /**
196    * {@inheritdoc}
197    */
198   public function invalidate($cid) {
199     $this->invalidateMultiple([$cid]);
200   }
201
202   /**
203    * Marks cache items as invalid.
204    *
205    * Invalid items may be returned in later calls to get(), if the
206    * $allow_invalid argument is TRUE.
207    *
208    * @param array $cids
209    *   An array of cache IDs to invalidate.
210    *
211    * @see Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
212    * @see Drupal\Core\Cache\CacheBackendInterface::invalidate()
213    * @see Drupal\Core\Cache\CacheBackendInterface::invalidateTags()
214    * @see Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
215    */
216   public function invalidateMultiple(array $cids) {
217     foreach ($cids as $cid) {
218       if ($item = $this->get($cid)) {
219         $item->expire = REQUEST_TIME - 1;
220         $this->memcache->set($cid, $item);
221       }
222     }
223   }
224
225   /**
226    * {@inheritdoc}
227    */
228   public function invalidateAll() {
229     $this->invalidateTags(["memcache:$this->bin"]);
230   }
231
232   /**
233    * {@inheritdoc}
234    */
235   public function invalidateTags(array $tags) {
236     $this->checksumProvider->invalidateTags($tags);
237   }
238
239   /**
240    * {@inheritdoc}
241    */
242   public function removeBin() {
243     $this->lastBinDeletionTime = $this->timestampInvalidator->invalidateTimestamp($this->bin);
244   }
245
246   /**
247    * {@inheritdoc}
248    */
249   public function garbageCollection() {
250     // Memcache will invalidate items; That items memory allocation is then
251     // freed up and reused. So nothing needs to be deleted/cleaned up here.
252   }
253
254   /**
255    * {@inheritdoc}
256    */
257   public function isEmpty() {
258     // We do not know so err on the safe side? Not sure if we can know this?
259     return TRUE;
260   }
261
262   /**
263    * Determines if a (micro)time is greater than the last bin deletion time.
264    *
265    * @param float $item_microtime
266    *   A given (micro)time.
267    *
268    * @internal
269    *
270    * @return bool
271    *   TRUE if the (micro)time is greater than the last bin deletion time, FALSE
272    *   otherwise.
273    */
274   protected function timeIsGreaterThanBinDeletionTime($item_microtime) {
275     $last_bin_deletion = $this->getBinLastDeletionTime();
276
277     // If there is time, assume FALSE as there is no previous deletion time
278     // to compare with.
279     if (!$last_bin_deletion) {
280       return FALSE;
281     }
282
283     return $item_microtime > $last_bin_deletion;
284   }
285
286   /**
287    * Gets the last invalidation time for the bin.
288    *
289    * @internal
290    *
291    * @return float
292    *   The last invalidation timestamp of the tag.
293    */
294   protected function getBinLastDeletionTime() {
295     if (!isset($this->lastBinDeletionTime)) {
296       $this->lastBinDeletionTime = $this->timestampInvalidator->getLastInvalidationTimestamp($this->bin);
297     }
298
299     return $this->lastBinDeletionTime;
300   }
301
302   /**
303    * Ensures a last bin deletion time has been set.
304    *
305    * @internal
306    */
307   protected function ensureBinDeletionTimeIsSet() {
308     if (!$this->getBinLastDeletionTime()) {
309       $this->lastBinDeletionTime = $this->timestampInvalidator->invalidateTimestamp($this->bin);
310     }
311   }
312
313 }