This repository has been archived on 2024-09-05. You can view files and clone it, but cannot push or open issues or pull requests.
shimmie2/core/cacheengine.php

242 lines
6 KiB
PHP
Raw Normal View History

2021-12-14 18:32:47 +00:00
<?php
declare(strict_types=1);
namespace Shimmie2;
interface CacheEngine
{
public function get(string $key);
public function set(string $key, $val, int $time=0): void;
public function delete(string $key): void;
}
class NoCache implements CacheEngine
{
public function get(string $key)
{
return false;
}
public function set(string $key, $val, int $time=0): void
{
}
public function delete(string $key): void
{
}
}
class MemcachedCache implements CacheEngine
{
2023-01-11 11:15:26 +00:00
public ?\Memcached $memcache=null;
public function __construct(string $args)
{
$hp = explode(":", $args);
2023-01-11 11:15:26 +00:00
$this->memcache = new \Memcached();
#$this->memcache->setOption(\Memcached::OPT_COMPRESSION, False);
#$this->memcache->setOption(\Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP);
#$this->memcache->setOption(\Memcached::OPT_PREFIX_KEY, phpversion());
2019-10-01 23:39:45 +00:00
$this->memcache->addServer($hp[0], (int)$hp[1]);
}
public function get(string $key)
{
$key = urlencode($key);
$val = $this->memcache->get($key);
$res = $this->memcache->getResultCode();
2023-01-11 11:15:26 +00:00
if ($res == \Memcached::RES_SUCCESS) {
return $val;
2023-01-11 11:15:26 +00:00
} elseif ($res == \Memcached::RES_NOTFOUND) {
return false;
} else {
error_log("Memcached error during get($key): $res");
return false;
}
}
public function set(string $key, $val, int $time=0): void
{
$key = urlencode($key);
$this->memcache->set($key, $val, $time);
$res = $this->memcache->getResultCode();
2023-01-11 11:15:26 +00:00
if ($res != \Memcached::RES_SUCCESS) {
error_log("Memcached error during set($key): $res");
}
}
public function delete(string $key): void
{
$key = urlencode($key);
$this->memcache->delete($key);
$res = $this->memcache->getResultCode();
2023-01-11 11:15:26 +00:00
if ($res != \Memcached::RES_SUCCESS && $res != \Memcached::RES_NOTFOUND) {
error_log("Memcached error during delete($key): $res");
}
}
}
class APCCache implements CacheEngine
{
public function __construct(string $args)
{
// $args is not used, but is passed in when APC cache is created.
}
public function get(string $key)
{
return apc_fetch($key);
}
public function set(string $key, $val, int $time=0): void
{
apc_store($key, $val, $time);
}
public function delete(string $key): void
{
apc_delete($key);
}
}
class RedisCache implements CacheEngine
{
2023-01-11 11:15:26 +00:00
private \Redis $redis;
public function __construct(string $args)
{
2023-01-11 11:15:26 +00:00
$this->redis = new \Redis();
$hp = explode(":", $args);
2019-10-01 23:39:45 +00:00
$this->redis->pconnect($hp[0], (int)$hp[1]);
2023-01-11 11:15:26 +00:00
$this->redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
$this->redis->setOption(\Redis::OPT_PREFIX, 'shm:');
}
public function get(string $key)
{
return $this->redis->get($key);
}
public function set(string $key, $val, int $time=0): void
{
if ($time > 0) {
$this->redis->setEx($key, $time, $val);
} else {
$this->redis->set($key, $val);
}
}
public function delete(string $key): void
{
$this->redis->del($key);
}
2019-05-26 15:33:26 +00:00
}
class CacheWithStats implements \Psr\SimpleCache\CacheInterface
{
public $engine;
public int $hits=0;
public int $misses=0;
public int $time=0;
public function __construct(CacheEngine $c)
{
$this->engine = $c;
}
public function get(string $key, mixed $default=null): mixed
{
2019-07-07 12:58:39 +00:00
global $_tracer;
$_tracer->begin("Cache Query", ["key"=>$key]);
$val = $this->engine->get($key);
if ($val !== false) {
2019-09-29 13:30:55 +00:00
$res = "hit";
$this->hits++;
} else {
2019-09-29 13:30:55 +00:00
$res = "miss";
$val = $default;
$this->misses++;
}
$_tracer->end(null, ["result"=>$res]);
2019-09-29 13:30:55 +00:00
return $val;
}
public function set(string $key, mixed $value, \DateInterval|int|null $ttl = null): bool
{
2019-07-07 12:58:39 +00:00
global $_tracer;
$_tracer->begin("Cache Set", ["key"=>$key, "ttl"=>$ttl]);
$this->engine->set($key, $value, $ttl ?? 0);
2019-07-07 12:58:39 +00:00
$_tracer->end();
return true;
}
public function delete(string $key): bool
{
2019-07-07 12:58:39 +00:00
global $_tracer;
$_tracer->begin("Cache Delete", ["key"=>$key]);
$this->engine->delete($key);
2019-07-07 12:58:39 +00:00
$_tracer->end();
return true;
}
public function clear(): bool
{
throw new Exception("Not implemented");
}
public function getMultiple(iterable $keys, mixed $default = null): iterable
{
$results = [];
foreach($keys as $key) {
$results[$key] = $this->get($key, $default);
}
return $results;
}
public function setMultiple(iterable $values, \DateInterval|int|null $ttl = null): bool {
foreach($values as $key => $value) {
$this->set($key, $value, $ttl);
}
return true;
}
public function deleteMultiple(iterable $keys): bool {
foreach($keys as $key) {
$this->delete($key);
}
}
public function has(string $key): bool {
$sentinel = 4345345735673;
return $this->get($key, $sentinel) != $sentinel;
}
public function get_hits(): int
{
return $this->hits;
}
public function get_misses(): int
{
return $this->misses;
}
}
function loadCache(?string $dsn): CacheWithStats {
$matches = [];
$c = null;
if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches) && !isset($_GET['DISABLE_CACHE'])) {
if ($matches[1] == "memcached" || $matches[1] == "memcache") {
$c = new MemcachedCache($matches[2]);
} elseif ($matches[1] == "apc") {
$c = new APCCache($matches[2]);
} elseif ($matches[1] == "redis") {
$c = new RedisCache($matches[2]);
}
} else {
$c = new NoCache();
}
return new CacheWithStats($c);
}