8000 Merge branch '3.4' into 4.4 · phpfour/symfony@701161e · GitHub
[go: up one dir, main page]

Skip to content

Commit 701161e

Browse files
Merge branch '3.4' into 4.4
* 3.4: [Cache] Use the default expiry when saving (not when creating) items
2 parents 0db52e1 + a397c49 commit 701161e

File tree

8 files changed

+144
-29
lines changed

8 files changed

+144
-29
lines changed

src/Symfony/Component/Cache/Adapter/AbstractAdapter.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@ protected function __construct(string $namespace = '', int $defaultLifetime = 0)
4343
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
4444
}
4545
$this->createCacheItem = \Closure::bind(
46-
static function ($key, $value, $isHit) use ($defaultLifetime) {
46+
static function ($key, $value, $isHit) {
4747
$item = new CacheItem();
4848
$item->key = $key;
4949
$item->value = $v = $value;
5050
$item->isHit = $isHit;
51-
$item->defaultLifetime = $defaultLifetime;
5251
// Detect wrapped values that encode for their expiry and creation duration
5352
// For compactness, these values are packed in the key of an array using
5453
// magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
@@ -66,15 +65,17 @@ static function ($key, $value, $isHit) use ($defaultLifetime) {
6665
);
6766
$getId = \Closure::fromCallable([$this, 'getId']);
6867
$this->mergeByLifetime = \Closure::bind(
69-
static function ($deferred, $namespace, &$expiredIds) use ($getId) {
68+
static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) {
7069
$byLifetime = [];
7170
$now = microtime(true);
7271
$expiredIds = [];
7372

7473
foreach ($deferred as $key => $item) {
7574
$key = (string) $key;
7675
if (null === $item->expiry) {
77-
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
76+
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
77+
} elseif (0 === $item->expiry) {
78+
$ttl = 0;
7879
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
7980
$expiredIds[] = $getId($key);
8081
continue;
341A

src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,9 @@ protected function __construct(string $namespace = '', int $defaultLifetime = 0)
4444
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
4545
}
4646
$this->createCacheItem = \Closure::bind(
47-
static function ($key, $value, $isHit) use ($defaultLifetime) {
47+
static function ($key, $value, $isHit) {
4848
$item = new CacheItem();
4949
$item->key = $key;
50-
$item->defaultLifetime = $defaultLifetime;
5150
$item->isTaggable = true;
5251
// If structure does not match what we expect return item as is (no value and not a hit)
5352
if (!\is_array($value) || !\array_key_exists('value', $value)) {
@@ -72,15 +71,17 @@ static function ($key, $value, $isHit) use ($defaultLifetime) {
7271
$getId = \Closure::fromCallable([$this, 'getId']);
7372
$tagPrefix = self::TAGS_PREFIX;
7473
$this->mergeByLifetime = \Closure::bind(
75-
static function ($deferred, &$expiredIds) use ($getId, $tagPrefix) {
74+
static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifetime) {
7675
$byLifetime = [];
7776
$now = microtime(true);
7877
$expiredIds = [];
7978

8079
foreach ($deferred as $key => $item) {
8180
$key = (string) $key;
8281
if (null === $item->expiry) {
83-
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
82+
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
83+
} elseif (0 === $item->expiry) {
84+
$ttl = 0;
8485
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
8586
$expiredIds[] = $getId($key);
8687
continue;

src/Symfony/Component/Cache/Adapter/ArrayAdapter.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,21 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
2626
use ArrayTrait;
2727

2828
private $createCacheItem;
29+
private $defaultLifetime;
2930

3031
/**
3132
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
3233
*/
3334
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
3435
{
36+
$this->defaultLifetime = $defaultLifetime;
3537
$this->storeSerialized = $storeSerialized;
3638
$this->createCacheItem = \Closure::bind(
37-
static function ($key, $value, $isHit) use ($defaultLifetime) {
39+
static function ($key, $value, $isHit) {
3840
$item = new CacheItem();
3941
$item->key = $key;
4042
$item->value = $value;
4143
$item->isHit = $isHit;
42-
$item->defaultLifetime = $defaultLifetime;
4344

4445
return $item;
4546
},
@@ -131,8 +132,8 @@ public function save(CacheItemInterface $item)
131132
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
132133
return false;
133134
}
134-
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
135-
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];
135+
if (null === $expiry && 0 < $this->defaultLifetime) {
136+
$expiry = microtime(true) + $this->defaultLifetime;
136137
}
137138

138139
$this->values[$key] = $value;

src/Symfony/Component/Cache/Adapter/ChainAdapter.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,11 @@ static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifeti
7070
unset($sourceMetadata[CacheItem::METADATA_TAGS]);
7171

7272
$item->value = $sourceItem->value;
73-
$item->expiry = $sourceMetadata[CacheItem::METADATA_EXPIRY] ?? $sourceItem->expiry;
7473
$item->isHit = $sourceItem->isHit;
7574
$item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata;
7675

77-
if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) {
78-
$defaultLifetime = $sourceItem->defaultLifetime;
79-
}
80-
if (0 < $defaultLifetime && ($item->defaultLifetime <= 0 || $defaultLifetime < $item->defaultLifetime)) {
81-
$item->defaultLifetime = $defaultLifetime;
76+
if (0 < $defaultLifetime) {
77+
$item->expiresAfter($defaultLifetime);
8278
}
8379

8480
return $item;

src/Symfony/Component/Cache/Adapter/ProxyAdapter.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
3333
private $createCacheItem;
3434
private $setInnerItem;
3535
private $poolHash;
36+
private $defaultLifetime;
3637

3738
public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
3839
{
3940
$this->pool = $pool;
4041
$this->poolHash = $poolHash = spl_object_hash($pool);
4142
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace);
4243
$this->namespaceLen = \strlen($namespace);
44+
$this->defaultLifetime = $defaultLifetime;
4345
$this->createCacheItem = \Closure::bind(
44-
static function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
46+
static function ($key, $innerItem) use ($poolHash) {
4547
$item = new CacheItem();
4648
$item->key = $key;
4749

@@ -52,7 +54,6 @@ static function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
5254
$item->value = $v = $innerItem->get();
5355
$item->isHit = $innerItem->isHit();
5456
$item->innerItem = $innerItem;
55-
$item->defaultLifetime = $defaultLifetime;
5657
$item->poolHash = $poolHash;
5758

5859
// Detect wrapped values that encode for their expiry and creation duration
@@ -227,8 +228,8 @@ private function doSave(CacheItemInterface $item, string $method)
227228
return false;
228229
}
229230
$item = (array) $item;
230-
if (null === $item["\0*\0expiry"] && 0 < $item["\0*\0defaultLifetime"]) {
231-
$item["\0*\0expiry"] = microtime(true) + $item["\0*\0defaultLifetime"];
231+
if (null === $item["\0*\0expiry"] && 0 < $this->defaultLifetime) {
232+
$item["\0*\0expiry"] = microtime(true) + $this->defaultLifetime;
232233
}
233234

234235
if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {

src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ static function ($key, $value, CacheItem $protoItem) {
4949
$item = new CacheItem();
5050
$item->key = $key;
5151
$item->value = $value;
52-
$item->defaultLifetime = $protoItem->defaultLifetime;
5352
$item->expiry = $protoItem->expiry;
5453
$item->poolHash = $protoItem->poolHash;
5554

@@ -94,8 +93,7 @@ static function ($deferred) {
9493
$this->invalidateTags = \Closure::bind(
9594
static function (AdapterInterface $tagsAdapter, array $tags) {
9695
foreach ($tags as $v) {
97-
$v->defaultLifetime = 0;
98-
$v->expiry = null;
96+
$v->expiry = 0;
9997
$tagsAdapter->saveDeferred($v);
10098
}
10199

src/Symfony/Component/Cache/CacheItem.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ final class CacheItem implements ItemInterface
2727
protected $value;
2828
protected $isHit = false;
2929
protected $expiry;
30-
protected $defaultLifetime;
3130
protected $metadata = [];
3231
protected $newMetadata = [];
3332
protected $innerItem;
@@ -78,7 +77,7 @@ public function set($value): self
7877
public function expiresAt($expiration): self
7978
{
8079
if (null === $expiration) {
81-
$this->expiry = $this->defaultLifetime > 0 ? microtime(true) + $this->defaultLifetime : null;
80+
$this->expiry = null;
8281
} elseif ($expiration instanceof \DateTimeInterface) {
8382
$this->expiry = (float) $expiration->format('U.u');
8483
} else {
@@ -96,7 +95,7 @@ public function expiresAt($expiration): self
9695
public function expiresAfter($time): self
9796
{
9897
if (null === $time) {
99-
$this->expiry = $this->defaultLifetime > 0 ? microtime(true) + $this->defaultLifetime : null;
98+
$this->expiry = null;
10099
} elseif ($time instanceof \DateInterval) {
101100
$this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
102101
} elseif (\is_int($time)) {

src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function createCachePool(int $defaultLifetime = 0, string $testMethod = n
3131
return new ChainAdapter([new FilesystemAdapter('a', $defaultLifetime), new FilesystemAdapter('b', $defaultLifetime)], $defaultLifetime);
3232
}
3333

34-
return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter(), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime);
34+
return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter($defaultLifetime), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime);
3535
}
3636

3737
public function testEmptyAdaptersException()
@@ -69,6 +69,124 @@ public function testPrune()
6969
$this->assertFalse($cache->prune());
7070
}
7171

72+
public function testMultipleCachesExpirationWhenCommonTtlIsNotSet()
73+
{
74+
if (isset($this->skippedTests[__FUNCTION__])) {
75+
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
76+
}
77+
78+
$adapter1 = new ArrayAdapter(4);
79+
$adapter2 = new ArrayAdapter(2);
80+
81+
$cache = new ChainAdapter([$adapter1, $adapter2]);
82+
83+
$cache->save($cache->getItem('key')->set('value'));
84+
85+
$item = $adapter1->getItem('key');
86+
$this->assertTrue($item->isHit());
87+
$this->assertEquals('value', $item->get());
88+
89+
$item = $adapter2->getItem('key');
90+
$this->assertTrue($item->isHit());
91+
$this->assertEquals('value', $item->get());
92+
93+
sleep(2);
94+
95+
$item = $adapter1->getItem('key');
96+
$this->assertTrue($item->isHit());
97+
$this->assertEquals('value', $item->get());
98+
99+
$item = $adapter2->getItem('key');
100+
$this->assertFalse($item->isHit());
101+
102+
sleep(2);
103+
104+
$item = $adapter1->getItem('key');
105+
$this->assertFalse($item->isHit());
106+
107+
$adapter2->save($adapter2->getItem('key1')->set('value1'));
108+
109+
$item = $cache->getItem('key1');
110+
$this->assertTrue($item->isHit());
111+
$this->assertEquals('value1', $item->get());
112+
113+
sleep(2);
114+
115+
$item = $adapter1->getItem('key1');
116+
$this->assertTrue($item->isHit());
117+
$this->assertEquals('value1', $item->get());
118+
119+
$item = $adapter2->getItem('key1');
120+
$this->assertFalse($item->isHit());
121+
122+
sleep(2);
123+
124+
$item = $adapter1->getItem('key1');
125+
$this->assertFalse($item->isHit());
126+
}
127+
128+
public function testMultipleCachesExpirationWhenCommonTtlIsSet()
129+
{
130+
if (isset($this->skippedTests[__FUNCTION__])) {
131+
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
132+
}
133+
134+
$adapter1 = new ArrayAdapter(4);
135+
$adapter2 = new ArrayAdapter(2);
136+
137+
$cache = new ChainAdapter([$adapter1, $adapter2], 6);
138+
139+
$cache->save($cache->getItem('key')->set('value'));
140+
141+
$item = $adapter1->getItem('key');
142+
$this->assertTrue($item->isHit());
143+
$this->assertEquals('value', $item->get());
144+
145+
$item = $adapter2->getItem('key');
146+
$this->assertTrue($item->isHit());
147+
$this->assertEquals('value', $item->get());
148+
149+
sleep(2);
150+
151+
$item = $adapter1->getItem('key');
152+
$this->assertTrue($item->isHit());
153+
$this->assertEquals('value', $item->get());
154+
155+
$item = $adapter2->getItem('key');
156+
$this->assertFalse($item->isHit());
157+
158+
sleep(2);
159+
160+
$item = $adapter1->getItem('key');
161+
$this->assertFalse($item->isHit());
162+
163+
$adapter2->save($adapter2->getItem('key1')->set('value1'));
164+
165+
$item = $cache->getItem('key1');
166+
$this->assertTrue($item->isHit());
167+
$this->assertEquals('value1', $item->get());
168+
169+
sleep(2);
170+
171+
$item = $adapter1->getItem('key1');
172+
$this->assertTrue($item->isHit());
173+
$this->assertEquals('value1', $item->get());
174+
175+
$item = $adapter2->getItem('key1');
176+
$this->assertFalse($item->isHit());
177+
178+
sleep(2);
179+
180+
$item = $adapter1->getItem('key1');
181+
$this->assertTrue($item->isHit());
182+
$this->assertEquals('value1', $item->get());
183+
184+
sleep(2);
185+
186+
$item = $adapter1->getItem('key1');
187+
$this->assertFalse($item->isHit());
188+
}
189+
72190
private function getPruneableMock(): AdapterInterface
73191
{
74192
$pruneable = $this->createMock([PruneableInterface::class, AdapterInterface::class]);

0 commit comments

Comments
 (0)
0