diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php index f6de468..40ede29 100644 --- a/core/lib/Drupal/Core/Cache/ApcuBackend.php +++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php @@ -36,20 +36,29 @@ class ApcuBackend implements CacheBackendInterface { protected $binPrefix; /** - * Prefix for keys holding cache tags. + * Prefix for keys holding invalidation cache tags. * * Includes the site-specific prefix in $sitePrefix. * * @var string */ - protected $tagsPrefix; + protected $invalidationsTagsPrefix; + + /** + * Prefix for keys holding invalidation cache tags. + * + * Includes the site-specific prefix in $sitePrefix. + * + * @var string + */ + protected $deletionsTagsPrefix; /** * A static cache of all tags checked during the request. * * @var array */ - protected static $tagCache = array(); + protected static $tagCache = array('deletions' => array(), 'invalidations' => array()); /** * Constructs a new ApcuBackend instance. @@ -63,7 +72,8 @@ public function __construct($bin, $site_prefix) { $this->bin = $bin; $this->sitePrefix = $site_prefix; $this->binPrefix = $this->sitePrefix . '::' . $this->bin . '::'; - $this->tagsPrefix = $this->sitePrefix . '::tags::'; + $this->invalidationsTagsPrefix = $this->sitePrefix . '::itags::'; + $this->deletionsTagsPrefix = $this->sitePrefix . '::dtags::'; } /** @@ -153,16 +163,16 @@ protected function prepareItem($cache, $allow_invalid) { $cache->tags = $cache->tags ? explode(' ', $cache->tags) : array(); $checksum = $this->checksumTags($cache->tags); - // The cache data is invalid if any of its tags have been cleared since. - if (!$this->validTags($checksum, $cache->tags)) { + // Check if deleteTags() has been called with any of the entry's tags. + if ($cache->checksum_deletions != $checksum['deletions']) { return FALSE; } // Check expire time. - $cache->valid = ($cache->expire == CacheBackendInterface::CACHE_PERMANENT) || ($cache->expire >= REQUEST_TIME); + $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; // Check if invalidateTags() has been called with any of the entry's tags. - if ($cache->checksum != $checksum) { + if ($cache->checksum_invalidations != $checksum['invalidations']) { $cache->valid = FALSE; } @@ -182,8 +192,9 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN $cache->created = REQUEST_TIME; $cache->expire = $expire; $cache->tags = implode(' ', $this->flattenTags($tags)); - $cache->checksum = $this->checksumTags($tags); - + $checksum = $this->checksumTags($tags); + $cache->checksum_invalidations = $checksum['invalidations']; + $cache->checksum_deletions = $checksum['deletions']; // APC serializes/unserializes any structure itself. $cache->serialized = 0; $cache->data = $data; @@ -199,7 +210,7 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN } /** - * {@inheritdoc + * {@inheritdoc} */ public function setMultiple(array $items = array()) { foreach ($items as $cid => $item) { @@ -241,7 +252,8 @@ public function garbageCollection() { */ public function removeBin() { $this->deleteAll(); - apc_delete(new \APCIterator('user', '/^' . preg_quote($this->tagsPrefix, '/') . '/')); + apc_delete(new \APCIterator('user', '/^' . preg_quote($this->deletionsTagsPrefix, '/') . '/')); + apc_delete(new \APCIterator('user', '/^' . preg_quote($this->invalidationsTagsPrefix, '/') . '/')); } /** @@ -283,8 +295,10 @@ public function invalidateAll() { */ public function deleteTags(array $tags) { foreach ($this->flattenTags($tags) as $tag) { - apc_delete($this->tagsPrefix . $tag); - unset(static::$tagCache[$tag]); + apc_inc($this->deletionsTagsPrefix . $tag, 1, $success); + if (!$success) { + apc_store($this->deletionsTagsPrefix . $tag, 1); + } } } @@ -293,33 +307,14 @@ public function deleteTags(array $tags) { */ public function invalidateTags(array $tags) { foreach ($this->flattenTags($tags) as $tag) { - unset(static::$tagCache[$tag]); - apc_inc($this->tagsPrefix . $tag, 1, $success); + apc_inc($this->invalidationsTagsPrefix . $tag, 1, $success); if (!$success) { - apc_store($this->tagsPrefix . $tag, 1); + apc_store($this->invalidationsTagsPrefix . $tag, 1); } } } /** - * Compares two checksums of tags. - * - * Used to determine whether to serve a cached item or treat it as - * invalidated. - * - * @param int $checksum - * The initial checksum to compare against. - * @param array $tags - * An array of tags to calculate a checksum for. - * - * @return bool - * TRUE if the checksums match, FALSE otherwise. - */ - protected function validTags($checksum, array $tags) { - return $checksum == $this->checksumTags($tags); - } - - /** * Flattens a tags array into a numeric array suitable for string storage. * * @param array $tags @@ -357,21 +352,26 @@ protected function flattenTags(array $tags) { * Sum of all invalidations. */ protected function checksumTags(array $tags) { - $checksum = 0; - $query_tags = array(); + $checksum = array('invalidations' => 0, 'deletions' => 0); + $query_tags = array('invalidations' => array(), 'deletions' => array()); foreach ($this->flattenTags($tags) as $tag) { - if (isset(static::$tagCache[$tag])) { - $checksum += static::$tagCache[$tag]; - } - else { - $query_tags[] = $this->tagsPrefix . $tag; + foreach (array('deletions', 'invalidations') as $type) { + if (isset(static::$tagCache[$type][$tag])) { + $checksum[$type] += static::$tagCache[$type][$tag]; + } + else { + $query_tags[$type][] = $this->{$type . 'TagsPrefix'} . $tag; + } } } - if ($query_tags) { - $result = apc_fetch($query_tags); - static::$tagCache = array_merge(static::$tagCache, $result); - $checksum += array_sum($result); + + foreach (array('deletions', 'invalidations') as $type) { + if ($query_tags[$type]) { + $result = apc_fetch($query_tags[$type]); + static::$tagCache[$type] = array_merge(static::$tagCache[$type], $result); + $checksum[$type] += array_sum($result); + } } return $checksum;