From 1a7a15a3ef78c9e1f8aeb476fa11f6cf016e00f3 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 17 Nov 2013 04:00:30 +0400 Subject: [PATCH] Implemented mset, madd for cache. Added tests. --- framework/yii/caching/ApcCache.php | 22 +++++ framework/yii/caching/Cache.php | 98 ++++++++++++++++++- framework/yii/caching/MemCache.php | 21 ++++ framework/yii/caching/WinCache.php | 24 +++++ .../unit/framework/caching/CacheTestCase.php | 26 +++-- 5 files changed, 180 insertions(+), 11 deletions(-) diff --git a/framework/yii/caching/ApcCache.php b/framework/yii/caching/ApcCache.php index 6c2754ac6e..688c3f111a 100644 --- a/framework/yii/caching/ApcCache.php +++ b/framework/yii/caching/ApcCache.php @@ -71,6 +71,17 @@ class ApcCache extends Cache return apc_store($key, $value, $expire); } + /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return array_keys(apc_store($data, null, $expire)); + } + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. @@ -84,6 +95,17 @@ class ApcCache extends Cache return apc_add($key, $value, $expire); } + /** + * Adds multiple key-value pairs to cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return array_keys(apc_add($data, null, $expire)); + } + /** * Deletes a value with the specified key from cache * This is the implementation of the method declared in the parent class. diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php index 6471e5d995..41a25b2551 100644 --- a/framework/yii/caching/Cache.php +++ b/framework/yii/caching/Cache.php @@ -220,14 +220,62 @@ abstract class Cache extends Component implements \ArrayAccess * If the cache already contains such a key, the existing value and * expiration time will be replaced with the new ones, respectively. * - * @param array $items the items to be cached, as key-value pairs. Each key can be a simple string or - * a complex data structure consisting of factors representing the key. - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. * @return boolean whether the items are successfully stored into cache */ - public function mset($items, $expire = 0) + public function mset($items, $expire = 0, $dependency = null) { - return false; + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->setValues($data, $expire); + } + + /** + * Stores multiple items in cache. Each item contains a value identified by a key. + * If the cache already contains such a key, the existing value and expiration time will be preserved. + * + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. + * @return boolean whether the items are successfully stored into cache + */ + public function madd($items, $expire = 0, $dependency = null) + { + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->addValues($data, $expire); } /** @@ -341,6 +389,46 @@ abstract class Cache extends Component implements \ArrayAccess return $results; } + /** + * Stores multiple key-value pairs in cache. + * The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache + * storage supports multiset, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->setValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + + /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->addValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + /** * Returns whether there is a cache entry with a specified key. * This method is required by the interface ArrayAccess. diff --git a/framework/yii/caching/MemCache.php b/framework/yii/caching/MemCache.php index 6f7a760ec0..339179673a 100644 --- a/framework/yii/caching/MemCache.php +++ b/framework/yii/caching/MemCache.php @@ -201,6 +201,27 @@ class MemCache extends Cache return $this->useMemcached ? $this->_cache->set($key, $value, $expire) : $this->_cache->set($key, $value, 0, $expire); } + /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys. Always empty in case of using memcached. + */ + protected function setValues($data, $expire) + { + if ($this->useMemcached) { + if ($expire > 0) { + $expire += time(); + } else { + $expire = 0; + } + $this->_cache->setMulti($data, $expire); + return []; + } else { + return parent::setValues($data, $expire); + } + } + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. diff --git a/framework/yii/caching/WinCache.php b/framework/yii/caching/WinCache.php index 3679884bb4..7f1eca8ea6 100644 --- a/framework/yii/caching/WinCache.php +++ b/framework/yii/caching/WinCache.php @@ -71,6 +71,17 @@ class WinCache extends Cache return wincache_ucache_set($key, $value, $expire); } + /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return wincache_ucache_set($data, null, $expire); + } + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. @@ -85,6 +96,19 @@ class WinCache extends Cache return wincache_ucache_add($key, $value, $expire); } + /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return wincache_ucache_add($data, null, $expire); + } + /** * Deletes a value with the specified key from cache * This is the implementation of the method declared in the parent class. diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index d51cebd769..849cad0524 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -93,15 +93,14 @@ abstract class CacheTestCase extends TestCase public function testMset() { - $this->markTestIncomplete('Work in progress'); - $cache = $this->getCacheInstance(); $cache->flush(); - $this->assertTrue($cache->mset(['string_test' => 'string_test', - 'number_test' => 42, - 'array_test' => ['array_test' => 'array_test'], - ])); + $cache->mset([ + 'string_test' => 'string_test', + 'number_test' => 42, + 'array_test' => ['array_test' => 'array_test'], + ]); $this->assertEquals('string_test', $cache->get('string_test')); @@ -185,6 +184,21 @@ abstract class CacheTestCase extends TestCase $this->assertEquals(13, $cache->get('add_test')); } + public function testMadd() + { + $cache = $this->prepare(); + + $this->assertFalse($cache->get('add_test')); + + $cache->madd([ + 'number_test' => 13, + 'add_test' => 13, + ]); + + $this->assertEquals(42, $cache->get('number_test')); + $this->assertEquals(13, $cache->get('add_test')); + } + public function testDelete() { $cache = $this->prepare();