trait CacheTagsChecksumTrait
Same name in other branches
- 8.9.x core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php \Drupal\Core\Cache\CacheTagsChecksumTrait
- 10 core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php \Drupal\Core\Cache\CacheTagsChecksumTrait
- 11.x core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php \Drupal\Core\Cache\CacheTagsChecksumTrait
A trait for cache tag checksum implementations.
Handles delayed cache tag invalidations.
Hierarchy
- trait \Drupal\Core\Cache\CacheTagsChecksumTrait
File
-
core/
lib/ Drupal/ Core/ Cache/ CacheTagsChecksumTrait.php, line 10
Namespace
Drupal\Core\CacheView source
trait CacheTagsChecksumTrait {
/**
* A list of tags that have already been invalidated in this request.
*
* Used to prevent the invalidation of the same cache tag multiple times.
*
* @var bool[]
*/
protected $invalidatedTags = [];
/**
* The set of cache tags whose invalidation is delayed.
*
* @var string[]
*/
protected $delayedTags = [];
/**
* Contains already loaded tag invalidation counts from the storage.
*
* @var int[]
*/
protected $tagCache = [];
/**
* Callback to be invoked just after a database transaction gets committed.
*
* Executes all delayed tag invalidations.
*
* @param bool $success
* Whether or not the transaction was successful.
*/
public function rootTransactionEndCallback($success) {
if ($success) {
$this->doInvalidateTags($this->delayedTags);
}
$this->delayedTags = [];
}
/**
* Implements \Drupal\Core\Cache\CacheTagsInvalidatorInterface::invalidateTags()
*/
public function invalidateTags(array $tags) {
// Only invalidate tags once per request unless they are written again.
foreach ($tags as $key => $tag) {
if (isset($this->invalidatedTags[$tag])) {
unset($tags[$key]);
}
else {
$this->invalidatedTags[$tag] = TRUE;
unset($this->tagCache[$tag]);
}
}
if (!$tags) {
return;
}
$in_transaction = $this->getDatabaseConnection()
->inTransaction();
if ($in_transaction) {
if (empty($this->delayedTags)) {
$this->getDatabaseConnection()
->addRootTransactionEndCallback([
$this,
'rootTransactionEndCallback',
]);
}
$this->delayedTags = Cache::mergeTags($this->delayedTags, $tags);
}
else {
$this->doInvalidateTags($tags);
}
}
/**
* Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::getCurrentChecksum()
*/
public function getCurrentChecksum(array $tags) {
// Any cache writes in this request containing cache tags whose invalidation
// has been delayed due to an in-progress transaction must not be read by
// any other request, so use a nonsensical checksum which will cause any
// written cache items to be ignored.
if (!empty(array_intersect($tags, $this->delayedTags))) {
return CacheTagsChecksumInterface::INVALID_CHECKSUM_WHILE_IN_TRANSACTION;
}
// 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);
}
/**
* Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::isValid()
*/
public function isValid($checksum, array $tags) {
// Any cache reads in this request involving cache tags whose invalidation
// has been delayed due to an in-progress transaction are not allowed to use
// data stored in cache; it must be assumed to be stale. This forces those
// results to be computed instead. Together with the logic in
// ::getCurrentChecksum(), it also prevents that computed data from being
// written to the cache.
if (!empty(array_intersect($tags, $this->delayedTags))) {
return FALSE;
}
return $checksum == $this->calculateChecksum($tags);
}
/**
* Calculates the current checksum for a given set of tags.
*
* @param string[] $tags
* The array of tags to calculate the checksum for.
*
* @return int
* The calculated checksum.
*/
protected function calculateChecksum(array $tags) {
$checksum = 0;
$query_tags = array_diff($tags, array_keys($this->tagCache));
if ($query_tags) {
$tag_invalidations = $this->getTagInvalidationCounts($query_tags);
$this->tagCache += $tag_invalidations;
// Fill static cache with empty objects for tags not found in the storage.
$this->tagCache += array_fill_keys(array_diff($query_tags, array_keys($tag_invalidations)), 0);
}
foreach ($tags as $tag) {
$checksum += $this->tagCache[$tag];
}
return $checksum;
}
/**
* Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::reset()
*/
public function reset() {
$this->tagCache = [];
$this->invalidatedTags = [];
}
/**
* Fetches invalidation counts for cache tags.
*
* @param string[] $tags
* The list of tags to fetch invalidations for.
*
* @return int[]
* List of invalidation counts keyed by the respective cache tag.
*
* @throws \Exception
* Thrown if the table could not be created or the database connection
* failed.
*/
protected abstract function getTagInvalidationCounts(array $tags);
/**
* Returns the database connection.
*
* @return \Drupal\Core\Database\Connection
* The database connection.
*/
protected abstract function getDatabaseConnection();
/**
* Marks cache items with any of the specified tags as invalid.
*
* @param string[] $tags
* The set of tags for which to invalidate cache items.
*
* @throws \Exception
* Thrown if the table could not be created or the database connection
* failed.
*/
protected abstract function doInvalidateTags(array $tags);
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overrides |
---|---|---|---|---|
CacheTagsChecksumTrait::$delayedTags | protected | property | The set of cache tags whose invalidation is delayed. | |
CacheTagsChecksumTrait::$invalidatedTags | protected | property | A list of tags that have already been invalidated in this request. | |
CacheTagsChecksumTrait::$tagCache | protected | property | Contains already loaded tag invalidation counts from the storage. | |
CacheTagsChecksumTrait::calculateChecksum | protected | function | Calculates the current checksum for a given set of tags. | |
CacheTagsChecksumTrait::doInvalidateTags | abstract protected | function | Marks cache items with any of the specified tags as invalid. | 1 |
CacheTagsChecksumTrait::getCurrentChecksum | public | function | Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::getCurrentChecksum() | |
CacheTagsChecksumTrait::getDatabaseConnection | abstract protected | function | Returns the database connection. | 1 |
CacheTagsChecksumTrait::getTagInvalidationCounts | abstract protected | function | Fetches invalidation counts for cache tags. | 1 |
CacheTagsChecksumTrait::invalidateTags | public | function | Implements \Drupal\Core\Cache\CacheTagsInvalidatorInterface::invalidateTags() | |
CacheTagsChecksumTrait::isValid | public | function | Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::isValid() | |
CacheTagsChecksumTrait::reset | public | function | Implements \Drupal\Core\Cache\CacheTagsChecksumInterface::reset() | |
CacheTagsChecksumTrait::rootTransactionEndCallback | public | function | Callback to be invoked just after a database transaction gets committed. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.