139 lines
3.4 KiB
PHP
139 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Database\Cache;
|
|
|
|
/**
|
|
* Einfache Cache-Strategy als Fallback wenn kein Framework-Cache verfügbar
|
|
*/
|
|
final class SimpleCacheStrategy implements CacheStrategy
|
|
{
|
|
private array $cache = [];
|
|
private array $expiry = [];
|
|
private array $stats = [
|
|
'hits' => 0,
|
|
'misses' => 0,
|
|
'sets' => 0,
|
|
'deletes' => 0,
|
|
'invalidations' => 0,
|
|
];
|
|
|
|
public function __construct(
|
|
private readonly string $keyPrefix = 'db_query:'
|
|
) {}
|
|
|
|
public function set(QueryCacheKey $key, array $value, int $ttlSeconds): bool
|
|
{
|
|
$keyString = $this->keyPrefix . $key->toString();
|
|
|
|
$this->cache[$keyString] = $value;
|
|
$this->expiry[$keyString] = time() + $ttlSeconds;
|
|
$this->stats['sets']++;
|
|
|
|
return true;
|
|
}
|
|
|
|
public function get(QueryCacheKey $key): ?array
|
|
{
|
|
$keyString = $this->keyPrefix . $key->toString();
|
|
|
|
// Prüfe Ablauf
|
|
if (isset($this->expiry[$keyString]) && time() > $this->expiry[$keyString]) {
|
|
$this->delete($key);
|
|
$this->stats['misses']++;
|
|
return null;
|
|
}
|
|
|
|
if (isset($this->cache[$keyString])) {
|
|
$this->stats['hits']++;
|
|
return $this->cache[$keyString];
|
|
}
|
|
|
|
$this->stats['misses']++;
|
|
return null;
|
|
}
|
|
|
|
public function has(QueryCacheKey $key): bool
|
|
{
|
|
return $this->get($key) !== null;
|
|
}
|
|
|
|
public function delete(QueryCacheKey $key): bool
|
|
{
|
|
$keyString = $this->keyPrefix . $key->toString();
|
|
|
|
$existed = isset($this->cache[$keyString]);
|
|
|
|
unset($this->cache[$keyString], $this->expiry[$keyString]);
|
|
|
|
if ($existed) {
|
|
$this->stats['deletes']++;
|
|
}
|
|
|
|
return $existed;
|
|
}
|
|
|
|
public function invalidatePattern(string $pattern): int
|
|
{
|
|
$deleted = 0;
|
|
|
|
foreach (array_keys($this->cache) as $keyString) {
|
|
if (fnmatch($pattern, $keyString)) {
|
|
unset($this->cache[$keyString], $this->expiry[$keyString]);
|
|
$deleted++;
|
|
}
|
|
}
|
|
|
|
$this->stats['invalidations'] += $deleted;
|
|
return $deleted;
|
|
}
|
|
|
|
public function clear(): void
|
|
{
|
|
$count = count($this->cache);
|
|
$this->cache = [];
|
|
$this->expiry = [];
|
|
$this->stats['invalidations'] += $count;
|
|
}
|
|
|
|
public function getStats(): array
|
|
{
|
|
return array_merge($this->stats, [
|
|
'size' => count($this->cache),
|
|
'memory_usage' => $this->estimateMemoryUsage(),
|
|
'hit_ratio' => $this->calculateHitRatio(),
|
|
'cache_type' => 'SimpleCacheStrategy'
|
|
]);
|
|
}
|
|
|
|
private function estimateMemoryUsage(): int
|
|
{
|
|
return memory_get_usage() - memory_get_usage(true); // Grobe Schätzung
|
|
}
|
|
|
|
private function calculateHitRatio(): float
|
|
{
|
|
$total = $this->stats['hits'] + $this->stats['misses'];
|
|
return $total > 0 ? ($this->stats['hits'] / $total) : 0.0;
|
|
}
|
|
|
|
/**
|
|
* Bereinigt abgelaufene Einträge
|
|
*/
|
|
public function cleanup(): int
|
|
{
|
|
$currentTime = time();
|
|
$cleaned = 0;
|
|
|
|
foreach ($this->expiry as $keyString => $expiry) {
|
|
if ($currentTime > $expiry) {
|
|
unset($this->cache[$keyString], $this->expiry[$keyString]);
|
|
$cleaned++;
|
|
}
|
|
}
|
|
|
|
return $cleaned;
|
|
}
|
|
}
|