Commit fe261118 by Qiang Xue

Fixes #4051: Renamed `yii\caching\GroupDependency` to `TagDependency` and added…

Fixes #4051: Renamed `yii\caching\GroupDependency` to `TagDependency` and added support for associating multiple tags to a single cached data item
parent 2e71f6e9
......@@ -242,8 +242,8 @@ Aquí abajo se muestra un sumario de las dependencias disponibles:
- [[yii\caching\DbDependency]]: la dependencia cambia si el resultado de la consulta de la sentencia SQL especificada cambia.
- [[yii\caching\ExpressionDependency]]: la dependencia cambia si el resultado de la expresión de PHP especificada cambia.
- [[yii\caching\FileDependency]]: la dependencia cambia si se modifica la última fecha de modificación del archivo.
- [[yii\caching\GroupDependency]]: marca un elemento de datos en caché con un nombre de grupo. Puedes invalidar los elementos de datos almacenados en caché
con el mismo nombre del grupo a la vez llamando a [[yii\caching\GroupDependency::invalidate()]].
- [[yii\caching\TagDependency]]: marca un elemento de datos en caché con un nombre de grupo. Puedes invalidar los elementos de datos almacenados en caché
con el mismo nombre del grupo a la vez llamando a [[yii\caching\TagDependency::invalidate()]].
## Consultas en Caché <a name="query-caching"></a>
......
......@@ -196,7 +196,8 @@ $data = $cache->get($key);
- [[yii\caching\DbDependency]]: 如果指定 SQL 语句的查询结果发生了变化,则依赖改变。
- [[yii\caching\ExpressionDependency]]: 如果指定的 PHP 表达式执行结果发生变化,则依赖改变。
- [[yii\caching\FileDependency]]: 如果文件的最后修改时间发生变化,则依赖改变。
- [[yii\caching\GroupDependency]]: 将一项缓存数据标记到一个组名,你可以通过调用 [[yii\caching\GroupDependency::invalidate()]] 一次性将同样组名的缓存数据全部置为失效状态。
- [[yii\caching\TagDependency]]: 为一项缓存数据添加一个或多个标签。你可以通过调用 [[yii\caching\TagDependency::invalidate()]]
一次性将具有指定标签的缓存数据全部置为失效状态。
## 查询缓存 <a name="query-caching"></a>
......
......@@ -232,8 +232,8 @@ Below is a summary of the available cache dependencies:
- [[yii\caching\DbDependency]]: the dependency is changed if the query result of the specified SQL statement is changed.
- [[yii\caching\ExpressionDependency]]: the dependency is changed if the result of the specified PHP expression is changed.
- [[yii\caching\FileDependency]]: the dependency is changed if the file's last modification time is changed.
- [[yii\caching\GroupDependency]]: marks a cached data item with a group name. You may invalidate the cached data items
with the same group name all at once by calling [[yii\caching\GroupDependency::invalidate()]].
- [[yii\caching\TagDependency]]: associates a cached data item with one or multiple tags. You may invalidate
the cached data items with the specified tag(s) by calling [[yii\caching\TagDependency::invalidate()]].
## Query Caching <a name="query-caching"></a>
......
......@@ -10,7 +10,7 @@ namespace yii\sphinx;
use yii\base\Object;
use yii\caching\Cache;
use Yii;
use yii\caching\GroupDependency;
use yii\caching\TagDependency;
use yii\db\Exception;
/**
......@@ -139,8 +139,8 @@ class Schema extends Object
if ($refresh || ($index = $cache->get($key)) === false) {
$index = $this->loadIndexSchema($realName);
if ($index !== null) {
$cache->set($key, $index, $db->schemaCacheDuration, new GroupDependency([
'group' => $this->getCacheGroup(),
$cache->set($key, $index, $db->schemaCacheDuration, new TagDependency([
'tags' => $this->getCacheTag(),
]));
}
}
......@@ -168,11 +168,11 @@ class Schema extends Object
}
/**
* Returns the cache group name.
* Returns the cache tag name.
* This allows [[refresh()]] to invalidate all cached index schemas.
* @return string the cache group name
* @return string the cache tag name
*/
protected function getCacheGroup()
protected function getCacheTag()
{
return md5(serialize([
__CLASS__,
......@@ -299,7 +299,7 @@ class Schema extends Object
/* @var $cache Cache */
$cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
if ($this->db->enableSchemaCache && $cache instanceof Cache) {
GroupDependency::invalidate($cache, $this->getCacheGroup());
TagDependency::invalidate($cache, $this->getCacheTag());
}
$this->_indexNames = [];
$this->_indexes = [];
......
......@@ -170,6 +170,7 @@ Yii Framework 2 Change Log
- Chg #3899: Moved `MailEvent` class to `yii\mail` namespace (cebe)
- Chg #3956: Flash messages set via `Yii::$app->session->setFlash()` will be removed only if they are accessed (qiangxue)
- Chg #3989: The default value for `yii\log\FileTarget::$rotateByCopy` now defaults to true to work on windows by default (cebe)
- Chg #4051: Renamed `yii\caching\GroupDependency` to `TagDependency` and added support for associating multiple tags to a single cached data item (qiangxue)
- Chg #4071: `mail` component renamed to `mailer`, `yii\log\EmailTarget::$mail` renamed to `yii\log\EmailTarget::$mailer` (samdark)
- Chg #4147: `BaseMailer::compose()` will not overwrite the `message` parameter if it is explicitly provided (qiangxue)
- Chg #4201: change default value of `SyslogTarget::facility` from LOG_SYSLOG to LOG_USER (dizews)
......
......@@ -74,7 +74,11 @@ Upgrade from Yii 2.0 Beta
* `mail` component was renamed to `mailer`, `yii\log\EmailTarget::$mail` was renamed to `yii\log\EmailTarget::$mailer`.
Please update all references in the code and config files.
* `\yii\rbac\PhpManager` now stores data in three separate files instead of one. In order to convert old file to
* `yii\caching\GroupDependency` was renamed to `TagDependency`. You should create such a dependency using the code
`new \yii\caching\TagDependency(['tags' => 'TagName'])`, where `TagName` is similar to the group name that you
previously used.
* `yii\rbac\PhpManager` now stores data in three separate files instead of one. In order to convert old file to
new ones save the following code as `convert.php` that should be placed in the same directory your `rbac.php` is in:
```php
......
......@@ -7,71 +7,104 @@
namespace yii\caching;
use yii\base\InvalidConfigException;
/**
* GroupDependency marks a cached data item with a group name.
* TagDependency associates a cached data item with one or multiple [[tags]].
*
* You may invalidate the cached data items with the same group name all at once
* by calling [[invalidate()]].
* By calling [[invalidate()]], you can invalidate all cached data items that are associated with the specified tag name(s).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class GroupDependency extends Dependency
class TagDependency extends Dependency
{
/**
* @var string the group name. This property must be set.
* @var string|array a list of tag names for this dependency. For a single tag, you may specify it as a string.
*/
public $group;
public $tags = [];
/**
* Generates the data needed to determine if dependency has been changed.
* This method does nothing in this class.
* @param Cache $cache the cache component that is currently evaluating this dependency
* @return mixed the data needed to determine if dependency has been changed.
* @throws InvalidConfigException if [[group]] is not set.
*/
protected function generateDependencyData($cache)
{
if ($this->group === null) {
throw new InvalidConfigException('GroupDependency::group must be set');
$timestamps = $this->getTimestamps($cache, (array) $this->tags);
$newKeys = [];
foreach ($timestamps as $key => $timestamp) {
if ($timestamp === false) {
$newKeys[] = $key;
}
}
$version = $cache->get([__CLASS__, $this->group]);
if ($version === false) {
$version = $this->invalidate($cache, $this->group);
if (!empty($newKeys)) {
$timestamps = array_merge($timestamps, $this->touchKeys($cache, $newKeys));
}
return $version;
return $timestamps;
}
/**
* Performs the actual dependency checking.
* @param Cache $cache the cache component that is currently evaluating this dependency
* @return boolean whether the dependency is changed or not.
* @throws InvalidConfigException if [[group]] is not set.
*/
public function getHasChanged($cache)
{
if ($this->group === null) {
throw new InvalidConfigException('GroupDependency::group must be set');
$timestamps = $this->getTimestamps($cache, (array) $this->tags);
return $timestamps !== $this->data;
}
/**
* Invalidates all of the cached data items that are associated with any of the specified [[tags]].
* @param Cache $cache the cache component that caches the data items
* @param string|array $tags
*/
public static function invalidate($cache, $tags)
{
$keys = [];
foreach ((array)$tags as $tag) {
$keys[] = $cache->buildKey([__CLASS__, $tag]);
}
$version = $cache->get([__CLASS__, $this->group]);
static::touchKeys($cache, $keys);
}
return $version === false || $version !== $this->data;
/**
* Generates the timestamp for the specified cache keys.
* @param Cache $cache
* @param string[] $keys
* @return array the timestamp indexed by cache keys
*/
protected static function touchKeys($cache, $keys)
{
$items = [];
$time = microtime();
foreach ($keys as $key) {
$items[$key] = $time;
}
$cache->mset($items);
return $items;
}
/**
* Invalidates all of the cached data items that have the same [[group]].
* @param Cache $cache the cache component that caches the data items
* @param string $group the group name
* @return string the current version number
* Returns the timestamps for the specified tags.
* @param Cache $cache
* @param string[] $tags
* @return array the timestamps indexed by the specified tags.
*/
public static function invalidate($cache, $group)
protected function getTimestamps($cache, $tags)
{
$version = microtime();
$cache->set([__CLASS__, $group], $version);
if (empty($tags)) {
return [];
}
$keys = [];
foreach ($tags as $tag) {
$keys[] = $cache->buildKey([__CLASS__, $tag]);
}
return $version;
return $cache->mget($keys);
}
}
......@@ -66,7 +66,7 @@ return [
'yii\caching\ExpressionDependency' => YII_PATH . '/caching/ExpressionDependency.php',
'yii\caching\FileCache' => YII_PATH . '/caching/FileCache.php',
'yii\caching\FileDependency' => YII_PATH . '/caching/FileDependency.php',
'yii\caching\GroupDependency' => YII_PATH . '/caching/GroupDependency.php',
'yii\caching\TagDependency' => YII_PATH . '/caching/TagDependency.php',
'yii\caching\MemCache' => YII_PATH . '/caching/MemCache.php',
'yii\caching\MemCacheServer' => YII_PATH . '/caching/MemCacheServer.php',
'yii\caching\WinCache' => YII_PATH . '/caching/WinCache.php',
......
......@@ -12,7 +12,7 @@ use yii\base\Object;
use yii\base\NotSupportedException;
use yii\base\InvalidCallException;
use yii\caching\Cache;
use yii\caching\GroupDependency;
use yii\caching\TagDependency;
/**
* Schema is the base class for concrete DBMS-specific schema classes.
......@@ -114,8 +114,8 @@ abstract class Schema extends Object
if ($refresh || ($table = $cache->get($key)) === false) {
$this->_tables[$name] = $table = $this->loadTableSchema($realName);
if ($table !== null) {
$cache->set($key, $table, $db->schemaCacheDuration, new GroupDependency([
'group' => $this->getCacheGroup(),
$cache->set($key, $table, $db->schemaCacheDuration, new TagDependency([
'tags' => $this->getCacheTag(),
]));
}
} else {
......@@ -145,11 +145,11 @@ abstract class Schema extends Object
}
/**
* Returns the cache group name.
* Returns the cache tag name.
* This allows [[refresh()]] to invalidate all cached table schemas.
* @return string the cache group name
* @return string the cache tag name
*/
protected function getCacheGroup()
protected function getCacheTag()
{
return md5(serialize([
__CLASS__,
......@@ -241,7 +241,7 @@ abstract class Schema extends Object
/* @var $cache Cache */
$cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
if ($this->db->enableSchemaCache && $cache instanceof Cache) {
GroupDependency::invalidate($cache, $this->getCacheGroup());
TagDependency::invalidate($cache, $this->getCacheTag());
}
$this->_tableNames = [];
$this->_tables = [];
......
<?php
namespace yiiunit\framework\caching;
use yiiunit\TestCase;
use yii\caching\FileCache;
use yii\caching\TagDependency;
/**
* @group caching
*/
class TagDependencyTest extends TestCase
{
public function testInvalidate()
{
$cache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']);
// single tag test
$cache->set('a1', 11, 0, new TagDependency(['tags' => 't1']));
$cache->set('a2', 12, 0, new TagDependency(['tags' => 't1']));
$cache->set('b1', 21, 0, new TagDependency(['tags' => 't2']));
$cache->set('b2', 22, 0, new TagDependency(['tags' => 't2']));
$this->assertEquals(11, $cache->get('a1'));
$this->assertEquals(12, $cache->get('a2'));
$this->assertEquals(21, $cache->get('b1'));
$this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't1');
$this->assertFalse($cache->get('a1'));
$this->assertFalse($cache->get('a2'));
$this->assertEquals(21, $cache->get('b1'));
$this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't2');
$this->assertFalse($cache->get('a1'));
$this->assertFalse($cache->get('a2'));
$this->assertFalse($cache->get('b1'));
$this->assertFalse($cache->get('b2'));
// multiple tag test
$cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']]));
$cache->set('a2', 12, 0, new TagDependency(['tags' => 't1']));
$cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']]));
$cache->set('b2', 22, 0, new TagDependency(['tags' => 't2']));
$this->assertEquals(11, $cache->get('a1'));
$this->assertEquals(12, $cache->get('a2'));
$this->assertEquals(21, $cache->get('b1'));
$this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't1');
$this->assertFalse($cache->get('a1'));
$this->assertFalse($cache->get('a2'));
$this->assertFalse($cache->get('b1'));
$this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't2');
$this->assertFalse($cache->get('a1'));
$this->assertFalse($cache->get('a2'));
$this->assertFalse($cache->get('b1'));
$this->assertFalse($cache->get('b2'));
$cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']]));
$cache->set('a2', 12, 0, new TagDependency(['tags' => 't1']));
$cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']]));
$cache->set('b2', 22, 0, new TagDependency(['tags' => 't2']));
$this->assertEquals(11, $cache->get('a1'));
$this->assertEquals(12, $cache->get('a2'));
$this->assertEquals(21, $cache->get('b1'));
$this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, ['t1', 't2']);
$this->assertFalse($cache->get('a1'));
$this->assertFalse($cache->get('a2'));
$this->assertFalse($cache->get('b1'));
$this->assertFalse($cache->get('b2'));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment