Browse Source

refactored redis cache, added mset()

tags/2.0.0-beta
Carsten Brandt 11 years ago
parent
commit
09a3300b7c
  1. 81
      framework/yii/caching/RedisCache.php
  2. 5
      tests/unit/framework/caching/ApcCacheTest.php
  3. 26
      tests/unit/framework/caching/CacheTestCase.php
  4. 12
      tests/unit/framework/caching/DbCacheTest.php
  5. 12
      tests/unit/framework/caching/FileCacheTest.php
  6. 8
      tests/unit/framework/caching/MemCacheTest.php
  7. 8
      tests/unit/framework/caching/MemCachedTest.php
  8. 11
      tests/unit/framework/caching/RedisCacheTest.php

81
framework/yii/caching/RedisCache.php

@ -10,7 +10,7 @@ namespace yii\caching;
use yii\redis\Connection; use yii\redis\Connection;
/** /**
* RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6 or higher. * RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6.12 or higher.
* *
* RedisCache needs to be configured with [[hostname]], [[port]] and [[database]] of the server * RedisCache needs to be configured with [[hostname]], [[port]] and [[database]] of the server
* to connect to. By default RedisCache assumes there is a redis server running on localhost at * to connect to. By default RedisCache assumes there is a redis server running on localhost at
@ -119,10 +119,7 @@ class RedisCache extends Cache
} }
/** /**
* Retrieves a value from cache with a specified key. * @inheritDocs
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
@ -130,9 +127,7 @@ class RedisCache extends Cache
} }
/** /**
* Retrieves multiple values from cache with the specified keys. * @inheritDocs
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/ */
protected function getValues($keys) protected function getValues($keys)
{ {
@ -146,14 +141,7 @@ class RedisCache extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * @inheritDocs
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached
* @param float $expire the number of seconds in which the cached value will expire. 0 means never expire.
* This can be a floating point number to specify the time in milliseconds.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/ */
protected function setValue($key, $value, $expire) protected function setValue($key, $value, $expire)
{ {
@ -161,40 +149,59 @@ class RedisCache extends Cache
return (bool) $this->_connection->executeCommand('SET', [$key, $value]); return (bool) $this->_connection->executeCommand('SET', [$key, $value]);
} else { } else {
$expire = (int) ($expire * 1000); $expire = (int) ($expire * 1000);
return (bool) $this->_connection->executeCommand('PSETEX', [$key, $expire, $value]); return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'PX', $expire]);
} }
} }
/** /**
* Stores a value identified by a key into cache if the cache does not contain this key. * @inheritDocs
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached
* @param float $expire the number of seconds in which the cached value will expire. 0 means never expire.
* This can be a floating point number to specify the time in milliseconds.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/ */
protected function addValue($key,$value,$expire) protected function setValues($data, $expire)
{ {
$args = [];
foreach($data as $key => $value) {
$args[] = $key;
$args[] = $value;
}
$failedKeys = [];
if ($expire == 0) { if ($expire == 0) {
return (bool) $this->_connection->executeCommand('SETNX', [$key, $value]); $this->_connection->executeCommand('MSET', $args);
} else { } else {
// TODO consider requiring redis version >= 2.6.12 that supports this in one command
$expire = (int) ($expire * 1000); $expire = (int) ($expire * 1000);
$this->_connection->executeCommand('MULTI'); $this->_connection->executeCommand('MULTI');
$this->_connection->executeCommand('SETNX', [$key, $value]); $this->_connection->executeCommand('MSET', $args);
$index = [];
foreach ($data as $key => $value) {
$this->_connection->executeCommand('PEXPIRE', [$key, $expire]); $this->_connection->executeCommand('PEXPIRE', [$key, $expire]);
$response = $this->_connection->executeCommand('EXEC'); $index[] = $key;
return (bool) $response[0]; }
$result = $this->_connection->executeCommand('EXEC');
array_shift($result);
foreach($result as $i => $r) {
if ($r != 1) {
$failedKeys[] = $index[$i];
}
}
}
return $failedKeys;
}
/**
* @inheritDocs
*/
protected function addValue($key, $value, $expire)
{
if ($expire == 0) {
return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'NX']);
} else {
$expire = (int) ($expire * 1000);
return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'PX', $expire, 'NX']);
} }
} }
/** /**
* Deletes a value with the specified key from cache * @inheritDocs
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return boolean if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -202,9 +209,7 @@ class RedisCache extends Cache
} }
/** /**
* Deletes all values from cache. * @inheritDocs
* This is the implementation of the method declared in the parent class.
* @return boolean whether the flush operation was successful.
*/ */
protected function flushValues() protected function flushValues()
{ {

5
tests/unit/framework/caching/ApcCacheTest.php

@ -37,4 +37,9 @@ class ApcCacheTest extends CacheTestCase
{ {
$this->markTestSkipped("APC keys are expiring only on the next request."); $this->markTestSkipped("APC keys are expiring only on the next request.");
} }
public function testExpireAdd()
{
$this->markTestSkipped("APC keys are expiring only on the next request.");
}
} }

26
tests/unit/framework/caching/CacheTestCase.php

@ -91,7 +91,18 @@ abstract class CacheTestCase extends TestCase
$this->assertEquals('array_test', $array['array_test']); $this->assertEquals('array_test', $array['array_test']);
} }
public function testMset() /**
* @return array testing mset with and without expiry
*/
public function msetExpiry()
{
return [[0], [2]];
}
/**
* @dataProvider msetExpiry
*/
public function testMset($expiry)
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$cache->flush(); $cache->flush();
@ -100,7 +111,7 @@ abstract class CacheTestCase extends TestCase
'string_test' => 'string_test', 'string_test' => 'string_test',
'number_test' => 42, 'number_test' => 42,
'array_test' => ['array_test' => 'array_test'], 'array_test' => ['array_test' => 'array_test'],
]); ], $expiry);
$this->assertEquals('string_test', $cache->get('string_test')); $this->assertEquals('string_test', $cache->get('string_test'));
@ -170,6 +181,17 @@ abstract class CacheTestCase extends TestCase
$this->assertFalse($cache->get('expire_test')); $this->assertFalse($cache->get('expire_test'));
} }
public function testExpireAdd()
{
$cache = $this->getCacheInstance();
$this->assertTrue($cache->add('expire_testa', 'expire_testa', 2));
usleep(500000);
$this->assertEquals('expire_testa', $cache->get('expire_testa'));
usleep(2500000);
$this->assertFalse($cache->get('expire_testa'));
}
public function testAdd() public function testAdd()
{ {
$cache = $this->prepare(); $cache = $this->prepare();

12
tests/unit/framework/caching/DbCacheTest.php

@ -83,4 +83,16 @@ class DbCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_test')); $this->assertFalse($cache->get('expire_test'));
} }
public function testExpireAdd()
{
$cache = $this->getCacheInstance();
static::$time = \time();
$this->assertTrue($cache->add('expire_testa', 'expire_testa', 2));
static::$time++;
$this->assertEquals('expire_testa', $cache->get('expire_testa'));
static::$time++;
$this->assertFalse($cache->get('expire_testa'));
}
} }

12
tests/unit/framework/caching/FileCacheTest.php

@ -33,4 +33,16 @@ class FileCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_test')); $this->assertFalse($cache->get('expire_test'));
} }
public function testExpireAdd()
{
$cache = $this->getCacheInstance();
static::$time = \time();
$this->assertTrue($cache->add('expire_testa', 'expire_testa', 2));
static::$time++;
$this->assertEquals('expire_testa', $cache->get('expire_testa'));
static::$time++;
$this->assertFalse($cache->get('expire_testa'));
}
} }

8
tests/unit/framework/caching/MemCacheTest.php

@ -34,4 +34,12 @@ class MemCacheTest extends CacheTestCase
} }
parent::testExpire(); parent::testExpire();
} }
public function testExpireAdd()
{
if (getenv('TRAVIS') == 'true') {
$this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.');
}
parent::testExpireAdd();
}
} }

8
tests/unit/framework/caching/MemCachedTest.php

@ -34,4 +34,12 @@ class MemCachedTest extends CacheTestCase
} }
parent::testExpire(); parent::testExpire();
} }
public function testExpireAdd()
{
if (getenv('TRAVIS') == 'true') {
$this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.');
}
parent::testExpireAdd();
}
} }

11
tests/unit/framework/caching/RedisCacheTest.php

@ -45,6 +45,17 @@ class RedisCacheTest extends CacheTestCase
$this->assertFalse($cache->get('expire_test_ms')); $this->assertFalse($cache->get('expire_test_ms'));
} }
public function testExpireAddMilliseconds()
{
$cache = $this->getCacheInstance();
$this->assertTrue($cache->add('expire_testa_ms', 'expire_testa_ms', 0.2));
usleep(100000);
$this->assertEquals('expire_testa_ms', $cache->get('expire_testa_ms'));
usleep(300000);
$this->assertFalse($cache->get('expire_testa_ms'));
}
/** /**
* Store a value that is 2 times buffer size big * Store a value that is 2 times buffer size big
* https://github.com/yiisoft/yii2/issues/743 * https://github.com/yiisoft/yii2/issues/743

Loading…
Cancel
Save