minor #40317 [Cache] boost perf by wrapping keys validity checks with assert()
(nicolas-grekas)
This PR was merged into the 5.3-dev branch.
Discussion
----------
[Cache] boost perf by wrapping keys validity checks with `assert()`
| Q | A
| ------------- | ---
| Branch? | 5.x
| Bug fix? | no
| New feature? | no
| Deprecations? | no
| Tickets | -
| License | MIT
| Doc PR | -
PSR-6 has one perf hog: checking the validity of keys.
But in practice, an invalid key should never happen in production: encoding/cleanup is a must-have, and it's a step that should be identified *during dev*.
That's why I think we're safe wrapping these checks with `assert()`.
On an `ArrayAdapter`, this doubles the throughput of the pool when getting items.
I didn't use `assert()` in constructors when not on the hot path.
This PR also makes some callable properties static, as they should be from the beginning.
Commits
-------
8f03a1f555
[Cache] boost perf by wrapping keys validity checks with `assert()`
This commit is contained in:
commit
1f65e78280
@ -39,10 +39,11 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
|
||||
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR;
|
||||
$this->defaultLifetime = $defaultLifetime;
|
||||
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
|
||||
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
|
||||
}
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
@ -63,9 +64,8 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$getId = \Closure::fromCallable([$this, 'getId']);
|
||||
$this->mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) {
|
||||
self::$mergeByLifetime ?? self::$mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime) {
|
||||
$byLifetime = [];
|
||||
$now = microtime(true);
|
||||
$expiredIds = [];
|
||||
@ -147,8 +147,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
|
||||
public function commit()
|
||||
{
|
||||
$ok = true;
|
||||
$byLifetime = $this->mergeByLifetime;
|
||||
$byLifetime = $byLifetime($this->deferred, $this->namespace, $expiredIds);
|
||||
$byLifetime = (self::$mergeByLifetime)($this->deferred, $this->namespace, $expiredIds, \Closure::fromCallable([$this, 'getId']), $this->defaultLifetime);
|
||||
$retry = $this->deferred = [];
|
||||
|
||||
if ($expiredIds) {
|
||||
|
@ -40,10 +40,11 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
|
||||
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
|
||||
$this->defaultLifetime = $defaultLifetime;
|
||||
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
|
||||
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
|
||||
}
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
@ -68,10 +69,8 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$getId = \Closure::fromCallable([$this, 'getId']);
|
||||
$tagPrefix = self::TAGS_PREFIX;
|
||||
$this->mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifetime) {
|
||||
self::$mergeByLifetime ?? self::$mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime) {
|
||||
$byLifetime = [];
|
||||
$now = microtime(true);
|
||||
$expiredIds = [];
|
||||
@ -175,8 +174,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
|
||||
public function commit(): bool
|
||||
{
|
||||
$ok = true;
|
||||
$byLifetime = $this->mergeByLifetime;
|
||||
$byLifetime = $byLifetime($this->deferred, $expiredIds);
|
||||
$byLifetime = (self::$mergeByLifetime)($this->deferred, $expiredIds, \Closure::fromCallable([$this, 'getId']), self::TAGS_PREFIX, $this->defaultLifetime);
|
||||
$retry = $this->deferred = [];
|
||||
|
||||
if ($expiredIds) {
|
||||
|
@ -33,11 +33,12 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
private $storeSerialized;
|
||||
private $values = [];
|
||||
private $expiries = [];
|
||||
private $createCacheItem;
|
||||
private $defaultLifetime;
|
||||
private $maxLifetime;
|
||||
private $maxItems;
|
||||
|
||||
private static $createCacheItem;
|
||||
|
||||
/**
|
||||
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
|
||||
*/
|
||||
@ -55,7 +56,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
$this->storeSerialized = $storeSerialized;
|
||||
$this->maxLifetime = $maxLifetime;
|
||||
$this->maxItems = $maxItems;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
@ -111,7 +112,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
|
||||
return true;
|
||||
}
|
||||
CacheItem::validateKey($key);
|
||||
\assert('' !== CacheItem::validateKey($key));
|
||||
|
||||
return isset($this->expiries[$key]) && !$this->deleteItem($key);
|
||||
}
|
||||
@ -131,9 +132,8 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
} else {
|
||||
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
|
||||
}
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key, $value, $isHit);
|
||||
return (self::$createCacheItem)($key, $value, $isHit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,13 +141,9 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!\is_string($key) || !isset($this->expiries[$key])) {
|
||||
CacheItem::validateKey($key);
|
||||
}
|
||||
}
|
||||
\assert(self::validateKeys($keys));
|
||||
|
||||
return $this->generateItems($keys, microtime(true), $this->createCacheItem);
|
||||
return $this->generateItems($keys, microtime(true), self::$createCacheItem);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,9 +153,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
if (!\is_string($key) || !isset($this->expiries[$key])) {
|
||||
CacheItem::validateKey($key);
|
||||
}
|
||||
\assert('' !== CacheItem::validateKey($key));
|
||||
unset($this->values[$key], $this->expiries[$key]);
|
||||
|
||||
return true;
|
||||
@ -395,4 +389,15 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function validateKeys(array $keys): bool
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!\is_string($key) || !isset($this->expiries[$key])) {
|
||||
CacheItem::validateKey($key);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
|
||||
private $adapters = [];
|
||||
private $adapterCount;
|
||||
private $syncItem;
|
||||
private $defaultLifetime;
|
||||
|
||||
private static $syncItem;
|
||||
|
||||
/**
|
||||
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
|
||||
@ -62,9 +64,10 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
}
|
||||
}
|
||||
$this->adapterCount = \count($this->adapters);
|
||||
$this->defaultLifetime = $defaultLifetime;
|
||||
|
||||
$this->syncItem = \Closure::bind(
|
||||
static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifetime) {
|
||||
self::$syncItem ?? self::$syncItem = \Closure::bind(
|
||||
static function ($sourceItem, $item, $defaultLifetime, $sourceMetadata = null) {
|
||||
$sourceItem->isTaggable = false;
|
||||
$sourceMetadata = $sourceMetadata ?? $sourceItem->metadata;
|
||||
unset($sourceMetadata[CacheItem::METADATA_TAGS]);
|
||||
@ -105,7 +108,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
$value = $this->doGet($adapter, $key, $callback, $beta, $metadata);
|
||||
}
|
||||
if (null !== $item) {
|
||||
($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata);
|
||||
(self::$syncItem)($lastItem = $lastItem ?? $item, $item, $this->defaultLifetime, $metadata);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@ -119,7 +122,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$syncItem = $this->syncItem;
|
||||
$syncItem = self::$syncItem;
|
||||
$misses = [];
|
||||
|
||||
foreach ($this->adapters as $i => $adapter) {
|
||||
@ -127,7 +130,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
|
||||
if ($item->isHit()) {
|
||||
while (0 <= --$i) {
|
||||
$this->adapters[$i]->save($syncItem($item, $misses[$i]));
|
||||
$this->adapters[$i]->save($syncItem($item, $misses[$i], $this->defaultLifetime));
|
||||
}
|
||||
|
||||
return $item;
|
||||
@ -164,13 +167,13 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
}
|
||||
|
||||
if ($missing) {
|
||||
$syncItem = $this->syncItem;
|
||||
$syncItem = self::$syncItem;
|
||||
$adapter = $this->adapters[$adapterIndex];
|
||||
$items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
|
||||
|
||||
foreach ($items as $k => $item) {
|
||||
if ($item->isHit()) {
|
||||
$adapter->save($syncItem($item, $misses[$k]));
|
||||
$adapter->save($syncItem($item, $misses[$k], $this->defaultLifetime));
|
||||
}
|
||||
|
||||
yield $k => $item;
|
||||
|
@ -20,19 +20,19 @@ use Symfony\Contracts\Cache\CacheInterface;
|
||||
*/
|
||||
class NullAdapter implements AdapterInterface, CacheInterface
|
||||
{
|
||||
private $createCacheItem;
|
||||
private static $createCacheItem;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
function ($key) {
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->isHit = false;
|
||||
|
||||
return $item;
|
||||
},
|
||||
$this,
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
@ -44,7 +44,7 @@ class NullAdapter implements AdapterInterface, CacheInterface
|
||||
{
|
||||
$save = true;
|
||||
|
||||
return $callback(($this->createCacheItem)($key), $save);
|
||||
return $callback((self::$createCacheItem)($key), $save);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,9 +52,7 @@ class NullAdapter implements AdapterInterface, CacheInterface
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key);
|
||||
return (self::$createCacheItem)($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +143,7 @@ class NullAdapter implements AdapterInterface, CacheInterface
|
||||
|
||||
private function generateItems(array $keys)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$f = self::$createCacheItem;
|
||||
|
||||
foreach ($keys as $key) {
|
||||
yield $key => $f($key);
|
||||
|
@ -37,8 +37,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||
private $file;
|
||||
private $keys;
|
||||
private $values;
|
||||
private $createCacheItem;
|
||||
|
||||
private static $createCacheItem;
|
||||
private static $valuesCache = [];
|
||||
|
||||
/**
|
||||
@ -49,7 +49,7 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->pool = $fallbackPool;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
@ -142,9 +142,7 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key, $value, $isHit);
|
||||
return (self::$createCacheItem)($key, $value, $isHit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,7 +405,7 @@ EOF;
|
||||
|
||||
private function generateItems(array $keys): \Generator
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$f = self::$createCacheItem;
|
||||
$fallbackKeys = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
|
@ -28,22 +28,26 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
use ContractsTrait;
|
||||
use ProxyTrait;
|
||||
|
||||
private $namespace;
|
||||
private $namespace = '';
|
||||
private $namespaceLen;
|
||||
private $createCacheItem;
|
||||
private $setInnerItem;
|
||||
private $poolHash;
|
||||
private $defaultLifetime;
|
||||
|
||||
private static $createCacheItem;
|
||||
private static $setInnerItem;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->pool = $pool;
|
||||
$this->poolHash = $poolHash = spl_object_hash($pool);
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace);
|
||||
if ('' !== $namespace) {
|
||||
\assert('' !== CacheItem::validateKey($namespace));
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
$this->namespaceLen = \strlen($namespace);
|
||||
$this->defaultLifetime = $defaultLifetime;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $innerItem) use ($poolHash) {
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $innerItem, $poolHash) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
|
||||
@ -74,7 +78,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$this->setInnerItem = \Closure::bind(
|
||||
self::$setInnerItem ?? self::$setInnerItem = \Closure::bind(
|
||||
/**
|
||||
* @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
|
||||
*/
|
||||
@ -105,9 +109,9 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
}
|
||||
|
||||
return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) {
|
||||
$item = ($this->createCacheItem)($key, $innerItem);
|
||||
$item = (self::$createCacheItem)($key, $innerItem, $this->poolHash);
|
||||
$item->set($value = $callback($item, $save));
|
||||
($this->setInnerItem)($innerItem, (array) $item);
|
||||
(self::$setInnerItem)($innerItem, (array) $item);
|
||||
|
||||
return $value;
|
||||
}, $beta, $metadata);
|
||||
@ -118,10 +122,9 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$item = $this->pool->getItem($this->getId($key));
|
||||
|
||||
return $f($key, $item);
|
||||
return (self::$createCacheItem)($key, $item, $this->poolHash);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,33 +236,32 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
||||
} elseif ($this->pool instanceof AdapterInterface) {
|
||||
// this is an optimization specific for AdapterInterface implementations
|
||||
// so we can save a round-trip to the backend by just creating a new item
|
||||
$f = $this->createCacheItem;
|
||||
$innerItem = $f($this->namespace.$item["\0*\0key"], null);
|
||||
$innerItem = (self::$createCacheItem)($this->namespace.$item["\0*\0key"], null, $this->poolHash);
|
||||
} else {
|
||||
$innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
|
||||
}
|
||||
|
||||
($this->setInnerItem)($innerItem, $item);
|
||||
(self::$setInnerItem)($innerItem, $item);
|
||||
|
||||
return $this->pool->$method($innerItem);
|
||||
}
|
||||
|
||||
private function generateItems(iterable $items)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$f = self::$createCacheItem;
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
if ($this->namespaceLen) {
|
||||
$key = substr($key, $this->namespaceLen);
|
||||
}
|
||||
|
||||
yield $key => $f($key, $item);
|
||||
yield $key => $f($key, $item, $this->poolHash);
|
||||
}
|
||||
}
|
||||
|
||||
private function getId($key): string
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
\assert('' !== CacheItem::validateKey($key));
|
||||
|
||||
return $this->namespace.$key;
|
||||
}
|
||||
|
@ -31,20 +31,21 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
use ProxyTrait;
|
||||
|
||||
private $deferred = [];
|
||||
private $createCacheItem;
|
||||
private $setCacheItemTags;
|
||||
private $getTagsByKey;
|
||||
private $invalidateTags;
|
||||
private $tags;
|
||||
private $knownTagVersions = [];
|
||||
private $knownTagVersionsTtl;
|
||||
|
||||
private static $createCacheItem;
|
||||
private static $setCacheItemTags;
|
||||
private static $getTagsByKey;
|
||||
private static $invalidateTags;
|
||||
|
||||
public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
|
||||
{
|
||||
$this->pool = $itemsPool;
|
||||
$this->tags = $tagsPool ?: $itemsPool;
|
||||
$this->knownTagVersionsTtl = $knownTagVersionsTtl;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, CacheItem $protoItem) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
@ -57,7 +58,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$this->setCacheItemTags = \Closure::bind(
|
||||
self::$setCacheItemTags ?? self::$setCacheItemTags = \Closure::bind(
|
||||
static function (CacheItem $item, $key, array &$itemTags) {
|
||||
$item->isTaggable = true;
|
||||
if (!$item->isHit) {
|
||||
@ -78,7 +79,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$this->getTagsByKey = \Closure::bind(
|
||||
self::$getTagsByKey ?? self::$getTagsByKey = \Closure::bind(
|
||||
static function ($deferred) {
|
||||
$tagsByKey = [];
|
||||
foreach ($deferred as $key => $item) {
|
||||
@ -91,7 +92,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$this->invalidateTags = \Closure::bind(
|
||||
self::$invalidateTags ?? self::$invalidateTags = \Closure::bind(
|
||||
static function (AdapterInterface $tagsAdapter, array $tags) {
|
||||
foreach ($tags as $v) {
|
||||
$v->expiry = 0;
|
||||
@ -114,7 +115,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
$tagsByKey = [];
|
||||
$invalidatedTags = [];
|
||||
foreach ($tags as $tag) {
|
||||
CacheItem::validateKey($tag);
|
||||
\assert('' !== CacheItem::validateKey($tag));
|
||||
$invalidatedTags[$tag] = 0;
|
||||
}
|
||||
|
||||
@ -127,13 +128,12 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->getTagsByKey;
|
||||
$tagsByKey = $f($items);
|
||||
$tagsByKey = (self::$getTagsByKey)($items);
|
||||
$this->deferred = [];
|
||||
}
|
||||
|
||||
$tagVersions = $this->getTagVersions($tagsByKey, $invalidatedTags);
|
||||
$f = $this->createCacheItem;
|
||||
$f = self::$createCacheItem;
|
||||
|
||||
foreach ($tagsByKey as $key => $tags) {
|
||||
$this->pool->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key]));
|
||||
@ -141,8 +141,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
$ok = $this->pool->commit() && $ok;
|
||||
|
||||
if ($invalidatedTags) {
|
||||
$f = $this->invalidateTags;
|
||||
$ok = $f($this->tags, $invalidatedTags) && $ok;
|
||||
$ok = (self::$invalidateTags)($this->tags, $invalidatedTags) && $ok;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
@ -329,7 +328,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
||||
private function generateItems(iterable $items, array $tagKeys)
|
||||
{
|
||||
$bufferedItems = $itemTags = [];
|
||||
$f = $this->setCacheItemTags;
|
||||
$f = self::$setCacheItemTags;
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
if (!$tagKeys) {
|
||||
|
@ -59,7 +59,7 @@ class EarlyExpirationHandler implements MessageHandlerInterface
|
||||
|
||||
static $setMetadata;
|
||||
|
||||
$setMetadata = $setMetadata ?? \Closure::bind(
|
||||
$setMetadata ?? $setMetadata = \Closure::bind(
|
||||
function (CacheItem $item, float $startTime) {
|
||||
if ($item->expiry > $endTime = microtime(true)) {
|
||||
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
|
||||
|
@ -45,7 +45,12 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
|
||||
static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
|
||||
$item = clone $cacheItemPrototype;
|
||||
$item->poolHash = $item->innerItem = null;
|
||||
$item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key);
|
||||
if ($allowInt && \is_int($key)) {
|
||||
$item->key = (string) $key;
|
||||
} else {
|
||||
\assert('' !== CacheItem::validateKey($key));
|
||||
$item->key = $key;
|
||||
}
|
||||
$item->value = $value;
|
||||
$item->isHit = false;
|
||||
|
||||
|
@ -28,6 +28,16 @@ abstract class AdapterTestCase extends CachePoolTest
|
||||
if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) {
|
||||
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
|
||||
}
|
||||
|
||||
try {
|
||||
\assert(false === true, new \Exception());
|
||||
$this->skippedTests['testGetItemInvalidKeys'] =
|
||||
$this->skippedTests['testGetItemsInvalidKeys'] =
|
||||
$this->skippedTests['testHasItemInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteItemInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteItemsInvalidKeys'] = 'Keys are checked only when assert() is enabled.';
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
|
@ -10,6 +10,26 @@ use Symfony\Component\Cache\Psr16Cache;
|
||||
|
||||
class Psr16CacheProxyTest extends SimpleCacheTest
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
\assert(false === true, new \Exception());
|
||||
$this->skippedTests['testGetInvalidKeys'] =
|
||||
$this->skippedTests['testGetMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testGetMultipleNoIterable'] =
|
||||
$this->skippedTests['testSetInvalidKeys'] =
|
||||
$this->skippedTests['testSetMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testSetMultipleNoIterable'] =
|
||||
$this->skippedTests['testHasInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteMultipleNoIterable'] = 'Keys are checked only when assert() is enabled.';
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
public function createSimpleCache(int $defaultLifetime = 0): CacheInterface
|
||||
{
|
||||
return new Psr16Cache(new ProxyAdapter(new ArrayAdapter($defaultLifetime), 'my-namespace.'));
|
||||
|
@ -38,6 +38,21 @@ class Psr16CacheTest extends SimpleCacheTest
|
||||
if (!$pool instanceof PruneableInterface) {
|
||||
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
|
||||
}
|
||||
|
||||
try {
|
||||
\assert(false === true, new \Exception());
|
||||
$this->skippedTests['testGetInvalidKeys'] =
|
||||
$this->skippedTests['testGetMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testGetMultipleNoIterable'] =
|
||||
$this->skippedTests['testSetInvalidKeys'] =
|
||||
$this->skippedTests['testSetMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testSetMultipleNoIterable'] =
|
||||
$this->skippedTests['testHasInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteMultipleInvalidKeys'] =
|
||||
$this->skippedTests['testDeleteMultipleNoIterable'] = 'Keys are checked only when assert() is enabled.';
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
public function createSimpleCache(int $defaultLifetime = 0): CacheInterface
|
||||
|
@ -28,14 +28,15 @@ trait AbstractAdapterTrait
|
||||
/**
|
||||
* @var \Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>)
|
||||
*/
|
||||
private $createCacheItem;
|
||||
private static $createCacheItem;
|
||||
|
||||
/**
|
||||
* @var \Closure needs to be set by class, signature is function(array <deferred>, string <namespace>, array <&expiredIds>)
|
||||
*/
|
||||
private $mergeByLifetime;
|
||||
private static $mergeByLifetime;
|
||||
|
||||
private $namespace;
|
||||
private $namespace = '';
|
||||
private $defaultLifetime;
|
||||
private $namespaceVersion = '';
|
||||
private $versioningIsEnabled = false;
|
||||
private $deferred = [];
|
||||
@ -212,7 +213,6 @@ trait AbstractAdapterTrait
|
||||
}
|
||||
$id = $this->getId($key);
|
||||
|
||||
$f = $this->createCacheItem;
|
||||
$isHit = false;
|
||||
$value = null;
|
||||
|
||||
@ -221,12 +221,12 @@ trait AbstractAdapterTrait
|
||||
$isHit = true;
|
||||
}
|
||||
|
||||
return $f($key, $value, $isHit);
|
||||
return (self::$createCacheItem)($key, $value, $isHit);
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]);
|
||||
}
|
||||
|
||||
return $f($key, null, false);
|
||||
return (self::$createCacheItem)($key, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,7 +336,7 @@ trait AbstractAdapterTrait
|
||||
|
||||
private function generateItems(iterable $items, array &$keys): iterable
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$f = self::$createCacheItem;
|
||||
|
||||
try {
|
||||
foreach ($items as $id => $value) {
|
||||
@ -376,7 +376,7 @@ trait AbstractAdapterTrait
|
||||
if (\is_string($key) && isset($this->ids[$key])) {
|
||||
return $this->namespace.$this->namespaceVersion.$this->ids[$key];
|
||||
}
|
||||
CacheItem::validateKey($key);
|
||||
\assert('' !== CacheItem::validateKey($key));
|
||||
$this->ids[$key] = $key;
|
||||
|
||||
if (null === $this->maxIdLength) {
|
||||
|
@ -57,7 +57,7 @@ trait ContractsTrait
|
||||
|
||||
static $setMetadata;
|
||||
|
||||
$setMetadata = $setMetadata ?? \Closure::bind(
|
||||
$setMetadata ?? $setMetadata = \Closure::bind(
|
||||
static function (CacheItem $item, float $startTime, ?array &$metadata) {
|
||||
if ($item->expiry > $endTime = microtime(true)) {
|
||||
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
|
||||
|
Reference in New Issue
Block a user