summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2014-04-15 19:48:35 (GMT)
committerNathaniel Catchpole2014-04-15 19:48:35 (GMT)
commit5639ae2d7b06d4a6bd9079c58de4ec9809737422 (patch)
tree3b8061d3095624e2f85c70d7fcade6cd5411e3ba
parenta4127f24af586ef946cc7b134fae1366a62da746 (diff)
Issue #1167248 by Berdir, damiankloip, Alan Evans, beejeebus, catch: Add CacheBackendInterface::setMultiple().
-rw-r--r--core/lib/Drupal/Core/Cache/BackendChain.php9
-rw-r--r--core/lib/Drupal/Core/Cache/CacheBackendInterface.php20
-rw-r--r--core/lib/Drupal/Core/Cache/DatabaseBackend.php72
-rw-r--r--core/lib/Drupal/Core/Cache/MemoryBackend.php13
-rw-r--r--core/lib/Drupal/Core/Cache/NullBackend.php5
-rw-r--r--core/lib/Drupal/Core/Config/CachedStorage.php5
-rw-r--r--core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php4
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php38
8 files changed, 161 insertions, 5 deletions
diff --git a/core/lib/Drupal/Core/Cache/BackendChain.php b/core/lib/Drupal/Core/Cache/BackendChain.php
index 4d8ca05..2ea1118 100644
--- a/core/lib/Drupal/Core/Cache/BackendChain.php
+++ b/core/lib/Drupal/Core/Cache/BackendChain.php
@@ -132,6 +132,15 @@ class BackendChain implements CacheBackendInterface {
}
/**
+ * {@inheritdoc}
+ */
+ public function setMultiple(array $items) {
+ foreach ($this->backends as $backend) {
+ $backend->setMultiple($items);
+ }
+ }
+
+ /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/
public function delete($cid) {
diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
index f0e9882..f604980 100644
--- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
+++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
@@ -96,6 +96,26 @@ interface CacheBackendInterface {
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array());
/**
+ * Store multiple items in the persistent cache.
+ *
+ * @param array $items
+ * An array of cache items, keyed by cid. In the form:
+ * @code
+ * $items = array(
+ * $cid => array(
+ * // Required, will be automatically serialized if not a string.
+ * 'data' => $data,
+ * // Optional, defaults to CacheBackendInterface::CACHE_PERMANENT.
+ * 'expire' => CacheBackendInterface::CACHE_PERMANENT,
+ * // (optional) The cache tags for this item, see CacheBackendInterface::set().
+ * 'tags' => array(),
+ * ),
+ * );
+ * @endcode
+ */
+ public function setMultiple(array $items);
+
+ /**
* Deletes an item from the cache.
*
* If the cache item is being deleted because it is no longer "fresh", you may
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 4c431dc..3ae9eac 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -202,6 +202,78 @@ class DatabaseBackend implements CacheBackendInterface {
}
/**
+ * {@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();
+
+ try {
+ // Delete all items first so we can do one insert. Rather than mulitple
+ // merge queries.
+ $this->deleteMultiple(array_keys($items));
+
+ $query = $this->connection
+ ->insert($this->bin)
+ ->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum_invalidations', 'checksum_deletions'));
+
+ foreach ($items as $cid => $item) {
+ $item += array(
+ 'expire' => CacheBackendInterface::CACHE_PERMANENT,
+ 'tags' => array(),
+ );
+
+ $flat_tags = $this->flattenTags($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 ($flat_tags as $tag) {
+ if (isset($deleted_tags[$tag])) {
+ unset($deleted_tags[$tag]);
+ }
+ if (isset($invalidated_tags[$tag])) {
+ unset($invalidated_tags[$tag]);
+ }
+ }
+
+ $checksum = $this->checksumTags($flat_tags);
+
+ $fields = array(
+ 'cid' => $cid,
+ 'expire' => $item['expire'],
+ 'created' => REQUEST_TIME,
+ 'tags' => implode(' ', $flat_tags),
+ 'checksum_invalidations' => $checksum['invalidations'],
+ 'checksum_deletions' => $checksum['deletions'],
+ );
+
+ if (!is_string($item['data'])) {
+ $fields['data'] = serialize($item['data']);
+ $fields['serialized'] = 1;
+ }
+ else {
+ $fields['data'] = $item['data'];
+ $fields['serialized'] = 0;
+ }
+
+ $query->values($fields);
+ }
+
+ $query->execute();
+ }
+ catch (\Exception $e) {
+ $transaction->rollback();
+ // @todo Log something here or just re throw?
+ throw $e;
+ }
+ }
+
+ /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/
public function delete($cid) {
diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php
index c4e16f7..fb9e29c 100644
--- a/core/lib/Drupal/Core/Cache/MemoryBackend.php
+++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php
@@ -107,6 +107,15 @@ class MemoryBackend implements CacheBackendInterface {
}
/**
+ * {@inheritdoc}
+ */
+ public function setMultiple(array $items = array()) {
+ foreach ($items as $cid => $item) {
+ $this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT, isset($item['tags']) ? $item['tags'] : array());
+ }
+ }
+
+ /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/
public function delete($cid) {
@@ -196,11 +205,11 @@ class MemoryBackend implements CacheBackendInterface {
foreach ($tags as $namespace => $values) {
if (is_array($values)) {
foreach ($values as $value) {
- $flat_tags["$namespace:$value"] = "$namespace:$value";
+ $flat_tags[] = "$namespace:$value";
}
}
else {
- $flat_tags["$namespace:$values"] = "$namespace:$values";
+ $flat_tags[] = "$namespace:$values";
}
}
return $flat_tags;
diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php
index 94a426d..2d5664d 100644
--- a/core/lib/Drupal/Core/Cache/NullBackend.php
+++ b/core/lib/Drupal/Core/Cache/NullBackend.php
@@ -50,6 +50,11 @@ class NullBackend implements CacheBackendInterface {
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {}
/**
+ * {@inheritdoc}
+ */
+ public function setMultiple(array $items = array()) {}
+
+ /**
* Implements Drupal\Core\Cache\CacheBackendInterface::delete().
*/
public function delete($cid) {}
diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php
index 08dc582..a5d11fd 100644
--- a/core/lib/Drupal/Core/Config/CachedStorage.php
+++ b/core/lib/Drupal/Core/Config/CachedStorage.php
@@ -93,9 +93,12 @@ class CachedStorage implements StorageInterface, StorageCacheInterface {
$list = $this->storage->readMultiple($names);
// Cache configuration objects that were loaded from the storage, cache
// missing configuration objects as an explicit FALSE.
+ $items = array();
foreach ($names as $name) {
- $this->cache->set($name, isset($list[$name]) ? $list[$name] : FALSE);
+ $items[$name] = array('data' => isset($list[$name]) ? $list[$name] : FALSE);
}
+
+ $this->cache->setMultiple($items);
}
// Add the configuration objects from the cache to the list.
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php
index d4066b0..feb5471 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php
@@ -237,7 +237,7 @@ class BlockViewBuilderTest extends DrupalUnitTestBase {
$cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache');
- $this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.');
+ $this->assertIdentical($cache_entry->tags, $expected_flattened_tags); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid);
// Advanced: cached block, but an alter hook adds an additional cache tag.
@@ -251,7 +251,7 @@ class BlockViewBuilderTest extends DrupalUnitTestBase {
$cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache', $alter_add_tag . ':1');
- $this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.');
+ $this->assertIdentical($cache_entry->tags, $expected_flattened_tags); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid);
// Advanced: cached block, but an alter hook adds a #pre_render callback to
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
index e558816..9002314 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
@@ -8,6 +8,7 @@
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\simpletest\DrupalUnitTestBase;
/**
@@ -296,6 +297,43 @@ abstract class GenericCacheBackendUnitTestBase extends DrupalUnitTestBase {
}
/**
+ * Tests \Drupal\Core\Cache\CacheBackendInterface::setMultiple().
+ */
+ public function testSetMultiple() {
+ $backend = $this->getCacheBackend();
+
+ $future_expiration = REQUEST_TIME + 100;
+
+ // Set multiple testing keys.
+ $backend->set('cid_1', 'Some other value');
+ $items = array(
+ 'cid_1' => array('data' => 1),
+ 'cid_2' => array('data' => 2),
+ 'cid_3' => array('data' => array(1, 2)),
+ 'cid_4' => array('data' => 1, 'expire' => $future_expiration),
+ 'cid_5' => array('data' => 1, 'tags' => array('test' => array('a', 'b'))),
+ );
+ $backend->setMultiple($items);
+ $cids = array_keys($items);
+ $cached = $backend->getMultiple($cids);
+
+ $this->assertEqual($cached['cid_1']->data, $items['cid_1']['data'], 'Over-written cache item set correctly.');
+ $this->assertEqual($cached['cid_1']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
+
+ $this->assertEqual($cached['cid_2']->data, $items['cid_2']['data'], 'New cache item set correctly.');
+ $this->assertEqual($cached['cid_2']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
+
+ $this->assertEqual($cached['cid_3']->data, $items['cid_3']['data'], 'New cache item with serialized data set correctly.');
+ $this->assertEqual($cached['cid_3']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Cache expiration defaults to permanent.');
+
+ $this->assertEqual($cached['cid_4']->data, $items['cid_4']['data'], 'New cache item set correctly.');
+ $this->assertEqual($cached['cid_4']->expire, $future_expiration, 'Cache expiration has been correctly set.');
+
+ $this->assertEqual($cached['cid_5']->data, $items['cid_5']['data'], 'New cache item set correctly.');
+ $this->assertEqual($cached['cid_5']->tags, array('test:a', 'test:b'));
+ }
+
+ /**
* Tests Drupal\Core\Cache\CacheBackendInterface::isEmpty().
*/
public function testIsEmpty() {