diff --git a/src/Core/Cache/Capability/ICanCacheInMemory.php b/src/Core/Cache/Capability/ICanCacheInMemory.php index 82492d368a..550273f5f0 100644 --- a/src/Core/Cache/Capability/ICanCacheInMemory.php +++ b/src/Core/Cache/Capability/ICanCacheInMemory.php @@ -53,4 +53,11 @@ interface ICanCacheInMemory extends ICanCache * @throws CachePersistenceException In case the underlying cache driver has errors during persistence */ public function compareDelete(string $key, $value): bool; + + /** + * Returns some basic statistics of the used Cache instance + * + * @return array Returns an associative array of statistics + */ + public function getStats(): array; } diff --git a/src/Core/Cache/Type/APCuCache.php b/src/Core/Cache/Type/APCuCache.php index f1dde2462c..3c72e76c98 100644 --- a/src/Core/Cache/Type/APCuCache.php +++ b/src/Core/Cache/Type/APCuCache.php @@ -147,4 +147,19 @@ class APCuCache extends AbstractCache implements ICanCacheInMemory return true; } + + /** {@inheritDoc} */ + public function getStats(): array + { + $apcu = apcu_cache_info(); + $sma = apcu_sma_info(); + + return [ + 'entries' => $apcu['num_entries'] ?? null, + 'used_memory' => $apcu['mem_size'] ?? null, + 'hits' => $apcu['num_hits'] ?? null, + 'misses' => $apcu['num_misses'] ?? null, + 'avail_mem' => $sma['avail_mem'] ?? null, + ]; + } } diff --git a/src/Core/Cache/Type/ArrayCache.php b/src/Core/Cache/Type/ArrayCache.php index 7fd44deb0a..c6a20d627b 100644 --- a/src/Core/Cache/Type/ArrayCache.php +++ b/src/Core/Cache/Type/ArrayCache.php @@ -96,4 +96,10 @@ class ArrayCache extends AbstractCache implements ICanCacheInMemory return false; } } + + /** {@inheritDoc} */ + public function getStats(): array + { + return []; + } } diff --git a/src/Core/Cache/Type/MemcacheCache.php b/src/Core/Cache/Type/MemcacheCache.php index 14bd5e310b..b2142ffd36 100644 --- a/src/Core/Cache/Type/MemcacheCache.php +++ b/src/Core/Cache/Type/MemcacheCache.php @@ -156,4 +156,21 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl); } + + /** {@inheritDoc} */ + public function getStats(): array + { + $stats = $this->memcache->getStats(); + + return [ + 'version' => $stats['version'] ?? null, + 'entries' => $stats['curr_items'] ?? null, + 'used_memory' => $stats['bytes'] ?? null, + 'uptime' => $stats['uptime'] ?? null, + 'connected_clients' => $stats['curr_connections'] ?? null, + 'hits' => $stats['get_hits'] ?? null, + 'misses' => $stats['get_misses'] ?? null, + 'evictions' => $stats['evictions'] ?? null, + ]; + } } diff --git a/src/Core/Cache/Type/MemcachedCache.php b/src/Core/Cache/Type/MemcachedCache.php index 2e970e6078..53f959fd2b 100644 --- a/src/Core/Cache/Type/MemcachedCache.php +++ b/src/Core/Cache/Type/MemcachedCache.php @@ -172,4 +172,27 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcached->add($cacheKey, $value, $ttl); } + + /** {@inheritDoc} */ + public function getStats(): array + { + $stats = $this->memcached->getStats(); + + // get statistics of the first instance + foreach ($stats as $value) { + $stats = $value; + break; + } + + return [ + 'version' => $stats['version'] ?? null, + 'entries' => $stats['curr_items'] ?? null, + 'used_memory' => $stats['bytes'] ?? null, + 'uptime' => $stats['uptime'] ?? null, + 'connected_clients' => $stats['curr_connections'] ?? null, + 'hits' => $stats['get_hits'] ?? null, + 'misses' => $stats['get_misses'] ?? null, + 'evictions' => $stats['evictions'] ?? null, + ]; + } } diff --git a/src/Core/Cache/Type/ProfilerCacheDecorator.php b/src/Core/Cache/Type/ProfilerCacheDecorator.php index 8071b79c5e..113aa76688 100644 --- a/src/Core/Cache/Type/ProfilerCacheDecorator.php +++ b/src/Core/Cache/Type/ProfilerCacheDecorator.php @@ -166,4 +166,14 @@ class ProfilerCacheDecorator implements ICanCache, ICanCacheInMemory { return $this->cache->getName() . ' (with profiler)'; } + + /** {@inheritDoc} */ + public function getStats(): array + { + if ($this->cache instanceof ICanCacheInMemory) { + return $this->cache->getStats(); + } else { + return []; + } + } } diff --git a/src/Core/Cache/Type/RedisCache.php b/src/Core/Cache/Type/RedisCache.php index cf78d362bb..d005624641 100644 --- a/src/Core/Cache/Type/RedisCache.php +++ b/src/Core/Cache/Type/RedisCache.php @@ -207,4 +207,21 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $this->redis->unwatch(); return false; } + + /** {@inheritDoc} */ + public function getStats(): array + { + $info = $this->redis->info(); + + return [ + 'version' => $info['redis_version'] ?? null, + 'entries' => $this->redis->dbSize() ?? null, + 'used_memory' => $info['used_memory'] ?? null, + 'connected_clients' => $info['connected_clients'] ?? null, + 'uptime' => $info['uptime_in_seconds'] ?? null, + 'hits' => $info['keyspace_hits'] ?? null, + 'misses' => $info['keyspace_misses'] ?? null, + 'evictions' => $info['evicted_keys'] ?? null, + ]; + } } diff --git a/src/Core/Lock/Type/CacheLock.php b/src/Core/Lock/Type/CacheLock.php index c3794d06a7..9fc9fad8f8 100644 --- a/src/Core/Lock/Type/CacheLock.php +++ b/src/Core/Lock/Type/CacheLock.php @@ -156,6 +156,16 @@ class CacheLock extends AbstractLock return $success; } + /** + * Returns stats about the cache provider + * + * @return array + */ + public function getCacheStats(): array + { + return $this->cache->getStats(); + } + /** * @param string $key The original key * diff --git a/tests/src/Core/Cache/APCuCacheTest.php b/tests/src/Core/Cache/APCuCacheTest.php index 117c211b04..47e660b26a 100644 --- a/tests/src/Core/Cache/APCuCacheTest.php +++ b/tests/src/Core/Cache/APCuCacheTest.php @@ -35,4 +35,18 @@ class APCuCacheTest extends MemoryCacheTestCase $this->cache->clear(false); parent::tearDown(); } + + /** + * @small + */ + public function testStats() + { + $stats = $this->instance->getStats(); + + self::assertNotNull($stats['entries']); + self::assertNotNull($stats['used_memory']); + self::assertNotNull($stats['hits']); + self::assertNotNull($stats['misses']); + self::assertNotNull($stats['avail_mem']); + } } diff --git a/tests/src/Core/Cache/MemcacheCacheTest.php b/tests/src/Core/Cache/MemcacheCacheTest.php index abd073f483..c622f22216 100644 --- a/tests/src/Core/Cache/MemcacheCacheTest.php +++ b/tests/src/Core/Cache/MemcacheCacheTest.php @@ -59,4 +59,21 @@ class MemcacheCacheTest extends MemoryCacheTestCase { static::markTestIncomplete('Race condition because of too fast getAllKeys() which uses a workaround'); } + + /** + * @small + */ + public function testStats() + { + $stats = $this->instance->getStats(); + + self::assertNotNull($stats['version']); + self::assertIsNumeric($stats['hits']); + self::assertIsNumeric($stats['misses']); + self::assertIsNumeric($stats['evictions']); + self::assertIsNumeric($stats['entries']); + self::assertIsNumeric($stats['used_memory']); + self::assertGreaterThan(0, $stats['connected_clients']); + self::assertGreaterThan(0, $stats['uptime']); + } } diff --git a/tests/src/Core/Cache/MemcachedCacheTest.php b/tests/src/Core/Cache/MemcachedCacheTest.php index f3b6107b5b..a1c3653f1b 100644 --- a/tests/src/Core/Cache/MemcachedCacheTest.php +++ b/tests/src/Core/Cache/MemcachedCacheTest.php @@ -58,4 +58,21 @@ class MemcachedCacheTest extends MemoryCacheTestCase { static::markTestIncomplete('Race condition because of too fast getAllKeys() which uses a workaround'); } + + /** + * @small + */ + public function testStats() + { + $stats = $this->instance->getStats(); + + self::assertNotNull($stats['version']); + self::assertIsNumeric($stats['hits']); + self::assertIsNumeric($stats['misses']); + self::assertIsNumeric($stats['evictions']); + self::assertIsNumeric($stats['entries']); + self::assertIsNumeric($stats['used_memory']); + self::assertGreaterThan(0, $stats['connected_clients']); + self::assertGreaterThan(0, $stats['uptime']); + } } diff --git a/tests/src/Core/Cache/RedisCacheTest.php b/tests/src/Core/Cache/RedisCacheTest.php index 6169171f40..d16bf5a64c 100644 --- a/tests/src/Core/Cache/RedisCacheTest.php +++ b/tests/src/Core/Cache/RedisCacheTest.php @@ -57,4 +57,21 @@ class RedisCacheTest extends MemoryCacheTestCase $this->cache->clear(false); parent::tearDown(); } + + /** + * @small + */ + public function testStats() + { + $stats = $this->instance->getStats(); + + self::assertNotNull($stats['version']); + self::assertIsNumeric($stats['hits']); + self::assertIsNumeric($stats['misses']); + self::assertIsNumeric($stats['evictions']); + self::assertIsNumeric($stats['entries']); + self::assertIsNumeric($stats['used_memory']); + self::assertGreaterThan(0, $stats['connected_clients']); + self::assertGreaterThan(0, $stats['uptime']); + } }