8000 [Cache] Add StatsInterface · symfony/symfony@a7028cd · GitHub
[go: up one dir, main page]

Skip to content

Commit a7028cd

Browse files
[Cache] Add StatsInterface
1 parent 80f3410 commit a7028cd

11 files changed

+211
-14
lines changed

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@
1717
use Psr\Log\LoggerAwareTrait;
1818
use Symfony\Component\Cache\CacheItem;
1919
use Symfony\Component\Cache\Exception\InvalidArgumentException;
20+
use Symfony\Component\Cache\StatsInterface;
2021

2122
/**
2223
* @author Nicolas Grekas <p@tchwork.com>
2324
*/
24-
abstract class AbstractAdapter implements CacheItemPoolInterface, LoggerAwareInterface
25+
abstract class AbstractAdapter implements CacheItemPoolInterface, LoggerAwareInterface, StatsInterface
2526
{
2627
use LoggerAwareTrait;
2728

2829
private $namespace;
2930
private $deferred = array();
3031
private $createCacheItem;
3132
private $mergeByLifetime;
33+
private $hits = 0;
34+
private $misses = 0;
3235

3336
protected function __construct($namespace = '', $defaultLifetime = 0)
3437
{
@@ -133,6 +136,11 @@ public function getItem($key)
133136
} catch (\Exception $e) {
134137
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', array('key' => $key, 'exception' => $e));
135138
}
139+
if ($isHit) {
140+
++$this->hits;
141+
} else {
142+
++$this->misses;
143+
}
136144

137145
return $f($key, $value, $isHit);
138146
}
@@ -351,12 +359,28 @@ private function generateItems($items, &$keys)
351359
$f = $this->createCacheItem;
352360

353361
foreach ($items as $id => $value) {
362+
++$this->hits;
354363
yield $keys[$id] => $f($keys[$id], $value, true);
355364
unset($keys[$id]);
356365
}
357366

358367
foreach ($keys as $key) {
368+
++$this->misses;
359369
yield $key => $f($key, null, false);
360370
}
361371
}
372+
373+
/**
374+
* {@inheritdoc}
375+
*/
376+
public function getStats()
377+
{
378+
return array(
379+
StatsInterface::STATS_HITS => $this->hits,
380+
StatsInterface::STATS_MISSES => $this->misses,
381+
StatsInterface::STATS_UPTIME => null,
382+
StatsInterface::STATS_MEMORY_USAGE => null,
383+
StatsInterface::STATS_MEMORY_AVAILABLE => null,
384+
);
385+
}
362386
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Symfony\Component\Cache\Exception\CacheException;
15+
use Symfony\Component\Cache\StatsInterface;
1516

1617
/**
1718
* @author Nicolas Grekas <p@tchwork.com>
1819
*/
19-
class ApcuAdapter extends AbstractAdapter
20+
class ApcuAdapter extends AbstractAdapter implements StatsInterface
2021
{
2122
public function __construct($namespace = '', $defaultLifetime = 0)
2223
{
@@ -72,4 +73,21 @@ protected function doSave(array $values, $lifetime)
7273
{
7374
return array_keys(apcu_store($values, null, $lifetime));
7475
}
76+
77+
/**
78+
* {@inheritdoc}
79+
*/
80+
public function getStats()
81+
{
82+
$cache = apcu_cache_info(true);
83+
$sma = apcu_sma_info();
84+
85+
return array(
86+
StatsInterface::STATS_HITS => (int) (isset($cache['num_hits']) ? $cache['num_hits'] : $cache['nhits']),
87+
StatsInterface::STATS_MISSES => (int) (isset($cache['num_misses']) ? $cache['num_misses'] : $cache['nmisses']),
88+
StatsInterface::STATS_UPTIME => (int) (isset($cache['start_time']) ? $cache['start_time'] : $cache['stime']),
89+
StatsInterface::STATS_MEMORY_USAGE => (int) $cache['mem_size'],
90+
StatsInterface::STATS_MEMORY_AVAILABLE => (int) $sma['avail_mem'],
91+
);
92+
}
7593
}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@
1717
use Psr\Log\LoggerAwareTrait;
1818
use Symfony\Component\Cache\CacheItem;
1919
use Symfony\Component\Cache\Exception\InvalidArgumentException;
20+
use Symfony\Component\Cache\StatsInterface;
2021

2122
/**
2223
* @author Nicolas Grekas <p@tchwork.com>
2324
*/
24-
class ArrayAdapter implements CacheItemPoolInterface, LoggerAwareInterface
25+
class ArrayAdapter implements CacheItemPoolInterface, LoggerAwareInterface, StatsInterface
2526
{
2627
use LoggerAwareTrait;
2728

2829
private $storeSerialized;
2930
private $values = array();
3031
private $expiries = array();
3132
private $createCacheItem;
33+
private $hits = 0;
34+
private $misses = 0;
3235

3336
/**
3437
* @param int $defaultLifetime
@@ -59,10 +62,13 @@ public function getItem($key)
5962
{
6063
if (!$isHit = $this->hasItem($key)) {
6164
$value = null;
65+
++$this->misses;
6266
} elseif ($this->storeSerialized) {
6367
$value = unserialize($this->values[$key]);
68+
++$this->hits;
6469
} else {
6570
$value = $this->values[$key];
71+
++$this->hits;
6672
}
6773
$f = $this->createCacheItem;
6874

@@ -192,13 +198,30 @@ private function generateItems(array $keys, $now)
192198
foreach ($keys as $key) {
193199
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
194200
$value = null;
201+
++$this->misses;
195202
} elseif ($this->storeSerialized) {
196203
$value = unserialize($this->values[$key]);
204+
++$this->hits;
197205
} else {
198206
$value = $this->values[$key];
207+
++$this->hits;
199208
}
200209

201210
yield $key => $f($key, $value, $isHit);
202211
}
203212
}
213+
214+
/**
215+
* {@inheritdoc}
216+
*/
217+
public function getStats()
218+
{
219+
return array(
220+
StatsInterface::STATS_HITS => $this->hits,
221+
StatsInterface::STATS_MISSES => $this->misses,
222+
StatsInterface::STATS_UPTIME => null,
223+
StatsInterface::STATS_MEMORY_USAGE => null,
224+
StatsInterface::STATS_MEMORY_AVAILABLE => null,
225+
);
226+
}
204227
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,12 @@ protected function doSave(array $values, $lifetime)
7070
{
7171
return $this->provider->saveMultiple($values, $lifetime);
7272
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function getStats()
78+
{
79+
return $this->provider->getStats() ?: parent::getStats();
80+
}
7381
}

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Cache\CacheItemPoolInterface;
1616
use Symfony\Component\Cache\CacheItem;
17+
use Symfony\Component\Cache\StatsInterface;
1718

1819
/**
1920
* @author Nicolas Grekas <p@tchwork.com>
2021
*/
21-
class ProxyAdapter implements CacheItemPoolInterface
22+
class ProxyAdapter implements CacheItemPoolInterface, StatsInterface
2223
{
2324
private $pool;
2425
private $createCacheItem;
26+
private $compatiblePoolItems;
27+
private $hits = 0;
28+
private $misses = 0;
2529

2630
public function __construct(CacheItemPoolInterface $pool)
2731
{
@@ -47,8 +51,16 @@ public function getItem($key)
4751
{
4852
$f = $this->createCacheItem;
4953
$item = $this->pool->getItem($key);
54+
if ($isHit = $item->isHit()) {
55+
++$this->hits;
56+
} else {
57+
++$this->misses;
58+
}
59+
if (null === $this->compatiblePoolItems) {
60+
$this->compatiblePoolItems = $item instanceof CacheItem;
61+
}
5062

51-
return $f($key, $item->get(), $item->isHit());
63+
return $this->compatiblePoolItems ? $item : $f($key, $item->get(), $isHit);
5264
}
5365

5466
/**
@@ -120,6 +132,10 @@ private function doSave(CacheItemInterface $item, $method)
120132
if (!$item instanceof CacheItem) {
121133
return false;
122134
}
135+
if ($this->compatiblePoolItems) {
136+
return $this->pool->$method($item);
137+
}
138+
123139
$item = (array) $item;
124140
$expiry = $item[CacheItem::CAST_PREFIX.'expiry'];
125141
$poolItem = $this->pool->getItem($item[CacheItem::CAST_PREFIX.'key']);
@@ -132,9 +148,36 @@ private function doSave(CacheItemInterface $item, $method)
132148
private function generateItems($items)
133149
{
134150
$f = $this->createCacheItem;
151+
$compatible = &$this->compatiblePoolItems;
135152

136153
foreach ($items as $key => $item) {
137-
yield $key => $f($key, $item->get(), $item->isHit());
154+
if (null === $compatible) {
155+
$compatible = $item instanceof CacheItem;
156+
}
157+
if ($isHit = $item->isHit()) {
158+
++$this->hits;
159+
} else {
160+
++$this->misses;
161+
}
162+
yield $key => $compatible ? $item : $f($key, $item->get(), $isHit);
138163
}
139164
}
165+
166+
/**
167+
* {@inheritdoc}
168+
*/
169+
public function getStats()
170+
{
171+
if ($this->pool instanceof StatsInterface) {
172+
return $this->pool->getStats();
173+
}
174+
175+
return array(
176+
StatsInterface::STATS_HITS => $this->hits,
177+
StatsInterface::STATS_MISSES => $this->misses,
178+
StatsInterface::STATS_UPTIME => null,
179+
StatsInterface::STATS_MEMORY_USAGE => null,
180+
StatsInterface::STATS_MEMORY_AVAILABLE => null,
181+
);
182+
}
140183
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache;
13+
14+
/**
15+
* Subset of the Doctrine\Common\Cache\Cache interface.
16+
*/
17+
interface StatsInterface
18+
{
19+
const STATS_HITS = 'hits';
20+
const STATS_MISSES = 'misses';
21+
const STATS_UPTIME = 'uptime';
22+
const STATS_MEMORY_USAGE = 'memory_usage';
23+
const STATS_MEMORY_AVAILABLE = 'memory_available';
24+
25+
/**
26+
* Retrieves cache statistics from the data store.
27+
*
28+
* The statistics array has the following values:
29+
* - hits: Number of keys that have been requested and found present.
30+
* - misses: Number of items that have been requested and not found.
31+
* - uptime: Time that the server is running.
32+
* - memory_usage: Memory used by the server to store items.
33+
* - memory_available: Memory allowed to use for storage.
34+
*
35+
* @return array An associative array with server's statistics.
36+
*/
37+
public function getStats();
38+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Tests\Adapter;
13+
14+
use Cache\IntegrationTests\CachePoolTest;
15+
use Symfony\Component\Cache\StatsInterface;
16+
17+
abstract class AdapterTestCase extends CachePoolTest
18+
{
19+
public function testGetStats()
20+
{
21+
$pool = $this->createCachePool();
22+
23+
if (!$pool instanceof StatsInterface) {
24+
$this->markTestSkipped(StatsInterface::class.' not implemented.');
25+
}
26+
27+
$stats = $pool->getStats();
28+
$keys = array_values((new \ReflectionClass(StatsInterface::class))->getConstants());
29+
$this->assertSame($keys, array_keys($stats));
30+
$this->assertSame(0, $stats['hits']);
31+
32+
$pool->getItem('bar');
33+
$stats = $pool->getStats();
34+
$this->assertGreaterThan(0, $stats['misses']);
35+
36+
$foo = $pool->getItem('foo');
37+
$s = $pool->getStats();
38+
$this->assertSame($stats['hits'], $s['hits']);
39+
$this->assertGreaterThan($stats['misses'], $s['misses']);
40+
41+
$pool->save($foo->set('bar'));
42+
$foo = $pool->getItem('foo');
43+
$s = $pool->getStats();
44+
$this->assertGreaterThan($stats['hits'], $s['hits']);
45+
$this->assertGreaterThan($stats['misses'], $s['misses']);
46+
}
47+
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

14-
use Cache\IntegrationTests\CachePoolTest;
1514
use Symfony\Component\Cache\Adapter\ApcuAdapter;
1615

17-
class ApcuAdapterTest extends CachePoolTest
16+
class ApcuAdapterTest extends AdapterTestCase
1817
{
1918
public function createCachePool()
2019
{

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111

1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

14-
use Cache\IntegrationTests\CachePoolTest;
1514
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1615

1716
/**
1817
* @group time-sensitive
1918
*/
20-
class ArrayAdapterTest extends CachePoolTest
19+
class ArrayAdapterTest extends AdapterTestCase
2120
{
2221
protected $skippedTests = array(
2322
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@
1111

1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

14-
use Cache\IntegrationTests\CachePoolTest;
1514
use Doctrine\Common\Cache\ArrayCache;
1615
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
1716

1817
/**
1918
* @group time-sensitive
2019
*/
21-
class DoctrineAdapterTest extends CachePoolTest
20+
class DoctrineAdapterTest extends AdapterTestCase
2221
{
2322
protected $skippedTests = array(
2423
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',

0 commit comments

Comments
 (0)
0