diff --git a/core/lib/Drupal/Core/Update/UpdateBackend.php b/core/lib/Drupal/Core/Update/UpdateBackend.php index 08e4cfd1f6..e144bfc4eb 100644 --- a/core/lib/Drupal/Core/Update/UpdateBackend.php +++ b/core/lib/Drupal/Core/Update/UpdateBackend.php @@ -2,8 +2,10 @@ namespace Drupal\Core\Update; +use Drupal\Component\Assertion\Inspector; +use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Cache\MemoryBackend; +use Drupal\Core\Cache\CacheTagsInvalidatorInterface; /** * Defines a cache backend for use during updating Drupal. @@ -11,7 +13,12 @@ * Passes on deletes to another backend while using a memory backend to avoid * using anything cached prior to running updates. */ -class UpdateBackend extends MemoryBackend { +class UpdateBackend implements CacheBackendInterface, CacheTagsInvalidatorInterface { + + /** + * Array to store cache objects. + */ + protected static $cache = []; /** * The regular runtime cache backend. @@ -20,21 +27,126 @@ class UpdateBackend extends MemoryBackend { */ protected $backend; + /** + * @var string + */ + protected $bin; + /** * UpdateBackend constructor. * * @param \Drupal\Core\Cache\CacheBackendInterface $backend * The regular runtime cache backend. + * @param $bin + * The cache bin name. */ - public function __construct(CacheBackendInterface $backend) { + public function __construct(CacheBackendInterface $backend, $bin) { $this->backend = $backend; + $this->bin = $bin; + if (!isset(static::$cache[$this->bin])) { + static::$cache[$this->bin] = []; + } + } + + /** + * {@inheritdoc} + */ + public function get($cid, $allow_invalid = FALSE) { + if (isset(static::$cache[$this->bin][$cid])) { + return $this->prepareItem(static::$cache[$this->bin][$cid], $allow_invalid); + } + else { + return FALSE; + } + } + + /** + * {@inheritdoc} + */ + public function getMultiple(&$cids, $allow_invalid = FALSE) { + $ret = []; + + $items = array_intersect_key(static::$cache[$this->bin], array_flip($cids)); + + foreach ($items as $item) { + $item = $this->prepareItem($item, $allow_invalid); + if ($item) { + $ret[$item->cid] = $item; + } + } + + $cids = array_diff($cids, array_keys($ret)); + + return $ret; + } + + /** + * Prepares a cached item. + * + * Checks that items are either permanent or did not expire, and returns data + * as appropriate. + * + * @param array $cache + * An item loaded from self::get() or self::getMultiple(). + * @param bool $allow_invalid + * (optional) If TRUE, cache items may be returned even if they have expired + * or been invalidated. + * + * @return object|false + * The item with data as appropriate or FALSE if there is no + * valid item to load. + */ + protected function prepareItem(array $cache, $allow_invalid) { + if (!isset($cache['data'])) { + return FALSE; + } + $prepared = (object) $cache; + $prepared->data = unserialize($prepared->data); + + // Check expire time. + $prepared->valid = $prepared->expire == Cache::PERMANENT || $prepared->expire >= $this->getRequestTime(); + + if (!$allow_invalid && !$prepared->valid) { + return FALSE; + } + + return $prepared; + } + + /** + * {@inheritdoc} + */ + public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = []) { + assert(Inspector::assertAllStrings($tags), 'Cache Tags must be strings.'); + $tags = array_unique($tags); + // Sort the cache tags so that they are stored consistently in the database. + sort($tags); + + // Do not create an object at this point to minimize the number of objects + // garbage collection has to keep a track off. + static::$cache[$this->bin][$cid] = [ + 'cid' => $cid, + 'data' => serialize($data), + 'created' => $this->getRequestTime(), + 'expire' => $expire, + 'tags' => $tags, + ]; + } + + /** + * {@inheritdoc} + */ + public function setMultiple(array $items = []) { + foreach ($items as $cid => $item) { + $this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT, isset($item['tags']) ? $item['tags'] : []); + } } /** * {@inheritdoc} */ public function delete($cid) { - parent::delete($cid); + unset(static::$cache[$this->bin][$cid]); $this->backend->delete($cid); } @@ -42,7 +154,7 @@ public function delete($cid) { * {@inheritdoc} */ public function deleteMultiple(array $cids) { - parent::deleteMultiple($cids); + static::$cache[$this->bin] = array_diff_key(static::$cache[$this->bin], array_flip($cids)); $this->backend->deleteMultiple($cids); } @@ -50,8 +162,85 @@ public function deleteMultiple(array $cids) { * {@inheritdoc} */ public function deleteAll() { - parent::deleteAll(); + static::$cache[$this->bin] = []; $this->backend->deleteAll(); } + /** + * {@inheritdoc} + */ + public function invalidate($cid) { + if (isset(static::$cache[$this->bin][$cid])) { + static::$cache[$this->bin][$cid]['expire'] = $this->getRequestTime() - 1; + } + } + + /** + * {@inheritdoc} + */ + public function invalidateMultiple(array $cids) { + $items = array_intersect_key(static::$cache[$this->bin], array_flip($cids)); + foreach ($items as $cid => $item) { + static::$cache[$this->bin][$cid]['expire'] = $this->getRequestTime() - 1; + } + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) { + foreach (static::$cache[$this->bin] as $cid => $item) { + if (array_intersect($tags, $item['tags'])) { + static::$cache[$this->bin][$cid]['expire'] = $this->getRequestTime() - 1; + } + } + } + + /** + * {@inheritdoc} + */ + public function invalidateAll() { + foreach (static::$cache[$this->bin] as $cid => $item) { + static::$cache[$this->bin][$cid]['expire'] = $this->getRequestTime() - 1; + } + } + + /** + * {@inheritdoc} + */ + public function garbageCollection() { + } + + /** + * {@inheritdoc} + */ + public function removeBin() { + static::$cache[$this->bin] = []; + } + + /** + * Wrapper method for REQUEST_TIME constant. + * + * @return int + */ + protected function getRequestTime() { + return defined('REQUEST_TIME') ? REQUEST_TIME : (int) $_SERVER['REQUEST_TIME']; + } + + /** + * Prevents data stored in memory backends from being serialized. + */ + public function __sleep() { + return []; + } + + /** + * Reset statically cached variables. + * + * This is only used by tests. + */ + public function reset() { + static::$cache = []; + } + } diff --git a/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php b/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php index e3f7dd12f1..1296e313c2 100644 --- a/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php +++ b/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php @@ -43,7 +43,7 @@ public function __construct(CacheFactoryInterface $cache_factory) { */ public function get($bin) { if (!isset($this->bins[$bin])) { - $this->bins[$bin] = new UpdateBackend($this->cacheFactory->get($bin)); + $this->bins[$bin] = new UpdateBackend($this->cacheFactory->get($bin), $bin); } return $this->bins[$bin]; } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index a4d467d253..acaff5c51f 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1843,6 +1843,10 @@ function system_update_8013() { $system_cron_config ->clear('threshold.autorun') ->save(TRUE); + + $config_factory = \Drupal::configFactory(); + $system_cron_config = $config_factory->getEditable('system.cron'); + $system_cron_config->save(TRUE); } /**