Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / memcache / src / Cache / TimestampCacheTagsChecksum.php
1 <?php
2
3 namespace Drupal\memcache\Cache;
4
5 use Drupal\Core\Cache\CacheTagsChecksumInterface;
6 use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
7 use Drupal\memcache\Invalidator\TimestampInvalidatorInterface;
8
9 /**
10  * Cache tags invalidations checksum implementation by timestamp invalidation.
11  */
12 class TimestampCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface {
13
14   /**
15    * The timestamp invalidator object.
16    *
17    * @var \Drupal\memcache\Invalidator\TimestampInvalidatorInterface
18    */
19   protected $invalidator;
20
21   /**
22    * Contains already loaded cache invalidations from the backend.
23    *
24    * @var array
25    */
26   protected $tagCache = [];
27
28   /**
29    * A list of tags that have already been invalidated in this request.
30    *
31    * Used to prevent the invalidation of the same cache tag multiple times.
32    *
33    * @var array
34    */
35   protected $invalidatedTags = [];
36
37   /**
38    * Constructs a TimestampCacheTagsChecksum object.
39    *
40    * @param \Drupal\memcache\Invalidator\TimestampInvalidatorInterface $invalidator
41    *   The timestamp invalidator object.
42    */
43   public function __construct(TimestampInvalidatorInterface $invalidator) {
44     $this->invalidator = $invalidator;
45   }
46
47   /**
48    * {@inheritdoc}
49    */
50   public function invalidateTags(array $tags) {
51     foreach ($tags as $tag) {
52       // @todo Revisit this behavior and determine a better way to handle.
53       // Only invalidate tags once per request unless they are written again.
54       if (isset($this->invalidatedTags[$tag])) {
55         continue;
56       }
57       $this->invalidatedTags[$tag] = TRUE;
58       $this->tagCache[$tag] = $this->invalidator->invalidateTimestamp($tag);
59     }
60   }
61
62   /**
63    * {@inheritdoc}
64    */
65   public function getCurrentChecksum(array $tags) {
66     // @todo Revisit the invalidatedTags hack.
67     // Remove tags that were already invalidated during this request from the
68     // static caches so that another invalidation can occur later in the same
69     // request. Without that, written cache items would not be invalidated
70     // correctly.
71     foreach ($tags as $tag) {
72       unset($this->invalidatedTags[$tag]);
73     }
74     // Taking the minimum of the current timestamp and the checksum is used to
75     // ensure that items that are not valid yet are identified properly as not
76     // valid. The checksum will change continuously until the item is valid,
77     // at which point the checksum will match and freeze at that value.
78     return min($this->invalidator->getCurrentTimestamp(), $this->calculateChecksum($tags));
79   }
80
81   /**
82    * {@inheritdoc}
83    */
84   public function isValid($checksum, array $tags) {
85     if (empty($tags)) {
86       // If there weren't any tags, the checksum should always be 0 or FALSE.
87       return $checksum == 0;
88     }
89     return $checksum == $this->calculateChecksum($tags);
90   }
91
92   /**
93    * Calculates the current checksum for a given set of tags.
94    *
95    * @param array $tags
96    *   The array of tags to calculate the checksum for.
97    *
98    * @return int
99    *   The calculated checksum.
100    */
101   protected function calculateChecksum(array $tags) {
102
103     $query_tags = array_diff($tags, array_keys($this->tagCache));
104     if ($query_tags) {
105       $backend_tags = $this->invalidator->getLastInvalidationTimestamps($query_tags);
106       $this->tagCache += $backend_tags;
107       $invalid = array_diff($query_tags, array_keys($backend_tags));
108       if (!empty($invalid)) {
109         // Invalidate any missing tags now. This is necessary because we cannot
110         // zero-optimize our tag list -- we can't tell the difference between
111         // a tag that has never been invalidated and a tag that was
112         // garbage-collected by the backend!
113         //
114         // This behavioral difference is the main change that allows us to use
115         // an unreliable backend to track cache tag invalidation.
116         //
117         // Invalidating the tag will cause it to start being tracked, so it can
118         // be matched against the checksums stored on items.
119         // All items cached after that point with the tag will end up with
120         // a valid checksum, and all items cached before that point with the tag
121         // will have an invalid checksum, because missing invalidations will
122         // keep moving forward in time as they get garbage collected and are
123         // re-invalidated.
124         //
125         // The main effect of all this is that a tag going missing
126         // will automatically cause the cache items tagged with it to no longer
127         // have the correct checksum.
128         foreach ($invalid as $invalid_tag) {
129           $this->invalidator->invalidateTimestamp($invalid_tag);
130         }
131       }
132     }
133
134     // The checksum is equal to the *most recent* invalidation of an applicable
135     // tag. If the item is untagged, the checksum is always 0.
136     return max([0] + array_intersect_key($this->tagCache, array_flip($tags)));
137   }
138
139   /**
140    * {@inheritdoc}
141    */
142   public function reset() {
143     $this->tagCache = [];
144     $this->invalidatedTags = [];
145   }
146
147 }