diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 55a3875..1e3a021 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2471,7 +2471,7 @@ function drupal_container(Container $new_container = NULL) { * @return Drupal\Core\KeyValueStore\KeyValueStoreInterface */ function state() { - return drupal_container()->get('keyvalue')->get('state'); + return drupal_container()->get('state'); } /** diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index e1147ac..9b9b5d1 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -75,9 +75,13 @@ public function build(ContainerBuilder $container) { ->register('keyvalue.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseFactory') ->addArgument(new Reference('database')); + $container->register('state', 'Drupal\Core\KeyValueStore\KeyValueCacheDecorator') + ->addArgument(new Reference('keyvalue')) + ->addArgument('state'); + $container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager') ->addArgument(new Reference('database')) - ->addArgument(new Reference('keyvalue')); + ->addArgument(new Reference('state')); $container->register('http_client_simpletest_subscriber', 'Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber'); $container->register('http_default_client', 'Guzzle\Http\Client') diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php new file mode 100644 index 0000000..8304fad --- /dev/null +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php @@ -0,0 +1,89 @@ +keyValueStore = $keyValueFactory->get($collection); + } + + protected function resolveCacheMiss($offset) { + $this->storage[$offset] = $this->keyValueStore->get($offset); + $this->persist($offset); + return $this->storage[$offset]; + } + + public function get($key) { + return $this->offsetGet($key); + } + + public function delete($key) { + $this->offsetUnset($key); + $this->keyValueStore->delete($key); + } + + public function deleteMultiple(array $keys) { + foreach ($keys as $key) { + $this->offsetUnset($key); + } + $this->keyValueStore->deleteMulitple($keys); + } + + public function getAll() { + // Don't cache this. + return $this->keyValueStore->getAll(); + } + + public function getCollectionName() { + return $this->keyValueStore->getCollectionName(); + } + + public function getMultiple(array $keys) { + $values = array(); + foreach ($keys as $key) { + $values[$key] = $this->offsetGet($key); + } + return $values; + } + + public function setIfNotExists($key, $value) { + if ($this->keyValueStore->setIfNotExists($key, $value)) { + $this->offsetSet($key, $value); + } + } + + public function setMultiple(array $data) { + $this->keyValueStore->setMultiple($data); + foreach ($data as $key => $value) { + $this->offsetSet($key, $value); + $this->persist($key); + } + } + + public function set($key, $value) { + $this->keyValueStore->set($key, $value); + $this->offsetSet($key, $value); + // Immediately update the cache. + $this->setData(array($key => $value)); + } + +} diff --git a/core/lib/Drupal/Core/Path/AliasManager.php b/core/lib/Drupal/Core/Path/AliasManager.php index 47bf77b..513190d 100644 --- a/core/lib/Drupal/Core/Path/AliasManager.php +++ b/core/lib/Drupal/Core/Path/AliasManager.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Path; use Drupal\Core\Database\Connection; -use Drupal\Core\KeyValueStore\KeyValueFactory; +use Drupal\Core\KeyValueStore\KeyValueStoreInterface; class AliasManager implements AliasManagerInterface { @@ -78,9 +78,9 @@ class AliasManager implements AliasManagerInterface { */ protected $preloadedPathLookups = array(); - public function __construct(Connection $connection, KeyValueFactory $keyvalue) { + public function __construct(Connection $connection, KeyValueStoreInterface $state) { $this->connection = $connection; - $this->state = $keyvalue->get('state'); + $this->state = $state; $this->langcode = language(LANGUAGE_TYPE_URL)->langcode; $this->whitelist = $this->state->get('system.path_alias_whitelist', NULL); if (!isset($this->whitelist)) { diff --git a/core/lib/Drupal/Core/Utility/CacheArray.php b/core/lib/Drupal/Core/Utility/CacheArray.php index eddfc27..03deeae 100644 --- a/core/lib/Drupal/Core/Utility/CacheArray.php +++ b/core/lib/Drupal/Core/Utility/CacheArray.php @@ -95,6 +95,13 @@ protected $keysToPersist = array(); /** + * An array of keys to remove from the cache at the end of the request. + * + * @var array + */ + protected $keysToRemove = array(); + + /** * Storage for the data itself. * * @var array @@ -152,6 +159,9 @@ public function offsetSet($offset, $value) { */ public function offsetUnset($offset) { unset($this->storage[$offset]); + $this->keysToRemove[$offset] = $offset; + // The offset might have been marked for persisting. + unset($this->keysToPersist[$offset]); } /** @@ -171,6 +181,8 @@ public function offsetUnset($offset) { */ protected function persist($offset, $persist = TRUE) { $this->keysToPersist[$offset] = $persist; + // The offset might have been marked for deletion. + unset($this->keysToRemove[$offset]); } /** @@ -196,13 +208,17 @@ protected function persist($offset, $persist = TRUE) { * @param $lock * Whether to acquire a lock before writing to cache. */ - protected function set($data, $lock = TRUE) { + protected function setData($data, $lock = TRUE) { // Lock cache writes to help avoid stampedes. // To implement locking for cache misses, override __construct(). $lock_name = $this->cid . ':' . $this->bin; if (!$lock || lock()->acquire($lock_name)) { if ($cached = cache($this->bin)->get($this->cid)) { - $data = $cached->data + $data; + $data = array_merge($cached->data, $data); + } + // Remove keys marked for deletion. + foreach ($this->keysToRemove as $delete_key) { + unset($data[$delete_key]); } cache($this->bin)->set($this->cid, $data, CacheBackendInterface::CACHE_PERMANENT, $this->tags); if ($lock) { @@ -222,7 +238,7 @@ public function __destruct() { } } if (!empty($data)) { - $this->set($data); + $this->setData($data); } } }