diff --git a/core/lib/Drupal/Core/Cache/CacheCollector.php b/core/lib/Drupal/Core/Cache/CacheCollector.php index 28c9026..956cd8e 100644 --- a/core/lib/Drupal/Core/Cache/CacheCollector.php +++ b/core/lib/Drupal/Core/Cache/CacheCollector.php @@ -2,7 +2,7 @@ /** * @file - * Contains Drupal\Core\Cache\CacheCollector. + * Contains \Drupal\Core\Cache\CacheCollector. */ namespace Drupal\Core\Cache; @@ -209,9 +209,9 @@ protected function updateCache($lock = TRUE) { } /** - * Implements KernelServiceTerminator::terminate(). + * Implements KernelServiceDestruction::destruct(). */ - public function terminate() { + public function destruct() { $this->updateCache(); } diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php index ccf9929..2735e84 100644 --- a/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueCacheDecorator.php @@ -2,7 +2,7 @@ /** * @file - * Contains Drupal\Core\KeyValueStore\KeyValueCacheDecorator. + * Contains \Drupal\Core\KeyValueStore\KeyValueCacheDecorator. */ namespace Drupal\Core\KeyValueStore; @@ -23,17 +23,35 @@ class KeyValueCacheDecorator extends CacheCollector implements KeyValueStoreInte */ protected $keyValueStore; + /** + * Constructs a key value cache decorator. + * + * @param \Drupal\Core\Cache\CacheBackendInterface $cache + * The cache backend to store the cache in. + * @param \Drupal\Core\Lock\LockBackendInterface $lock + * The lock implementation to use when writing a changed cache storage. + * @param \Drupal\Core\KeyValueStore\KeyValueFactory $keyValueFactory + * The key value factory to get the key value storage from. + * @param string $collection + * Name of the key value storage collection, also used as the cache id. + */ public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, KeyValueFactory $keyValueFactory, $collection) { - parent::__construct('state', $cache, $lock); + parent::__construct($collection, $cache, $lock); $this->keyValueStore = $keyValueFactory->get($collection); } + /** + * Implements \Drupal\Core\Cache\CacheCollector::resolveCacheMiss(). + */ protected function resolveCacheMiss($offset) { $this->storage[$offset] = $this->keyValueStore->get($offset); $this->persist($offset); return $this->storage[$offset]; } + /** + * Overrides \Drupal\Core\Cache\CacheCollector::delete(). + */ public function delete($key) { parent::delete($key); $this->keyValueStore->delete($key); @@ -42,6 +60,9 @@ public function delete($key) { $this->cache->delete($this->cid); } + /** + * Overrides \Drupal\Core\Cache\CacheCollector::deleteMultiple(). + */ public function deleteMultiple(array $keys) { foreach ($keys as $key) { $this->delete($key); @@ -52,57 +73,85 @@ public function deleteMultiple(array $keys) { $this->cache->delete($this->cid); } + /** + * Implements KeyValueStoreInterface::getAll(). + */ public function getAll() { // Don't cache this. return $this->keyValueStore->getAll(); } + /** + * Implements KeyValueStoreInterface::getCollectionName(). + */ public function getCollectionName() { return $this->keyValueStore->getCollectionName(); } + /** + * Implements KeyValueStoreInterface::getAll(). + */ public function getMultiple(array $keys) { $values = array(); foreach ($keys as $key) { - $values[$key] = $this->get($key); + $value = $this->get($key); + // Only return keys with a value. + if ($value !== NULL) { + $values[$key] = $value; + } } return $values; } + /** + * Implements KeyValueStoreInterface::setIfNotExists(). + */ public function setIfNotExists($key, $value) { if ($this->keyValueStore->setIfNotExists($key, $value)) { $this->set($key, $value); + return TRUE; } + return FALSE; } + /** + * Implements KeyValueStoreInterface::setMultiple(). + */ public function setMultiple(array $data) { $this->keyValueStore->setMultiple($data); foreach ($data as $key => $value) { parent::set($key, $value); + $this->keysToPersist[$key] = $value; } // Delete the cache to make sure that other requests immediately see the new // value before this request is terminated. $this->cache->delete($this->cid); } + /** + * Implements KeyValueStoreInterface::set(). + */ public function set($key, $value) { $this->keyValueStore->set($key, $value); parent::set($key, $value); + $this->keysToPersist[$key] = $value; // Delete the cache to make sure that other requests immediately see the new // value before this request is terminated. $this->cache->delete($this->cid); } /** - * @todo: Remove this once the service terminator can be used. + * Destruct the class, write the cache back. + * + * @todo: Remove this once the service destructor can be used. */ public function __destruct() { try { - $this->terminate(); + $this->destruct(); } catch (\Exception $e) { // During testing the table is gone before this fires. - // @todo Use service terminator that directly invokes terminate(), see + // @todo Use service destruction that directly invokes destruct(), see // http://drupal.org/node/512026. } } diff --git a/core/modules/system/lib/Drupal/system/Tests/KeyValueStore/CacheDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/KeyValueStore/CacheDecoratorTest.php new file mode 100644 index 0000000..fa56f24 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/KeyValueStore/CacheDecoratorTest.php @@ -0,0 +1,87 @@ + 'Key value cache decorator', + 'description' => 'Tests the key value cache decorator.', + 'group' => 'Key-value store', + ); + } + + protected function setUp() { + parent::setUp(); + $this->container + ->register('keyvalue.memory', 'Drupal\Core\KeyValueStore\KeyValueMemoryFactory'); + global $conf; + $conf['keyvalue_default'] = 'keyvalue.memory'; + $this->cache = $cache = new MemoryBackend('bin'); + } + + /** + * Tests that values are cached. + */ + public function testCache() { + $stores = $this->createStorage(); + $values = array(); + // Set the value and test that it is correctly returned. + foreach ($this->collections as $i => $collection) { + $stores[$i]->set('key', $this->objects[$i]); + $this->assertEqual($stores[$i]->get('key'), $this->objects[$i]); + // Destruct the class to have it write the cache. + $stores[$i]->destruct(); + + // Delete the value from the key value storage. + $this->container->get($this->factory)->get($collection)->delete('key'); + } + + // Create new objects. + $stores = $this->createStorage(); + + // Verify that we get the cached state as we have not notified the decorator + // about the deletion. + foreach ($this->collections as $i => $collection) { + $this->assertEqual($stores[$i]->get('key'), $this->objects[$i]); + + // Reset the cache and make sure the value was updated. + $stores[$i]->reset(); + $this->assertNull($stores[$i]->get('key')); + } + } + + /** + * Overrides StorageTestBase::createStorage() + */ + protected function createStorage() { + $stores = array(); + // Prepare the memory key value storages and decorated ones. + foreach ($this->collections as $i => $collection) { + $stores[$i] = new KeyValueCacheDecorator($this->cache, new NullLockBackend(), $this->container->get($this->factory), $collection); + } + + return $stores; + } + +}