diff --git a/core/core.services.yml b/core/core.services.yml index 328acd8..2ae1da0 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -32,6 +32,18 @@ services: class: Drupal\Core\Cache\TimeZoneCacheContext tags: - { name: cache.context} + cache_tags.invalidator: + parent: container.trait + class: Drupal\Core\Cache\CacheTagsInvalidator + calls: + - [setContainer, ['@service_container']] + tags: + - { name: service_collector, call: addInvalidator, tag: cache_tags_invalidator } + cache_tags.invalidator.checksum: + class: Drupal\Core\Cache\DatabaseCacheTagsChecksum + arguments: ['@database'] + tags: + - { name: cache_tags_invalidator} cache.backend.chainedfast: class: Drupal\Core\Cache\ChainedFastBackendFactory arguments: ['@settings'] @@ -39,12 +51,13 @@ services: - [setContainer, ['@service_container']] cache.backend.database: class: Drupal\Core\Cache\DatabaseBackendFactory - arguments: ['@database'] + arguments: ['@database', '@cache_tags.invalidator.checksum'] cache.backend.apcu: class: Drupal\Core\Cache\ApcuBackendFactory - arguments: ['@app.root'] + arguments: ['@app.root', '@cache_tags.invalidator.checksum'] cache.backend.php: class: Drupal\Core\Cache\PhpBackendFactory + arguments: ['@cache_tags.invalidator.checksum'] cache.bootstrap: class: Drupal\Core\Cache\CacheBackendInterface tags: diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php index 50fb0fd..46a73b6 100644 --- a/core/lib/Drupal/Core/Cache/ApcuBackend.php +++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php @@ -45,20 +45,18 @@ class ApcuBackend implements CacheBackendInterface { protected $invalidationsTagsPrefix; /** - * Prefix for keys holding invalidation cache tags. + * The cache tags checksum provider. * - * Includes the site-specific prefix in $sitePrefix. - * - * @var string + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface */ - protected $deletionsTagsPrefix; + protected $checksumProvider; /** * A static cache of all tags checked during the request. * * @var array */ - protected static $tagCache = array('deletions' => array(), 'invalidations' => array()); + protected static $tagCache = array(); /** * Constructs a new ApcuBackend instance. @@ -67,13 +65,15 @@ class ApcuBackend implements CacheBackendInterface { * The name of the cache bin. * @param string $site_prefix * The prefix to use for all keys in the storage that belong to this site. + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. */ - public function __construct($bin, $site_prefix) { + public function __construct($bin, $site_prefix, CacheTagsChecksumInterface $checksum_provider) { $this->bin = $bin; $this->sitePrefix = $site_prefix; + $this->checksumProvider = $checksum_provider; $this->binPrefix = $this->sitePrefix . '::' . $this->bin . '::'; $this->invalidationsTagsPrefix = $this->sitePrefix . '::itags::'; - $this->deletionsTagsPrefix = $this->sitePrefix . '::dtags::'; } /** @@ -163,18 +163,12 @@ protected function prepareItem($cache, $allow_invalid) { } $cache->tags = $cache->tags ? explode(' ', $cache->tags) : array(); - $checksum = $this->checksumTags($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 == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; // Check if invalidateTags() has been called with any of the entry's tags. - if ($cache->checksum_invalidations != $checksum['invalidations']) { + if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) { $cache->valid = FALSE; } @@ -196,9 +190,7 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN $cache->created = round(microtime(TRUE), 3); $cache->expire = $expire; $cache->tags = implode(' ', $tags); - $checksum = $this->checksumTags($tags); - $cache->checksum_invalidations = $checksum['invalidations']; - $cache->checksum_deletions = $checksum['deletions']; + $cache->checksum = $this->checksumProvider->getCurrentChecksum($tags); // APC serializes/unserializes any structure itself. $cache->serialized = 0; $cache->data = $data; @@ -283,65 +275,4 @@ public function invalidateAll() { } } - /** - * {@inheritdoc} - */ - public function deleteTags(array $tags) { - foreach ($tags as $tag) { - apc_inc($this->deletionsTagsPrefix . $tag, 1, $success); - if (!$success) { - apc_store($this->deletionsTagsPrefix . $tag, 1); - } - } - } - - /** - * {@inheritdoc} - */ - public function invalidateTags(array $tags) { - foreach ($tags as $tag) { - apc_inc($this->invalidationsTagsPrefix . $tag, 1, $success); - if (!$success) { - apc_store($this->invalidationsTagsPrefix . $tag, 1); - } - } - } - - /** - * Returns the sum total of validations for a given set of tags. - * - * @param array $tags - * Associative array of tags. - * - * @return int - * Sum of all invalidations. - */ - protected function checksumTags(array $tags) { - $checksum = array('invalidations' => 0, 'deletions' => 0); - $query_tags = array('invalidations' => array(), 'deletions' => array()); - - foreach ($tags as $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; - } - } - } - - foreach (array('deletions', 'invalidations') as $type) { - if ($query_tags[$type]) { - $result = apc_fetch($query_tags[$type]); - if ($result) { - static::$tagCache[$type] = array_merge(static::$tagCache[$type], $result); - $checksum[$type] += array_sum($result); - } - } - } - - return $checksum; - } - } diff --git a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php index ffe5993..bbc4e3d 100644 --- a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php @@ -19,13 +19,23 @@ class ApcuBackendFactory implements CacheFactoryInterface { protected $sitePrefix; /** + * The cache tags checksum provider. + * + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface + */ + protected $checksumProvider; + + /** * Constructs an ApcuBackendFactory object. * * @param string $root * The app root. + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. */ - public function __construct($root) { + public function __construct($root, CacheTagsChecksumInterface $checksum_provider) { $this->sitePrefix = Crypt::hashBase64($root . '/' . conf_path()); + $this->checksumProvider = $checksum_provider; } /** @@ -38,7 +48,7 @@ public function __construct($root) { * The cache backend object for the specified cache bin. */ public function get($bin) { - return new ApcuBackend($bin, $this->sitePrefix); + return new ApcuBackend($bin, $this->sitePrefix, $this->checksumProvider); } } diff --git a/core/lib/Drupal/Core/Cache/BackendChain.php b/core/lib/Drupal/Core/Cache/BackendChain.php index 0cea142..f7681d9 100644 --- a/core/lib/Drupal/Core/Cache/BackendChain.php +++ b/core/lib/Drupal/Core/Cache/BackendChain.php @@ -23,7 +23,7 @@ * @ingroup cache */ -class BackendChain implements CacheBackendInterface { +class BackendChain implements CacheBackendInterface, CacheTagsInvalidatorInterface { /** * Ordered list of CacheBackendInterface instances. @@ -159,15 +159,6 @@ public function deleteMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). - */ - public function deleteTags(array $tags) { - foreach ($this->backends as $backend) { - $backend->deleteTags($tags); - } - } - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll(). */ public function deleteAll() { @@ -199,7 +190,9 @@ public function invalidateMultiple(array $cids) { */ public function invalidateTags(array $tags) { foreach ($this->backends as $backend) { - $backend->invalidateTags($tags); + if ($backend instanceof CacheTagsInvalidatorInterface) { + $backend->invalidateTags($tags); + } } } diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index ddf444e..4ce3610 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -94,43 +94,13 @@ public static function buildTags($prefix, array $suffixes) { } /** - * Deletes items from all bins with any of the specified tags. - * - * Many sites have more than one active cache backend, and each backend may - * use a different strategy for storing tags against cache items, and - * deleting cache items associated with a given tag. - * - * When deleting a given list of tags, we iterate over each cache backend, and - * and call deleteTags() on each. - * - * @param string[] $tags - * The list of tags to delete cache items for. - */ - public static function deleteTags(array $tags) { - static::validateTags($tags); - foreach (static::getBins() as $cache_backend) { - $cache_backend->deleteTags($tags); - } - } - - /** * Marks cache items from all bins with any of the specified tags as invalid. * - * Many sites have more than one active cache backend, and each backend my use - * a different strategy for storing tags against cache items, and invalidating - * cache items associated with a given tag. - * - * When invalidating a given list of tags, we iterate over each cache backend, - * and call invalidateTags() on each. - * * @param string[] $tags * The list of tags to invalidate cache items for. */ public static function invalidateTags(array $tags) { - static::validateTags($tags); - foreach (static::getBins() as $cache_backend) { - $cache_backend->invalidateTags($tags); - } + \Drupal::service('cache_tags.invalidator')->invalidateTags($tags); } /** diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php index 39c8c26..faf2459 100644 --- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php +++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php @@ -136,7 +136,6 @@ public function setMultiple(array $items); * * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags() * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() */ public function delete($cid); @@ -155,39 +154,16 @@ public function delete($cid); * * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() * @see \Drupal\Core\Cache\CacheBackendInterface::delete() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags() * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() */ public function deleteMultiple(array $cids); /** - * Deletes items with any of the specified tags. - * - * If the cache items are being deleted because they are no longer "fresh", - * you may consider using invalidateTags() instead. This allows callers to - * retrieve the invalid items by calling get() with $allow_invalid set to TRUE. - * In some cases an invalid item may be acceptable rather than having to - * rebuild the cache. - * - * @param array $tags - * Associative array of tags, in the same format that is passed to - * CacheBackendInterface::set(). - * - * @see \Drupal\Core\Cache\CacheBackendInterface::set() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags() - * @see \Drupal\Core\Cache\CacheBackendInterface::delete() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() - */ - public function deleteTags(array $tags); - - /** * Deletes all cache items in a bin. * * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() * @see \Drupal\Core\Cache\CacheBackendInterface::delete() * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags() */ public function deleteAll(); @@ -202,7 +178,6 @@ public function deleteAll(); * * @see \Drupal\Core\Cache\CacheBackendInterface::delete() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() */ public function invalidate($cid); @@ -213,44 +188,24 @@ public function invalidate($cid); * Invalid items may be returned in later calls to get(), if the $allow_invalid * argument is TRUE. * - * @param string $cids + * @param string[] $cids * An array of cache IDs to invalidate. * * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() */ public function invalidateMultiple(array $cids); /** - * Marks cache items with any of the specified tags as invalid. - * - * @param array $tags - * Associative array of tags, in the same format that is passed to - * CacheBackendInterface::set(). - * - * @see \Drupal\Core\Cache\CacheBackendInterface::set() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() - */ - public function invalidateTags(array $tags); - - /** * Marks all cache items as invalid. * * Invalid items may be returned in later calls to get(), if the $allow_invalid * argument is TRUE. * - * @param string $cids - * An array of cache IDs to invalidate. - * * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags() */ public function invalidateAll(); diff --git a/core/lib/Drupal/Core/Cache/CacheCollector.php b/core/lib/Drupal/Core/Cache/CacheCollector.php index d80da7d..a6d8ab5 100644 --- a/core/lib/Drupal/Core/Cache/CacheCollector.php +++ b/core/lib/Drupal/Core/Cache/CacheCollector.php @@ -280,7 +280,7 @@ public function reset() { public function clear() { $this->reset(); if ($this->tags) { - Cache::deleteTags($this->tags); + Cache::invalidateTags($this->tags); } else { $this->cache->delete($this->getCid()); diff --git a/core/lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php b/core/lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php new file mode 100644 index 0000000..a140112 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php @@ -0,0 +1,62 @@ +invalidators as $invalidator) { + $invalidator->invalidateTags($tags); + } + + // Additionally, notify each cache bin if it implements the service. + foreach ($this->getInvalidatorCacheBins() as $bin) { + $bin->invalidateTags($tags); + } + } + + /** + * Adds a cache tags invalidator. + * + * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $invalidator + * A cache invalidator. + */ + public function addInvalidator(CacheTagsInvalidatorInterface $invalidator) { + $this->invalidators[] = $invalidator; + } + + /** + * Returns all cache bins that need to be notified about invalidations. + * + * @return \Drupal\Core\Cache\CacheTagsInvalidatorInterface[] + * An array of cache backend objects that implement the invalidator + * interface, keyed by their cache bin. + */ + protected function getInvalidatorCacheBins() { + $bins = array(); + foreach ($this->container->getParameter('cache_bins') as $service_id => $bin) { + $service = $this->container->get($service_id); + if ($service instanceof CacheTagsInvalidatorInterface) { + $bins[$bin] = $service; + } + } + return $bins; + } + +} diff --git a/core/lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php b/core/lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php new file mode 100644 index 0000000..bf63041 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php @@ -0,0 +1,29 @@ +markAsOutdated(); - $this->consistentBackend->deleteTags($tags); - } - - /** - * {@inheritdoc} - */ public function deleteAll() { $this->consistentBackend->deleteAll(); $this->markAsOutdated(); @@ -245,7 +237,9 @@ public function invalidateMultiple(array $cids) { * {@inheritdoc} */ public function invalidateTags(array $tags) { - $this->consistentBackend->invalidateTags($tags); + if ($this->consistentBackend instanceof CacheTagsInvalidatorInterface) { + $this->consistentBackend->invalidateTags($tags); + } $this->markAsOutdated(); } diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index 813c00a..4610636 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -35,19 +35,29 @@ class DatabaseBackend implements CacheBackendInterface { protected $connection; /** + * The cache tags checksum provider. + * + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface + */ + protected $checksumProvider; + + /** * Constructs a DatabaseBackend object. * * @param \Drupal\Core\Database\Connection $connection * The database connection. + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. * @param string $bin * The cache bin for which the object is created. */ - public function __construct(Connection $connection, $bin) { + public function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider, $bin) { // All cache tables should be prefixed with 'cache_'. $bin = 'cache_' . $bin; $this->bin = $bin; $this->connection = $connection; + $this->checksumProvider = $checksum_provider; } /** @@ -76,7 +86,7 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { // ::select() is a much smaller proportion of the request. $result = array(); try { - $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum_invalidations, checksum_deletions FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => array_keys($cid_mapping))); + $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => array_keys($cid_mapping))); } catch (\Exception $e) { // Nothing to do. @@ -116,18 +126,11 @@ protected function prepareItem($cache, $allow_invalid) { $cache->tags = $cache->tags ? explode(' ', $cache->tags) : array(); - $checksum = $this->checksumTags($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 == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; - // Check if invalidateTags() has been called with any of the entry's tags. - if ($cache->checksum_invalidations != $checksum['invalidations']) { + // Check if invalidateTags() has been called with any of the items's tags. + if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) { $cache->valid = FALSE; } @@ -174,27 +177,11 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array * Actually set the cache. */ protected function doSet($cid, $data, $expire, $tags) { - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); - // Remove tags that were already deleted or invalidated during this request - // from the static caches so that another deletion or invalidation can - // occur. - foreach ($tags as $tag) { - if (isset($deleted_tags[$tag])) { - unset($deleted_tags[$tag]); - } - if (isset($invalidated_tags[$tag])) { - unset($invalidated_tags[$tag]); - } - } - $checksum = $this->checksumTags($tags); $fields = array( - 'serialized' => 0, 'created' => round(microtime(TRUE), 3), 'expire' => $expire, 'tags' => implode(' ', $tags), - 'checksum_invalidations' => $checksum['invalidations'], - 'checksum_deletions' => $checksum['deletions'], + 'checksum' => $this->checksumProvider->getCurrentChecksum($tags), ); if (!is_string($data)) { $fields['data'] = serialize($data); @@ -215,9 +202,6 @@ protected function doSet($cid, $data, $expire, $tags) { * {@inheritdoc} */ public function setMultiple(array $items) { - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); - // Use a transaction so that the database can write the changes in a single // commit. $transaction = $this->connection->startTransaction(); @@ -229,7 +213,7 @@ public function setMultiple(array $items) { $query = $this->connection ->insert($this->bin) - ->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum_invalidations', 'checksum_deletions')); + ->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum')); foreach ($items as $cid => $item) { $item += array( @@ -242,27 +226,12 @@ public function setMultiple(array $items) { // Sort the cache tags so that they are stored consistently in the DB. sort($item['tags']); - // Remove tags that were already deleted or invalidated during this - // request from the static caches so that another deletion or - // invalidation can occur. - foreach ($item['tags'] as $tag) { - if (isset($deleted_tags[$tag])) { - unset($deleted_tags[$tag]); - } - if (isset($invalidated_tags[$tag])) { - unset($invalidated_tags[$tag]); - } - } - - $checksum = $this->checksumTags($item['tags']); - $fields = array( 'cid' => $cid, 'expire' => $item['expire'], 'created' => round(microtime(TRUE), 3), 'tags' => implode(' ', $item['tags']), - 'checksum_invalidations' => $checksum['invalidations'], - 'checksum_deletions' => $checksum['deletions'], + 'checksum' => $this->checksumProvider->getCurrentChecksum($item['tags']), ); if (!is_string($item['data'])) { @@ -317,32 +286,6 @@ public function deleteMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). - */ - public function deleteTags(array $tags) { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - foreach ($tags as $tag) { - // Only delete tags once per request unless they are written again. - if (isset($deleted_tags[$tag])) { - continue; - } - $deleted_tags[$tag] = TRUE; - unset($tag_cache[$tag]); - try { - $this->connection->merge('cachetags') - ->insertFields(array('deletions' => 1)) - ->expression('deletions', 'deletions + 1') - ->key('tag', $tag) - ->execute(); - } - catch (\Exception $e) { - $this->catchException($e, 'cachetags'); - } - } - } - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll(). */ public function deleteAll() { @@ -386,32 +329,6 @@ public function invalidateMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). - */ - public function invalidateTags(array $tags) { - try { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); - foreach ($tags as $tag) { - // Only invalidate tags once per request unless they are written again. - if (isset($invalidated_tags[$tag])) { - continue; - } - $invalidated_tags[$tag] = TRUE; - unset($tag_cache[$tag]); - $this->connection->merge('cachetags') - ->insertFields(array('invalidations' => 1)) - ->expression('invalidations', 'invalidations + 1') - ->key('tag', $tag) - ->execute(); - } - } - catch (\Exception $e) { - $this->catchException($e, 'cachetags'); - } - } - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateAll(). */ public function invalidateAll() { @@ -443,40 +360,6 @@ public function garbageCollection() { } /** - * Returns the sum total of validations for a given set of tags. - * - * @param array $tags - * Array of cache tags. - * - * @return int - * Sum of all invalidations. - */ - protected function checksumTags(array $tags) { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); - - $checksum = array( - 'invalidations' => 0, - 'deletions' => 0, - ); - - $query_tags = array_diff($tags, array_keys($tag_cache)); - if ($query_tags) { - $db_tags = $this->connection->query('SELECT tag, invalidations, deletions FROM {cachetags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllAssoc('tag', \PDO::FETCH_ASSOC); - $tag_cache += $db_tags; - - // Fill static cache with empty objects for tags not found in the database. - $tag_cache += array_fill_keys(array_diff($query_tags, array_keys($db_tags)), $checksum); - } - - foreach ($tags as $tag) { - $checksum['invalidations'] += $tag_cache[$tag]['invalidations']; - $checksum['deletions'] += $tag_cache[$tag]['deletions']; - } - - return $checksum; - } - - /** * {@inheritdoc} */ public function removeBin() { @@ -496,11 +379,7 @@ protected function ensureBinExists() { $database_schema = $this->connection->schema(); if (!$database_schema->tableExists($this->bin)) { $schema_definition = $this->schemaDefinition(); - $database_schema->createTable($this->bin, $schema_definition['bin']); - // If the bin doesn't exist, the cache tags table may also not exist. - if (!$database_schema->tableExists('cachetags')) { - $database_schema->createTable('cachetags', $schema_definition['cachetags']); - } + $database_schema->createTable($this->bin, $schema_definition); return TRUE; } } @@ -516,14 +395,16 @@ protected function ensureBinExists() { /** * Act on an exception when cache might be stale. * - * If the {cachetags} table does not yet exist, that's fine but if the table - * exists and yet the query failed, then the cache is stale and the - * exception needs to propagate. + * If the table does not yet exist, that's fine, but if the table exists and + * yet the query failed, then the cache is stale and the exception needs to + * propagate. * * @param $e * The exception. * @param string|null $table_name - * The table name, defaults to $this->bin. Can be cachetags. + * The table name. Defaults to $this->bin. + * + * @throws \Exception */ protected function catchException(\Exception $e, $table_name = NULL) { if ($this->connection->schema()->tableExists($table_name ?: $this->bin)) { @@ -552,10 +433,10 @@ protected function normalizeCid($cid) { } /** - * Defines the schema for the {cache_*} bin and {cachetags} tables. + * Defines the schema for the {cache_*} bin tables. */ public function schemaDefinition() { - $schema['bin'] = array( + $schema = array( 'description' => 'Storage for the cache API.', 'fields' => array( 'cid' => array( @@ -599,49 +480,18 @@ public function schemaDefinition() { 'size' => 'big', 'not null' => FALSE, ), - 'checksum_invalidations' => array( + 'checksum' => array( 'description' => 'The tag invalidation sum when this entry was saved.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), - 'checksum_deletions' => array( - 'description' => 'The tag deletion sum when this entry was saved.', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), ), 'indexes' => array( 'expire' => array('expire'), ), 'primary key' => array('cid'), ); - $schema['cachetags'] = array( - 'description' => 'Cache table for tracking cache tags related to the cache bin.', - 'fields' => array( - 'tag' => array( - 'description' => 'Namespace-prefixed tag string.', - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'invalidations' => array( - 'description' => 'Number incremented when the tag is invalidated.', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), - 'deletions' => array( - 'description' => 'Number incremented when the tag is deleted.', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), - ), - 'primary key' => array('tag'), - ); return $schema; } } diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php index 1d70164..59b0b22 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php @@ -19,12 +19,23 @@ class DatabaseBackendFactory implements CacheFactoryInterface { protected $connection; /** + * The cache tags checksum provider. + * + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface + */ + protected $checksumProvider; + + /** * Constructs the DatabaseBackendFactory object. * * @param \Drupal\Core\Database\Connection $connection + * Database connection + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. */ - function __construct(Connection $connection) { + function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider) { $this->connection = $connection; + $this->checksumProvider = $checksum_provider; } /** @@ -37,7 +48,7 @@ function __construct(Connection $connection) { * The cache backend object for the specified cache bin. */ function get($bin) { - return new DatabaseBackend($this->connection, $bin); + return new DatabaseBackend($this->connection, $this->checksumProvider, $bin); } } diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php new file mode 100644 index 0000000..4375b45 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php @@ -0,0 +1,207 @@ +connection = $connection; + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) { + try { + foreach ($tags as $tag) { + // Only invalidate tags once per request unless they are written again. + if (isset($this->invalidatedTags[$tag])) { + continue; + } + $this->invalidatedTags[$tag] = TRUE; + unset($this->tagCache[$tag]); + $this->connection->merge('cachetags') + ->insertFields(array('invalidations' => 1)) + ->expression('invalidations', 'invalidations + 1') + ->key('tag', $tag) + ->execute(); + } + } + catch (\Exception $e) { + // Create the cache table, which will be empty. This fixes cases during + // core install where cache tags are invalidated before the table is + // created. + if (!$this->ensureTableExists()) { + $this->catchException($e); + } + } + } + + /** + * {@inheritdoc} + */ + public function getCurrentChecksum(array $tags) { + // Remove tags that were already invalidated during this request from the + // static caches so that another invalidation can occur later in the same + // request. Without that, written cache items would not be invalidated + // correctly. + foreach ($tags as $tag) { + unset($this->invalidatedTags[$tag]); + } + return $this->calculateChecksum($tags); + } + + /** + * {@inheritdoc} + */ + public function isValid($checksum, array $tags) { + return $checksum == $this->calculateChecksum($tags); + } + + /** + * {@inheritdoc} + */ + public function calculateChecksum(array $tags) { + $checksum = 0; + + $query_tags = array_diff($tags, array_keys($this->tagCache)); + if ($query_tags) { + $db_tags = array(); + try { + $db_tags = $this->connection->query('SELECT tag, invalidations FROM {cachetags} WHERE tag IN (:tags)', array(':tags' => $query_tags)) + ->fetchAllKeyed(); + $this->tagCache += $db_tags; + } + catch (\Exception $e) { + // If the table does not exist yet, create. + if (!$this->ensureTableExists()) { + $this->catchException($e); + } + } + // Fill static cache with empty objects for tags not found in the database. + $this->tagCache += array_fill_keys(array_diff($query_tags, array_keys($db_tags)), 0); + } + + foreach ($tags as $tag) { + $checksum += $this->tagCache[$tag]; + } + + return $checksum; + } + + /** + * {@inheritdoc} + */ + public function reset() { + $this->tagCache = array(); + $this->invalidatedTags = array(); + } + + /** + * Check if the cache tags table exists and create it if not. + */ + protected function ensureTableExists() { + try { + $database_schema = $this->connection->schema(); + // Create the cache tags table if it does not exist. + if (!$database_schema->tableExists('cachetags')) { + $schema_definition = $this->schemaDefinition(); + $database_schema->createTable('cachetags', $schema_definition); + + return TRUE; + } + } + // If another process has already created the cachetags table, attempting to + // recreate it will throw an exception. In this case just catch the + // exception and do nothing. + catch (SchemaObjectExistsException $e) { + return TRUE; + } + return FALSE; + } + + /** + * Defines the schema for the {cachetags} table. + */ + public function schemaDefinition() { + $schema = array( + 'description' => 'Cache table for tracking cache tag invalidations.', + 'fields' => array( + 'tag' => array( + 'description' => 'Namespace-prefixed tag string.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'invalidations' => array( + 'description' => 'Number incremented when the tag is invalidated.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('tag'), + ); + return $schema; + } + + /** + * Act on an exception when cache might be stale. + * + * If the {cachetags} table does not yet exist, that's fine but if the table + * exists and yet the query failed, then the cache is stale and the + * exception needs to propagate. + * + * @param \Exception $e + * The exception. + * + * @throws \Exception + */ + protected function catchException(\Exception $e) { + if ($this->connection->schema()->tableExists('cachetags')) { + throw $e; + } + } + +} diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php index 23fddc5..5d7cfab 100644 --- a/core/lib/Drupal/Core/Cache/MemoryBackend.php +++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php @@ -17,7 +17,7 @@ * * @ingroup cache */ -class MemoryBackend implements CacheBackendInterface { +class MemoryBackend implements CacheBackendInterface, CacheTagsInvalidatorInterface { /** * Array to store cache objects. @@ -144,17 +144,6 @@ public function deleteMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). - */ - public function deleteTags(array $tags) { - foreach ($this->cache as $cid => $item) { - if (array_intersect($tags, $item->tags)) { - unset($this->cache[$cid]); - } - } - } - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll(). */ public function deleteAll() { @@ -180,7 +169,7 @@ public function invalidateMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). + * {@inheritdoc} */ public function invalidateTags(array $tags) { foreach ($this->cache as $cid => $item) { diff --git a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php index c9e288d..53e5b07 100644 --- a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php @@ -10,10 +10,20 @@ class MemoryBackendFactory implements CacheFactoryInterface { /** + * Instantiated memory cache bins. + * + * @var \Drupal\Core\Cache\MemoryBackend[] + */ + protected $bins = array(); + + /** * {@inheritdoc} */ function get($bin) { - return new MemoryBackend($bin); + if (!isset($this->bins[$bin])) { + $this->bins[$bin] = new MemoryBackend($bin); + } + return $this->bins[$bin]; } } diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php index d27bc13..852da7b 100644 --- a/core/lib/Drupal/Core/Cache/NullBackend.php +++ b/core/lib/Drupal/Core/Cache/NullBackend.php @@ -70,11 +70,6 @@ public function deleteMultiple(array $cids) {} public function deleteAll() {} /** - * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). - */ - public function deleteTags(array $tags) {} - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::invalidate(). */ public function invalidate($cid) {} @@ -85,11 +80,6 @@ public function invalidate($cid) {} public function invalidateMultiple(array $cids) {} /** - * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). - */ - public function invalidateTags(array $tags) {} - - /** * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateAll(). */ public function invalidateAll() {} diff --git a/core/lib/Drupal/Core/Cache/PhpBackend.php b/core/lib/Drupal/Core/Cache/PhpBackend.php index e188ffb..b665e86 100644 --- a/core/lib/Drupal/Core/Cache/PhpBackend.php +++ b/core/lib/Drupal/Core/Cache/PhpBackend.php @@ -36,13 +36,23 @@ class PhpBackend implements CacheBackendInterface { protected $cache = array(); /** + * The cache tags checksum provider. + * + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface + */ + protected $checksumProvider; + + /** * Constructs a PhpBackend object. * * @param string $bin * The cache bin for which the object is created. + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. */ - public function __construct($bin) { + public function __construct($bin, CacheTagsChecksumInterface $checksum_provider) { $this->bin = 'cache_' . $bin; + $this->checksumProvider = $checksum_provider; } /** @@ -122,6 +132,11 @@ protected function prepareItem($cache, $allow_invalid) { // Check expire time. $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; + // Check if invalidateTags() has been called with any of the item's tags. + if (!$this->checksumProvider->isValid($cache->checksum, $cache->tags)) { + $cache->valid = FALSE; + } + if (!$allow_invalid && !$cache->valid) { return FALSE; } @@ -140,6 +155,7 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array 'created' => round(microtime(TRUE), 3), 'expire' => $expire, 'tags' => array_unique($tags), + 'checksum' => $this->checksumProvider->getCurrentChecksum($tags), ); $this->writeItem($this->normalizeCid($cid), $item); } @@ -163,18 +179,6 @@ public function deleteMultiple(array $cids) { /** * {@inheritdoc} */ - public function deleteTags(array $tags) { - foreach ($this->storage()->listAll() as $cidhash) { - $item = $this->getByHash($cidhash); - if (is_object($item) && array_intersect($tags, $item->tags)) { - $this->delete($item->cid); - } - } - } - - /** - * {@inheritdoc} - */ public function deleteAll() { $this->storage()->deleteAll(); } @@ -211,18 +215,6 @@ public function invalidateMultiple(array $cids) { /** * {@inheritdoc} */ - public function invalidateTags(array $tags) { - foreach ($this->storage()->listAll() as $cidhash) { - $item = $this->getByHash($cidhash); - if ($item && array_intersect($tags, $item->tags)) { - $this->invalidate($item->cid); - } - } - } - - /** - * {@inheritdoc} - */ public function invalidateAll() { foreach($this->storage()->listAll() as $cidhash) { $this->invalidatebyHash($cidhash); diff --git a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php index 0801b72..dde93d4 100644 --- a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php @@ -10,6 +10,23 @@ class PhpBackendFactory implements CacheFactoryInterface { /** + * The cache tags checksum provider. + * + * @var \Drupal\Core\Cache\CacheTagsChecksumInterface + */ + protected $checksumProvider; + + /** + * Constructs a PhpBackendFactory object. + * + * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider + * The cache tags checksum provider. + */ + public function __construct(CacheTagsChecksumInterface $checksum_provider) { + $this->checksumProvider = $checksum_provider; + } + + /** * Gets PhpBackend for the specified cache bin. * * @param $bin @@ -19,7 +36,7 @@ class PhpBackendFactory implements CacheFactoryInterface { * The cache backend object for the specified cache bin. */ function get($bin) { - return new PhpBackend($bin); + return new PhpBackend($bin, $this->checksumProvider); } } diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php index b657f66..5023c35 100644 --- a/core/lib/Drupal/Core/Config/CachedStorage.php +++ b/core/lib/Drupal/Core/Config/CachedStorage.php @@ -131,7 +131,7 @@ public function write($name, array $data) { // While not all written data is read back, setting the cache instead of // just deleting it avoids cache rebuild stampedes. $this->cache->set($this->getCacheKey($name), $data); - Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); + Cache::invalidateTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); $this->findByPrefixCache = array(); return TRUE; } @@ -146,7 +146,7 @@ public function delete($name) { // rebuilding the cache before the storage is gone. if ($this->storage->delete($name)) { $this->cache->delete($this->getCacheKey($name)); - Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); + Cache::invalidateTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); $this->findByPrefixCache = array(); return TRUE; } @@ -162,7 +162,7 @@ public function rename($name, $new_name) { if ($this->storage->rename($name, $new_name)) { $this->cache->delete($this->getCacheKey($name)); $this->cache->delete($this->getCacheKey($new_name)); - Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); + Cache::invalidateTags(array($this::FIND_BY_PREFIX_CACHE_TAG)); $this->findByPrefixCache = array(); return TRUE; } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 7d7eded..cd9c9a7 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -671,7 +671,7 @@ public function clearCachedFieldDefinitions() { $this->fieldMapByFieldType = array(); $this->displayModeInfo = array(); $this->extraFields = array(); - Cache::deleteTags(array('entity_field_info')); + Cache::invalidateTags(array('entity_field_info')); // The typed data manager statically caches prototype objects with injected // definitions, clear those as well. $this->typedDataManager->clearCachedDefinitions(); @@ -682,7 +682,7 @@ public function clearCachedFieldDefinitions() { */ public function clearCachedBundles() { $this->bundleInfo = array(); - Cache::deleteTags(array('entity_bundles')); + Cache::invalidateTags(array('entity_bundles')); // Entity bundles are exposed as data types, clear that cache too. $this->typedDataManager->clearCachedDefinitions(); } diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 40a695e..7afae45 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity\Sql; use Drupal\Component\Utility\String; +use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Database\Database; @@ -574,7 +575,7 @@ public function resetCache(array $ids = NULL) { else { $this->entities = array(); if ($this->entityType->isPersistentlyCacheable()) { - $this->cacheBackend->deleteTags(array($this->entityTypeId . '_values')); + Cache::invalidateTags(array($this->entityTypeId . '_values')); } } } diff --git a/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php index 41b5a87..57cc618 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php @@ -57,7 +57,7 @@ public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface */ public function onRouterRebuild(Event $event) { $this->menuLinksRebuild(); - Cache::deleteTags(array('local_task')); + Cache::invalidateTags(array('local_task')); } /** diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 8beb184..89ad503 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -621,7 +621,7 @@ protected function resetSystem() { // @todo It feels wrong to have the requirement to clear the local tasks // cache here. - Cache::deleteTags(array('local_task')); + Cache::invalidateTags(array('local_task')); $this->themeRegistryRebuild(); } diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php index 6e93561..f9d86f0 100644 --- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php +++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php @@ -49,6 +49,12 @@ public function register(ContainerBuilder $container) { $container ->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper'); + // Remove the cache tags invalidator tag from the cache tags storage, so + // that we don't call it when cache tags are invalidated very early in the + // installer. + $container->getDefinition('cache_tags.invalidator.checksum') + ->clearTag('cache_tags_invalidator'); + // Replace the route builder with an empty implementation. // @todo Convert installer steps into routes; add an installer.routing.yml. $definition = $container->getDefinition('router.builder'); diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 5828d33..95928e4 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -161,7 +161,7 @@ public function clearCachedDefinitions() { if ($this->cacheBackend) { if ($this->cacheTags) { // Use the cache tags to clear the cache. - Cache::deleteTags($this->cacheTags); + Cache::invalidateTags($this->cacheTags); } else { $this->cacheBackend->delete($this->cacheKey); diff --git a/core/lib/Drupal/Core/Utility/Token.php b/core/lib/Drupal/Core/Utility/Token.php index 4cfc63f..dc7d162 100644 --- a/core/lib/Drupal/Core/Utility/Token.php +++ b/core/lib/Drupal/Core/Utility/Token.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Utility; +use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageInterface; @@ -346,7 +347,7 @@ public function setInfo(array $tokens) { */ public function resetInfo() { $this->tokenInfo = NULL; - $this->cache->deleteTags(array( + Cache::invalidateTags(array( static::TOKEN_INFO_CACHE_TAG => TRUE, )); } diff --git a/core/modules/book/src/BookManager.php b/core/modules/book/src/BookManager.php index 3f5cfdc..3659f8d 100644 --- a/core/modules/book/src/BookManager.php +++ b/core/modules/book/src/BookManager.php @@ -433,7 +433,7 @@ public function deleteFromBook($nid) { } $this->updateOriginalParent($original); $this->books = NULL; - \Drupal::cache('data')->deleteTags(array('bid:' . $original['bid'])); + Cache::invalidateTags(array('bid:' . $original['bid'])); } /** @@ -763,7 +763,7 @@ public function saveBookLink(array $link, $new) { foreach ($affected_bids as $bid) { $cache_tags[] = 'bid:' . $bid; } - \Drupal::cache('data')->deleteTags($cache_tags); + Cache::invalidateTags($cache_tags); return $link; } diff --git a/core/modules/config/src/Tests/Storage/CachedStorageTest.php b/core/modules/config/src/Tests/Storage/CachedStorageTest.php index 11c3599..66f6225 100644 --- a/core/modules/config/src/Tests/Storage/CachedStorageTest.php +++ b/core/modules/config/src/Tests/Storage/CachedStorageTest.php @@ -90,7 +90,8 @@ public function containerBuild(ContainerBuilder $container) { parent::containerBuild($container); // Use the regular database cache backend to aid testing. $container->register('cache_factory', 'Drupal\Core\Cache\DatabaseBackendFactory') - ->addArgument(new Reference('database')); + ->addArgument(new Reference('database')) + ->addArgument(new Reference('cache_tags.invalidator.checksum')); } } diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index 82cff29..9e09a46 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -986,7 +986,7 @@ function _locale_refresh_translations($langcodes, $lids = array()) { } } // Clear locale cache. - Cache::deleteTags(array('locale')); + Cache::invalidateTags(array('locale')); } /** diff --git a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php index 994eb38..83a967d 100644 --- a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php +++ b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php @@ -136,8 +136,8 @@ public function testStringTranslation() { $this->assertRaw($translation_to_en, 'English translation properly saved.'); // Reset the tag cache on the tester side in order to pick up the call to - // Cache::deleteTags() on the tested side. - drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache'); + // Cache::invalidateTags() on the tested side. + \Drupal::service('cache_tags.invalidator.checksum')->reset(); $this->assertTrue($name != $translation && t($name, array(), array('langcode' => $langcode)) == $translation, 't() works for non-English.'); // Refresh the locale() cache to get fresh data from t() below. We are in diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index 4109d83..cc15f13 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -1151,12 +1151,7 @@ protected function resetAll() { */ protected function refreshVariables() { // Clear the tag cache. - // @todo Replace drupal_static() usage within classes and provide a - // proper interface for invoking reset() on a cache backend: - // https://www.drupal.org/node/2311945. - drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache'); - drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::deletedTags'); - drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::invalidatedTags'); + \Drupal::service('cache_tags.invalidator.checksum')->reset(); foreach (Cache::getBins() as $backend) { if (is_callable(array($backend, 'reset'))) { $backend->reset(); diff --git a/core/modules/system/core.api.php b/core/modules/system/core.api.php index ad73fa0..78ffb9b 100644 --- a/core/modules/system/core.api.php +++ b/core/modules/system/core.api.php @@ -468,10 +468,10 @@ * - An array of values. For example, the "node" tag indicates that particular * node's data is present in the cache item, so its value is an array of node * IDs. - * Data that has been tagged can be deleted or invalidated as a group: no matter + * Data that has been tagged can be invalidated as a group: no matter * the Cache ID (cid) of the cache item, no matter in which cache bin a cache * item lives; as long as it is tagged with a certain cache tag, it will be - * deleted or invalidated. + * invalidated. * * Because of that, cache tags are a solution to the cache invalidation problem: * - For caching to be effective, each cache item must only be invalidated when @@ -495,8 +495,7 @@ * ); * \Drupal::cache()->set($cid, $data, CacheBackendInterface::CACHE_PERMANENT, $tags); * - * // Delete or invalidate all cache items with certain tags. - * \Drupal\Core\Cache\Cache::deleteTags(array('node:1')); + * // Invalidate all cache items with certain tags. * \Drupal\Core\Cache\Cache::invalidateTags(array('user:1')); * @endcode * @@ -513,8 +512,6 @@ * \Drupal\Core\Entity\Entity::invalidateTagsOnSave() and * \Drupal\Core\Entity\Entity::invalidateTagsOnDelete(). * - * @todo Update cache tag deletion in https://drupal.org/node/918538 - * * @section configuration Configuration * * By default cached data is stored in the database. This can be configured diff --git a/core/modules/system/src/Tests/Cache/ApcuBackendUnitTest.php b/core/modules/system/src/Tests/Cache/ApcuBackendUnitTest.php index da8f565..20fb3a4 100644 --- a/core/modules/system/src/Tests/Cache/ApcuBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/ApcuBackendUnitTest.php @@ -34,7 +34,7 @@ protected function checkRequirements() { } protected function createCacheBackend($bin) { - return new ApcuBackend($bin, $this->databasePrefix); + return new ApcuBackend($bin, $this->databasePrefix, \Drupal::service('cache_tags.invalidator.checksum')); } protected function tearDown() { diff --git a/core/modules/system/src/Tests/Cache/BackendChainUnitTest.php b/core/modules/system/src/Tests/Cache/BackendChainUnitTest.php index c19a8ae..4c90701 100644 --- a/core/modules/system/src/Tests/Cache/BackendChainUnitTest.php +++ b/core/modules/system/src/Tests/Cache/BackendChainUnitTest.php @@ -26,6 +26,8 @@ protected function createCacheBackend($bin) { ->prependBackend(new MemoryBackend('bar')) ->appendBackend(new MemoryBackend('baz')); + \Drupal::service('cache_tags.invalidator')->addInvalidator($chain); + return $chain; } diff --git a/core/modules/system/src/Tests/Cache/ChainedFastBackendUnitTest.php b/core/modules/system/src/Tests/Cache/ChainedFastBackendUnitTest.php index 32488a6..c34563c 100644 --- a/core/modules/system/src/Tests/Cache/ChainedFastBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/ChainedFastBackendUnitTest.php @@ -25,9 +25,13 @@ class ChainedFastBackendUnitTest extends GenericCacheBackendUnitTestBase { * A new ChainedFastBackend object. */ protected function createCacheBackend($bin) { - $consistent_backend = new DatabaseBackend($this->container->get('database'), $bin); - $fast_backend = new PhpBackend($bin); - return new ChainedFastBackend($consistent_backend, $fast_backend, $bin); + $consistent_backend = new DatabaseBackend(\Drupal::service('database'), \Drupal::service('cache_tags.invalidator.checksum'), $bin); + $fast_backend = new PhpBackend($bin, \Drupal::service('cache_tags.invalidator.checksum')); + $backend = new ChainedFastBackend($consistent_backend, $fast_backend, $bin); + // Explicitly register the cache bin as it can not work through the + // cache bin list in the container. + \Drupal::service('cache_tags.invalidator')->addInvalidator($backend); + return $backend; } } diff --git a/core/modules/system/src/Tests/Cache/DatabaseBackendTagTest.php b/core/modules/system/src/Tests/Cache/DatabaseBackendTagTest.php index e2b9d37..24cef4d 100644 --- a/core/modules/system/src/Tests/Cache/DatabaseBackendTagTest.php +++ b/core/modules/system/src/Tests/Cache/DatabaseBackendTagTest.php @@ -62,28 +62,4 @@ public function testTagInvalidations() { $this->assertEqual($invalidations_after, $invalidations_before + 1, 'Only one addition cache tag invalidation has occurred after invalidating a tag used in multiple bins.'); } - public function testTagDeletions() { - // Create cache entry in multiple bins. - $tags = array('test_tag:1', 'test_tag:2', 'test_tag:3'); - $bins = array('data', 'bootstrap', 'render'); - foreach ($bins as $bin) { - $bin = \Drupal::cache($bin); - $bin->set('test', 'value', Cache::PERMANENT, $tags); - $this->assertTrue($bin->get('test'), 'Cache item was set in bin.'); - } - - $deletions_before = intval(db_select('cachetags')->fields('cachetags', array('deletions'))->condition('tag', 'test_tag:2')->execute()->fetchField()); - Cache::deleteTags(array('test_tag:2')); - - // Test that cache entry has been deleted in multiple bins. - foreach ($bins as $bin) { - $bin = \Drupal::cache($bin); - $this->assertFalse($bin->get('test'), 'Tag invalidation affected item in bin.'); - } - - // Test that only one tag deletion has occurred. - $deletions_after = intval(db_select('cachetags')->fields('cachetags', array('deletions'))->condition('tag', 'test_tag:2')->execute()->fetchField()); - $this->assertEqual($deletions_after, $deletions_before + 1, 'Only one addition cache tag deletion has occurred after deleting a tag used in multiple bins.'); - } - } diff --git a/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php index bd2952e..e54198b 100644 --- a/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php @@ -30,7 +30,7 @@ class DatabaseBackendUnitTest extends GenericCacheBackendUnitTestBase { * A new DatabaseBackend object. */ protected function createCacheBackend($bin) { - return new DatabaseBackend($this->container->get('database'), $bin); + return new DatabaseBackend($this->container->get('database'), $this->container->get('cache_tags.invalidator.checksum'), $bin); } } diff --git a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php index d6f31bf..463be08 100644 --- a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php +++ b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php @@ -473,66 +473,6 @@ public function testDeleteMultiple() { } /** - * Tests Drupal\Core\Cache\CacheBackendInterface::deleteTags(). - */ - function testDeleteTags() { - $backend = $this->getCacheBackend(); - - // Create two cache entries with the same tag and tag value. - $backend->set('test_cid_invalidate1', $this->defaultValue, Cache::PERMANENT, array('test_tag:2')); - $backend->set('test_cid_invalidate2', $this->defaultValue, Cache::PERMANENT, array('test_tag:2')); - $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.'); - - // Delete test_tag of value 1. This should delete both entries. - $backend->deleteTags(array('test_tag:2')); - $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after deleting a cache tag.'); - $this->assertFalse($backend->get('test_cid_invalidate1', TRUE) || $backend->get('test_cid_invalidate2', TRUE), 'Two cache items deleted after deleting a cache tag.'); - - // Create two cache entries with the same tag and an array tag value. - $backend->set('test_cid_invalidate1', $this->defaultValue, Cache::PERMANENT, array('test_tag:1')); - $backend->set('test_cid_invalidate2', $this->defaultValue, Cache::PERMANENT, array('test_tag:1')); - $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.'); - - // Delete test_tag of value 1. This should delete both entries. - $backend->deleteTags(array('test_tag:1')); - $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after deleted a cache tag.'); - $this->assertFalse($backend->get('test_cid_invalidate1', TRUE) || $backend->get('test_cid_invalidate2', TRUE), 'Two cache items deleted after deleting a cache tag.'); - - // Create three cache entries with a mix of tags and tag values. - $backend->set('test_cid_invalidate1', $this->defaultValue, Cache::PERMANENT, array('test_tag:1')); - $backend->set('test_cid_invalidate2', $this->defaultValue, Cache::PERMANENT, array('test_tag:2')); - $backend->set('test_cid_invalidate3', $this->defaultValue, Cache::PERMANENT, array('test_tag_foo:3')); - $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2') && $backend->get('test_cid_invalidate3'), 'Three cached items were created.'); - $backend->deleteTags(array('test_tag_foo:3')); - $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Cached items not matching the tag were not deleted.'); - $this->assertFalse($backend->get('test_cid_invalidated3', TRUE), 'Cache item matching the tag was deleted.'); - - // Create cache entry in multiple bins. Two cache entries - // (test_cid_invalidate1 and test_cid_invalidate2) still exist from previous - // tests. - $tags = array('test_tag:1', 'test_tag:2', 'test_tag:3'); - $bins = array('path', 'bootstrap', 'page'); - foreach ($bins as $bin) { - $this->getCacheBackend($bin)->set('test', $this->defaultValue, Cache::PERMANENT, $tags); - $this->assertTrue($this->getCacheBackend($bin)->get('test'), 'Cache item was set in bin.'); - } - - // Delete tag in mulitple bins. - foreach ($bins as $bin) { - $this->getCacheBackend($bin)->deleteTags(array('test_tag:2')); - } - - // Test that cache entry has been deleted in multple bins. - foreach ($bins as $bin) { - $this->assertFalse($this->getCacheBackend($bin)->get('test', TRUE), 'Tag deletion affected item in bin.'); - } - // Test that the cache entry with a matching tag has been invalidated. - $this->assertFalse($this->getCacheBackend($bin)->get('test_cid_invalidate2', TRUE), 'Cache items matching tag were deleted.'); - // Test that the cache entry with without a matching tag still exists. - $this->assertTrue($this->getCacheBackend($bin)->get('test_cid_invalidate1'), 'Cache items not matching tag were not invalidated.'); - } - - /** * Test Drupal\Core\Cache\CacheBackendInterface::deleteAll(). */ public function testDeleteAll() { @@ -596,7 +536,7 @@ function testInvalidateTags() { $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.'); // Invalidate test_tag of value 1. This should invalidate both entries. - $backend->invalidateTags(array('test_tag:2')); + Cache::invalidateTags(array('test_tag:2')); $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after invalidating a cache tag.'); $this->assertTrue($backend->get('test_cid_invalidate1', TRUE) && $backend->get('test_cid_invalidate2', TRUE), 'Cache items not deleted after invalidating a cache tag.'); @@ -606,7 +546,7 @@ function testInvalidateTags() { $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.'); // Invalidate test_tag of value 1. This should invalidate both entries. - $backend->invalidateTags(array('test_tag:1')); + Cache::invalidateTags(array('test_tag:1')); $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two caches removed after invalidating a cache tag.'); $this->assertTrue($backend->get('test_cid_invalidate1', TRUE) && $backend->get('test_cid_invalidate2', TRUE), 'Cache items not deleted after invalidating a cache tag.'); @@ -615,7 +555,7 @@ function testInvalidateTags() { $backend->set('test_cid_invalidate2', $this->defaultValue, Cache::PERMANENT, array('test_tag:2')); $backend->set('test_cid_invalidate3', $this->defaultValue, Cache::PERMANENT, array('test_tag_foo:3')); $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2') && $backend->get('test_cid_invalidate3'), 'Three cached items were created.'); - $backend->invalidateTags(array('test_tag_foo:3')); + Cache::invalidateTags(array('test_tag_foo:3')); $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Cache items not matching the tag were not invalidated.'); $this->assertFalse($backend->get('test_cid_invalidated3'), 'Cached item matching the tag was removed.'); @@ -629,10 +569,7 @@ function testInvalidateTags() { $this->assertTrue($this->getCacheBackend($bin)->get('test'), 'Cache item was set in bin.'); } - // Invalidate tag in mulitple bins. - foreach ($bins as $bin) { - $this->getCacheBackend($bin)->invalidateTags(array('test_tag:2')); - } + Cache::invalidateTags(array('test_tag:2')); // Test that cache entry has been invalidated in multple bins. foreach ($bins as $bin) { diff --git a/core/modules/system/src/Tests/Cache/MemoryBackendUnitTest.php b/core/modules/system/src/Tests/Cache/MemoryBackendUnitTest.php index 85edfde..0dfeae7 100644 --- a/core/modules/system/src/Tests/Cache/MemoryBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/MemoryBackendUnitTest.php @@ -23,6 +23,8 @@ class MemoryBackendUnitTest extends GenericCacheBackendUnitTestBase { * A new MemoryBackend object. */ protected function createCacheBackend($bin) { - return new MemoryBackend($bin); + $backend = new MemoryBackend($bin); + \Drupal::service('cache_tags.invalidator')->addInvalidator($backend); + return $backend; } } diff --git a/core/modules/system/src/Tests/Cache/PhpBackendUnitTest.php b/core/modules/system/src/Tests/Cache/PhpBackendUnitTest.php index 57df19b..1751883 100644 --- a/core/modules/system/src/Tests/Cache/PhpBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/PhpBackendUnitTest.php @@ -23,7 +23,8 @@ class PhpBackendUnitTest extends GenericCacheBackendUnitTestBase { * A new MemoryBackend object. */ protected function createCacheBackend($bin) { - return new PhpBackend($bin); + $backend = new PhpBackend($bin, \Drupal::service('cache_tags.invalidator.checksum')); + return $backend; } } diff --git a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php index d0c0685..7b612ed 100644 --- a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php +++ b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php @@ -267,7 +267,7 @@ function testCacheClearByCacheTag() { // Log in admin_user and clear the caches for this user using a tag. $this->drupalLogin($this->admin_user); - Cache::deleteTags(array('user:' . $admin_user_id)); + Cache::invalidateTags(array('user:' . $admin_user_id)); // Assert that no toolbar cache exists for admin_user against the // language "en". diff --git a/core/modules/views/src/ViewsData.php b/core/modules/views/src/ViewsData.php index 796e94b..c90c69e 100644 --- a/core/modules/views/src/ViewsData.php +++ b/core/modules/views/src/ViewsData.php @@ -322,6 +322,6 @@ public function clear() { $this->storage = array(); $this->allStorage = array(); $this->fullyLoaded = FALSE; - Cache::deleteTags(array('views_data')); + Cache::invalidateTags(array('views_data')); } } diff --git a/core/modules/views/tests/src/Unit/ViewsDataTest.php b/core/modules/views/tests/src/Unit/ViewsDataTest.php index 0476ffd..9002420 100644 --- a/core/modules/views/tests/src/Unit/ViewsDataTest.php +++ b/core/modules/views/tests/src/Unit/ViewsDataTest.php @@ -26,6 +26,13 @@ class ViewsDataTest extends UnitTestCase { protected $cacheBackend; /** + * The mocked cache tags invalidator. + * + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheTagsInvalidator; + + /** * The mocked module handler. * * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject @@ -57,8 +64,9 @@ class ViewsDataTest extends UnitTestCase { * {@inheritdoc} */ protected function setUp() { + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); - $this->getContainerWithCacheBins($this->cacheBackend); + $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator); $configs = array(); $configs['views.settings']['skip_cache'] = FALSE; @@ -250,20 +258,21 @@ public function testFullAndTableGetCache() { $this->cacheBackend->expects($this->at(3)) ->method('set') ->with("views_data:$random_table_name:en", array()); + $this->cacheTagsInvalidator->expects($this->once()) + ->method('invalidateTags') + ->with(['views_data']); $this->cacheBackend->expects($this->at(4)) - ->method('deleteAll'); + ->method('get') + ->with("views_data:en") + ->will($this->returnValue(FALSE)); $this->cacheBackend->expects($this->at(5)) - ->method('get') - ->with("views_data:en") - ->will($this->returnValue(FALSE)); + ->method('set') + ->with("views_data:en", $expected_views_data); $this->cacheBackend->expects($this->at(6)) - ->method('set') - ->with("views_data:en", $expected_views_data); + ->method('get') + ->with("views_data:$random_table_name:en") + ->will($this->returnValue(FALSE)); $this->cacheBackend->expects($this->at(7)) - ->method('get') - ->with("views_data:$random_table_name:en") - ->will($this->returnValue(FALSE)); - $this->cacheBackend->expects($this->at(8)) ->method('set') ->with("views_data:$random_table_name:en", array()); diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 7c170dc..5c13075 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -472,7 +472,7 @@ function views_field_config_create(FieldConfigInterface $field) { * Implements hook_ENTITY_TYPE_update() for 'field_config'. */ function views_field_config_update(FieldConfigInterface $field) { - Cache::deleteTags(array('extension' => 'views')); + Cache::invalidateTags(array('extension' => 'views')); \Drupal::cache('render')->deleteAll(); } @@ -480,7 +480,7 @@ function views_field_config_update(FieldConfigInterface $field) { * Implements hook_ENTITY_TYPE_delete() for 'field_config'. */ function views_field_config_delete(FieldConfigInterface $field) { - Cache::deleteTags(array('extension' => 'views')); + Cache::invalidateTags(array('extension' => 'views')); \Drupal::cache('render')->deleteAll(); } @@ -489,7 +489,7 @@ function views_field_config_delete(FieldConfigInterface $field) { */ function views_invalidate_cache() { // Clear Views' info cache entries. - Cache::deleteTags(array('extension' => 'views')); + Cache::invalidateTags(array('extension' => 'views')); // Set the menu as needed to be rebuilt. \Drupal::service('router.builder_indicator')->setRebuildNeeded(); diff --git a/core/tests/Drupal/Tests/Core/Cache/BackendChainImplementationUnitTest.php b/core/tests/Drupal/Tests/Core/Cache/BackendChainImplementationUnitTest.php index f977695..6ab09c4 100644 --- a/core/tests/Drupal/Tests/Core/Cache/BackendChainImplementationUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/BackendChainImplementationUnitTest.php @@ -229,7 +229,7 @@ public function testDeleteTagsPropagation() { 'Two cache items were created in all backends.'); // Invalidate test_tag of value 1. This should invalidate both entries. - $this->chain->deleteTags(array('test_tag:2')); + $this->chain->invalidateTags(array('test_tag:2')); $this->assertSame(FALSE, $this->firstBackend->get('test_cid_clear1') && $this->firstBackend->get('test_cid_clear2') && $this->secondBackend->get('test_cid_clear1') @@ -250,7 +250,7 @@ public function testDeleteTagsPropagation() { 'Two cache items were created in all backends.'); // Invalidate test_tag of value 1. This should invalidate both entries. - $this->chain->deleteTags(array('test_tag:1')); + $this->chain->invalidateTags(array('test_tag:1')); $this->assertSame(FALSE, $this->firstBackend->get('test_cid_clear1') && $this->firstBackend->get('test_cid_clear2') && $this->secondBackend->get('test_cid_clear1') @@ -274,7 +274,7 @@ public function testDeleteTagsPropagation() { && $this->thirdBackend->get('test_cid_clear3'), 'Three cached items were created in all backends.'); - $this->chain->deleteTags(array('test_tag_foo:3')); + $this->chain->invalidateTags(array('test_tag_foo:3')); $this->assertNotSame(FALSE, $this->firstBackend->get('test_cid_clear1') && $this->firstBackend->get('test_cid_clear2') && $this->secondBackend->get('test_cid_clear1') diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php index cf5b3f1..7e91fcb 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php @@ -19,9 +19,16 @@ class CacheCollectorTest extends UnitTestCase { /** * The cache backend that should be used. * - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cache; + protected $cacheBackend; + + /** + * The cache tags invalidator. + * + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheTagsInvalidator; /** * The lock backend that should be used. @@ -48,12 +55,13 @@ class CacheCollectorTest extends UnitTestCase { * {@inheritdoc} */ protected function setUp() { - $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); $this->cid = $this->randomMachineName(); - $this->collector = new CacheCollectorHelper($this->cid, $this->cache, $this->lock); + $this->collector = new CacheCollectorHelper($this->cid, $this->cacheBackend, $this->lock); - $this->getContainerWithCacheBins($this->cache); + $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator); } @@ -90,7 +98,7 @@ public function testSetAndGetNull() { $key = $this->randomMachineName(); $value = NULL; - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('invalidate') ->with($this->cid); $this->collector->set($key, $value); @@ -115,7 +123,7 @@ public function testGetFromCache() { 'data' => array($key => $value), 'created' => REQUEST_TIME, ); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('get') ->with($this->cid) ->will($this->returnValue($cache)); @@ -137,7 +145,7 @@ public function testDelete() { $this->assertTrue($this->collector->has($key)); $this->assertEquals($value, $this->collector->get($key)); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('invalidate') ->with($this->cid); $this->collector->delete($key); @@ -151,7 +159,7 @@ public function testDelete() { public function testUpdateCacheNoChanges() { $this->lock->expects($this->never()) ->method('acquire'); - $this->cache->expects($this->never()) + $this->cacheBackend->expects($this->never()) ->method('set'); // Destruct the object to trigger the update data process. @@ -175,10 +183,10 @@ public function testUpdateCache() { ->method('acquire') ->with($this->cid . ':Drupal\Core\Cache\CacheCollector') ->will($this->returnValue(TRUE)); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('get') ->with($this->cid, FALSE); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('set') ->with($this->cid, array($key => $value), Cache::PERMANENT, array()); $this->lock->expects($this->once()) @@ -205,7 +213,7 @@ public function testUpdateCacheLockFail() { ->method('acquire') ->with($this->cid . ':Drupal\Core\Cache\CacheCollector') ->will($this->returnValue(FALSE)); - $this->cache->expects($this->never()) + $this->cacheBackend->expects($this->never()) ->method('set'); // Destruct the object to trigger the update data process. @@ -223,12 +231,12 @@ public function testUpdateCacheInvalidatedConflict() { 'data' => array($key => $value), 'created' => REQUEST_TIME, ); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with($this->cid) ->will($this->returnValue($cache)); - $this->cache->expects($this->at(1)) + $this->cacheBackend->expects($this->at(1)) ->method('invalidate') ->with($this->cid); $this->collector->set($key, 'new value'); @@ -244,11 +252,11 @@ public function testUpdateCacheInvalidatedConflict() { 'data' => array($key => $value), 'created' => REQUEST_TIME + 1, ); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with($this->cid) ->will($this->returnValue($cache)); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('delete') ->with($this->cid); $this->lock->expects($this->once()) @@ -280,11 +288,11 @@ public function testUpdateCacheMerge() { 'data' => array('other key' => 'other value'), 'created' => REQUEST_TIME + 1, ); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with($this->cid) ->will($this->returnValue($cache)); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('set') ->with($this->cid, array('other key' => 'other value', $key => $value), Cache::PERMANENT, array()); $this->lock->expects($this->once()) @@ -306,7 +314,7 @@ public function testUpdateCacheDelete() { 'data' => array($key => $value), 'created' => REQUEST_TIME, ); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with($this->cid) ->will($this->returnValue($cache)); @@ -322,10 +330,10 @@ public function testUpdateCacheDelete() { ->will($this->returnValue(TRUE)); // The second argument is set to TRUE because we triggered a cache // invalidation. - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with($this->cid, TRUE); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('set') ->with($this->cid, array(), Cache::PERMANENT, array()); $this->lock->expects($this->once()) @@ -373,11 +381,11 @@ public function testUpdateCacheClear() { $this->assertEquals(1, $this->collector->getCacheMisses()); // Clear the collected cache, should call it again. - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('delete') ->with($this->cid); - $this->cache->expects($this->never()) - ->method('deleteTags'); + $this->cacheTagsInvalidator->expects($this->never()) + ->method('invalidateTags'); $this->collector->clear(); $this->assertEquals($value, $this->collector->get($key)); $this->assertEquals(2, $this->collector->getCacheMisses()); @@ -390,7 +398,7 @@ public function testUpdateCacheClearTags() { $key = $this->randomMachineName(); $value = $this->randomMachineName(); $tags = array($this->randomMachineName()); - $this->collector = new CacheCollectorHelper($this->cid, $this->cache, $this->lock, $tags); + $this->collector = new CacheCollectorHelper($this->cid, $this->cacheBackend, $this->lock, $tags); // Set the data and request it. $this->collector->setCacheMissData($key, $value); @@ -401,10 +409,10 @@ public function testUpdateCacheClearTags() { $this->assertEquals(1, $this->collector->getCacheMisses()); // Clear the collected cache using the tags, should call it again. - $this->cache->expects($this->never()) + $this->cacheBackend->expects($this->never()) ->method('delete'); - $this->cache->expects($this->once()) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->once()) + ->method('invalidateTags') ->with($tags); $this->collector->clear(); $this->assertEquals($value, $this->collector->get($key)); diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheTagsInvalidatorTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheTagsInvalidatorTest.php new file mode 100644 index 0000000..1424b1e --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Cache/CacheTagsInvalidatorTest.php @@ -0,0 +1,68 @@ +invalidateTags(['node' => [2, 3, 5, 8, 13]]); + } + + /** + * @covers ::invalidateTags + * @covers ::addInvalidator + * @covers ::getBins + */ + public function testInvalidateTags() { + $cache_tags_invalidator = new CacheTagsInvalidator(); + + // This does not actually implement, + // \Drupal\Cache\Cache\CacheBackendInterface but we can not mock from two + // interfaces, we would need a test class for that. + $invalidator_cache_bin = $this->getMock('\Drupal\Core\Cache\CacheTagsInvalidator'); + $invalidator_cache_bin->expects($this->once()) + ->method('invalidateTags') + ->with(array('node:1')); + + // We do not have to define that invalidateTags() is never called as the + // interface does not define that method, trying to call it would result in + // a fatal error. + $non_invalidator_cache_bin = $this->getMock('\Drupal\Core\Cache\CacheBackendInterface'); + + $container = new Container(); + $container->set('cache.invalidator_cache_bin', $invalidator_cache_bin); + $container->set('cache.non_invalidator_cache_bin', $non_invalidator_cache_bin); + $container->setParameter('cache_bins', array('cache.invalidator_cache_bin' => 'invalidator_cache_bin', 'cache.non_invalidator_cache_bin' => 'non_invalidator_cache_bin')); + $cache_tags_invalidator->setContainer($container); + + $invalidator = $this->getMock('\Drupal\Core\Cache\CacheTagsInvalidator'); + $invalidator->expects($this->once()) + ->method('invalidateTags') + ->with(array('node:1')); + + $cache_tags_invalidator->addInvalidator($invalidator); + + $cache_tags_invalidator->invalidateTags(array('node:1')); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php index a425572..ea30f1a 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php @@ -117,24 +117,4 @@ public function testBuildTags($prefix, array $suffixes, array $expected) { $this->assertEquals($expected, Cache::buildTags($prefix, $suffixes)); } - /** - * @covers ::deleteTags - * - * @expectedException \LogicException - * @expectedExceptionMessage Cache tags must be strings, array given. - */ - public function testDeleteTags() { - Cache::deleteTags(['node' => [2, 3, 5, 8, 13]]); - } - - /** - * @covers ::invalidateTags - * - * @expectedException \LogicException - * @expectedExceptionMessage Cache tags must be strings, array given. - */ - public function testInvalidateTags() { - Cache::invalidateTags(['node' => [2, 3, 5, 8, 13]]); - } - } diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php index 2da84fe..0480f52 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php @@ -79,9 +79,9 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagsInvalidator; /** * The mocked typed config manager. @@ -121,7 +121,7 @@ protected function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); @@ -129,9 +129,8 @@ protected function setUp() { $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); + $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator); $container->set('config.typed', $this->typedConfigManager); - $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId)); @@ -361,7 +360,7 @@ public function testEnable() { * @depends testSetStatus */ public function testDisable() { - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array($this->entityTypeId . ':' . $this->id)); diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php index ddfbd81..24ce7d2 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php @@ -85,9 +85,9 @@ class ConfigEntityStorageTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagsInvalidator; /** * The mocked typed config manager. @@ -153,7 +153,7 @@ protected function setUp() { ->with('test_entity_type') ->will($this->returnValue($this->entityType)); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); $this->typedConfigManager->expects($this->any()) @@ -162,8 +162,7 @@ protected function setUp() { $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('config.typed', $this->typedConfigManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator); \Drupal::setContainer($container); } @@ -173,7 +172,7 @@ protected function setUp() { * @covers ::doCreate */ public function testCreateWithPredefinedUuid() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->moduleHandler->expects($this->at(0)) @@ -198,7 +197,7 @@ public function testCreateWithPredefinedUuid() { * @return \Drupal\Core\Entity\EntityInterface */ public function testCreate() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->moduleHandler->expects($this->at(0)) @@ -240,7 +239,7 @@ public function testSaveInsert(EntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. @@ -299,7 +298,7 @@ public function testSaveUpdate(EntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':foo', // Own cache tag. @@ -359,7 +358,7 @@ public function testSaveRename(ConfigEntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId .':bar', // Own cache tag. @@ -403,7 +402,7 @@ public function testSaveRename(ConfigEntityInterface $entity) { * @expectedExceptionMessage The entity does not have an ID. */ public function testSaveInvalid() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $entity = $this->getMockEntity(); @@ -428,7 +427,7 @@ public function testSaveDuplicate() { $config_object->expects($this->never()) ->method('save'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->once()) @@ -459,7 +458,7 @@ public function testSaveMismatch() { $config_object->expects($this->never()) ->method('save'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->once()) @@ -492,7 +491,7 @@ public function testSaveNoMismatch() { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. @@ -542,7 +541,7 @@ public function testSaveChangedUuid() { array('id', 'foo'), ))); - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->at(1)) @@ -699,7 +698,7 @@ public function testLoadRevision() { * @covers ::deleteRevision */ public function testDeleteRevision() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->assertSame(NULL, $this->entityStorage->deleteRevision(1)); @@ -725,7 +724,7 @@ public function testDelete() { $config_map[] = array("the_config_prefix.$id", $config_object); } - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':bar', // Own cache tag. @@ -775,7 +774,7 @@ public function testDeleteNothing() { $this->configFactory->expects($this->never()) ->method('get'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); $this->entityStorage->delete(array()); diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index fa7c14b..d3d4036 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -63,7 +63,14 @@ class EntityManagerTest extends UnitTestCase { * * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cache; + protected $cacheBackend; + + /** + * The cache tags invalidator. + * + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheTagsInvalidator; /** * The language manager. @@ -119,7 +126,8 @@ protected function setUp() { ->with('entity_type_build') ->will($this->returnValue(array())); - $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $language = $this->getMock('Drupal\Core\Language\LanguageInterface'); $language->expects($this->any()) @@ -139,7 +147,7 @@ protected function setUp() { $this->formBuilder = $this->getMock('Drupal\Core\Form\FormBuilderInterface'); $this->controllerResolver = $this->getClassResolverStub(); - $this->container = $this->getContainerWithCacheBins($this->cache); + $this->container = $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator); $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface'); @@ -180,7 +188,7 @@ protected function setUpEntityManager($definitions = array()) { ->method('getDefinitions') ->will($this->returnValue($definitions)); - $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->cache, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions, $this->eventDispatcher); + $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->cacheBackend, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions, $this->eventDispatcher); $this->entityManager->setContainer($this->container); $this->entityManager->setDiscovery($this->discovery); } @@ -193,14 +201,14 @@ protected function setUpEntityManager($definitions = array()) { */ public function testClearCachedDefinitions() { $this->setUpEntityManager(); - $this->cache->expects($this->at(0)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(0)) + ->method('invalidateTags') ->with(array('entity_types')); - $this->cache->expects($this->at(1)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(1)) + ->method('invalidateTags') ->with(array('entity_bundles')); - $this->cache->expects($this->at(2)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(2)) + ->method('invalidateTags') ->with(array('entity_field_info')); $this->entityManager->clearCachedDefinitions(); @@ -524,21 +532,21 @@ public function testGetBaseFieldDefinitionsWithCaching() { $expected = array('id' => $field_definition); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(1)) + $this->cacheBackend->expects($this->at(1)) ->method('get') ->with('entity_type', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(2)) + $this->cacheBackend->expects($this->at(2)) ->method('set') ->with('entity_type'); - $this->cache->expects($this->at(3)) + $this->cacheBackend->expects($this->at(3)) ->method('set') ->with('entity_base_field_definitions:test_entity_type:en'); - $this->cache->expects($this->at(4)) + $this->cacheBackend->expects($this->at(4)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => $expected))); @@ -558,27 +566,27 @@ public function testGetFieldDefinitionsWithCaching() { $expected = array('id' => $field_definition); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => $expected))); - $this->cache->expects($this->at(1)) + $this->cacheBackend->expects($this->at(1)) ->method('get') ->with('entity_bundle_field_definitions:test_entity_type:test_bundle:en', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(2)) + $this->cacheBackend->expects($this->at(2)) ->method('get') ->with('entity_type', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(3)) + $this->cacheBackend->expects($this->at(3)) ->method('set'); - $this->cache->expects($this->at(4)) + $this->cacheBackend->expects($this->at(4)) ->method('set'); - $this->cache->expects($this->at(5)) + $this->cacheBackend->expects($this->at(5)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => $expected))); - $this->cache->expects($this->at(6)) + $this->cacheBackend->expects($this->at(6)) ->method('get') ->with('entity_bundle_field_definitions:test_entity_type:test_bundle:en', FALSE) ->will($this->returnValue((object) array('data' => $expected))); @@ -617,29 +625,29 @@ public function testGetFieldStorageDefinitionsWithCaching() { 'field_storage' => $field_storage_definition, ); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => array('id' => $expected['id'])))); - $this->cache->expects($this->at(1)) + $this->cacheBackend->expects($this->at(1)) ->method('get') ->with('entity_field_storage_definitions:test_entity_type:en', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(2)) + $this->cacheBackend->expects($this->at(2)) ->method('get') ->with('entity_type', FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(3)) + $this->cacheBackend->expects($this->at(3)) ->method('set') ->with('entity_type'); - $this->cache->expects($this->at(4)) + $this->cacheBackend->expects($this->at(4)) ->method('set') ->with('entity_field_storage_definitions:test_entity_type:en'); - $this->cache->expects($this->at(5)) + $this->cacheBackend->expects($this->at(5)) ->method('get') ->with('entity_base_field_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => array('id' => $expected['id'])))); - $this->cache->expects($this->at(6)) + $this->cacheBackend->expects($this->at(6)) ->method('get') ->with('entity_field_storage_definitions:test_entity_type:en', FALSE) ->will($this->returnValue((object) array('data' => $expected))); @@ -771,8 +779,8 @@ protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $f */ public function testClearCachedFieldDefinitions() { $this->setUpEntityManager(); - $this->cache->expects($this->once()) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->once()) + ->method('invalidateTags') ->with(array('entity_field_info')); $this->typedDataManager->expects($this->once()) ->method('clearCachedDefinitions'); @@ -787,8 +795,8 @@ public function testClearCachedFieldDefinitions() { */ public function testClearCachedBundles() { $this->setUpEntityManager(); - $this->cache->expects($this->once()) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->once()) + ->method('invalidateTags') ->with(array('entity_bundles')); $this->entityManager->clearCachedBundles(); @@ -859,30 +867,30 @@ public function testGetAllBundleInfo() { 'apple' => $apple, 'banana' => $banana, )); - $this->cache->expects($this->at(0)) + $this->cacheBackend->expects($this->at(0)) ->method('get') ->with("entity_bundle_info:en", FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(1)) + $this->cacheBackend->expects($this->at(1)) ->method('get') ->with("entity_type", FALSE) ->will($this->returnValue(FALSE)); - $this->cache->expects($this->at(2)) + $this->cacheBackend->expects($this->at(2)) ->method('set') ->with("entity_type"); - $this->cache->expects($this->at(3)) + $this->cacheBackend->expects($this->at(3)) ->method('set') ->with("entity_bundle_info:en"); - $this->cache->expects($this->at(4)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(0)) + ->method('invalidateTags') ->with(array('entity_types')); - $this->cache->expects($this->at(5)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(1)) + ->method('invalidateTags') ->with(array('entity_bundles')); - $this->cache->expects($this->at(6)) - ->method('deleteTags') + $this->cacheTagsInvalidator->expects($this->at(2)) + ->method('invalidateTags') ->with(array('entity_field_info')); - $this->cache->expects($this->at(7)) + $this->cacheBackend->expects($this->at(4)) ->method('get') ->with("entity_bundle_info:en", FALSE) ->will($this->returnValue((object) array('data' => 'cached data'))); @@ -1015,7 +1023,7 @@ function testgetExtraFields() { ->method('getCurrentLanguage') ->will($this->returnValue($language)); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('get') ->with($cache_id); @@ -1027,7 +1035,7 @@ function testgetExtraFields() { ->method('alter') ->with('entity_extra_field_info', $hook_bundle_extra_fields); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('set') ->with($cache_id, $processed_hook_bundle_extra_fields[$entity_type_id][$bundle]); @@ -1167,7 +1175,7 @@ public function testGetFieldMapFromCache() { ) ); $this->setUpEntityManager(); - $this->cache->expects($this->once()) + $this->cacheBackend->expects($this->once()) ->method('get') ->with('entity_field_map') ->will($this->returnValue((object) array('data' => $expected))); diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php index 6535732..3f4029d 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php @@ -73,11 +73,11 @@ class EntityUnitTest extends UnitTestCase { protected $languageManager; /** - * The mocked cache backend. + * The mocked cache tags invalidator. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagsInvalidator; /** * The entity values. @@ -116,14 +116,13 @@ protected function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidator'); $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\Entity', array($this->values, $this->entityTypeId)); @@ -393,12 +392,12 @@ public function testPreSave() { * @covers ::postSave */ public function testPostSave() { - $this->cacheBackend->expects($this->at(0)) + $this->cacheTagsInvalidator->expects($this->at(0)) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. )); - $this->cacheBackend->expects($this->at(1)) + $this->cacheTagsInvalidator->expects($this->at(1)) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':' . $this->values['id'], // Own cache tag. @@ -450,7 +449,7 @@ public function testPreDelete() { * @covers ::postDelete */ public function testPostDelete() { - $this->cacheBackend->expects($this->once()) + $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':' . $this->values['id'], diff --git a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php index ee10e54..79c5999 100644 --- a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php @@ -68,11 +68,11 @@ class KeyValueEntityStorageTest extends UnitTestCase { protected $entityManager; /** - * The mocked cache backend. + * The mocked cache tags invalidator. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagsInvalidator; /** * {@inheritdoc} @@ -110,7 +110,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') { ->with('test_entity_type') ->will($this->returnValue($this->entityType)); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); $this->keyValueStore = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface'); $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); @@ -130,8 +130,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') { $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator); \Drupal::setContainer($container); } diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php index 0a58e81..2c9a015 100644 --- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php @@ -121,8 +121,8 @@ protected function setUp() { $logger = $this->getMock('Psr\Log\LoggerInterface'); $this->themeHandler = new TestThemeHandler($this->root, $this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $logger, $this->cssCollectionOptimizer, $this->configInstaller, $this->configManager, $this->routeBuilderIndicator, $this->extensionDiscovery); - $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); - $this->getContainerWithCacheBins($cache_backend); + $cache_tags_invalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); + $this->getContainerWithCacheTagsInvalidator($cache_tags_invalidator); } /** diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php index c2ef841..9cd9375 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php @@ -190,18 +190,17 @@ public function testDefaultPluginManagerWithFilledCache() { */ public function testCacheClearWithTags() { $cid = $this->randomMachineName(); - $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend') - ->disableOriginalConstructor() - ->getMock(); - $cache_backend + $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $cache_tags_invalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface'); + $cache_tags_invalidator ->expects($this->once()) - ->method('deleteTags') + ->method('invalidateTags') ->with(array('tag')); $cache_backend ->expects($this->never()) ->method('deleteMultiple'); - $this->getContainerWithCacheBins($cache_backend); + $this->getContainerWithCacheTagsInvalidator($cache_tags_invalidator); $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface'); $plugin_manager->setCacheBackend($cache_backend, $cid, array('tag')); diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index 43748e8..1a0ac77 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -8,8 +8,7 @@ namespace Drupal\Tests; use Drupal\Component\Utility\Random; -use Drupal\Component\Utility\String; -use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; /** @@ -197,24 +196,20 @@ public function getStringTranslationStub() { } /** - * Sets up a container with cache bins. + * Sets up a container with a cache tags invalidator. * - * @param \Drupal\Core\Cache\CacheBackendInterface $backend - * The cache backend to set up. + * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_validator + * The cache tags invalidator. * * @return \Symfony\Component\DependencyInjection\ContainerInterface|\PHPUnit_Framework_MockObject_MockObject - * The container with the cache bins set up. + * The container with the cache tags invalidator service. */ - protected function getContainerWithCacheBins(CacheBackendInterface $backend) { + protected function getContainerWithCacheTagsInvalidator(CacheTagsInvalidatorInterface $cache_tags_validator) { $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); $container->expects($this->any()) - ->method('getParameter') - ->with('cache_bins') - ->will($this->returnValue(array('cache.test' => 'test'))); - $container->expects($this->any()) ->method('get') - ->with('cache.test') - ->will($this->returnValue($backend)); + ->with('cache_tags.invalidator') + ->will($this->returnValue($cache_tags_validator)); \Drupal::setContainer($container); return $container;