2021-12-14 18:32:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2023-01-10 22:44:09 +00:00
|
|
|
|
|
|
|
namespace Shimmie2;
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
interface CacheEngine
|
|
|
|
{
|
|
|
|
public function get(string $key);
|
2021-03-14 23:43:50 +00:00
|
|
|
public function set(string $key, $val, int $time=0): void;
|
|
|
|
public function delete(string $key): void;
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class NoCache implements CacheEngine
|
|
|
|
{
|
|
|
|
public function get(string $key)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
public function set(string $key, $val, int $time=0): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
public function delete(string $key): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class MemcachedCache implements CacheEngine
|
|
|
|
{
|
2023-01-11 11:15:26 +00:00
|
|
|
public ?\Memcached $memcache=null;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
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]);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2019-05-28 16:59:38 +00:00
|
|
|
return $val;
|
2023-01-11 11:15:26 +00:00
|
|
|
} elseif ($res == \Memcached::RES_NOTFOUND) {
|
2019-05-28 16:59:38 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
error_log("Memcached error during get($key): $res");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function set(string $key, $val, int $time=0): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
$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) {
|
2019-05-28 16:59:38 +00:00
|
|
|
error_log("Memcached error during set($key): $res");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function delete(string $key): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
$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) {
|
2019-05-28 16:59:38 +00:00
|
|
|
error_log("Memcached error during delete($key): $res");
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function set(string $key, $val, int $time=0): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
apc_store($key, $val, $time);
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function delete(string $key): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
apc_delete($key);
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class RedisCache implements CacheEngine
|
|
|
|
{
|
2023-01-11 11:15:26 +00:00
|
|
|
private \Redis $redis;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function __construct(string $args)
|
|
|
|
{
|
2023-01-11 11:15:26 +00:00
|
|
|
$this->redis = new \Redis();
|
2019-05-28 16:59:38 +00:00
|
|
|
$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:');
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function get(string $key)
|
|
|
|
{
|
|
|
|
return $this->redis->get($key);
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function set(string $key, $val, int $time=0): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
if ($time > 0) {
|
|
|
|
$this->redis->setEx($key, $time, $val);
|
|
|
|
} else {
|
|
|
|
$this->redis->set($key, $val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function delete(string $key): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2019-10-02 10:23:57 +00:00
|
|
|
$this->redis->del($key);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2019-05-26 15:33:26 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class Cache
|
|
|
|
{
|
|
|
|
public $engine;
|
2021-03-14 23:43:50 +00:00
|
|
|
public int $hits=0;
|
|
|
|
public int $misses=0;
|
|
|
|
public int $time=0;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function __construct(?string $dsn)
|
|
|
|
{
|
|
|
|
$matches = [];
|
2019-05-28 19:27:23 +00:00
|
|
|
$c = null;
|
2019-07-07 09:26:31 +00:00
|
|
|
if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches) && !isset($_GET['DISABLE_CACHE'])) {
|
2022-11-13 01:33:03 +00:00
|
|
|
if ($matches[1] == "memcached" || $matches[1] == "memcache") {
|
2019-05-28 16:59:38 +00:00
|
|
|
$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();
|
|
|
|
}
|
|
|
|
$this->engine = $c;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function get(string $key)
|
|
|
|
{
|
2019-07-07 12:58:39 +00:00
|
|
|
global $_tracer;
|
|
|
|
$_tracer->begin("Cache Query", ["key"=>$key]);
|
2019-05-28 16:59:38 +00:00
|
|
|
$val = $this->engine->get($key);
|
|
|
|
if ($val !== false) {
|
2019-09-29 13:30:55 +00:00
|
|
|
$res = "hit";
|
2019-05-28 16:59:38 +00:00
|
|
|
$this->hits++;
|
|
|
|
} else {
|
2019-09-29 13:30:55 +00:00
|
|
|
$res = "miss";
|
2019-05-28 16:59:38 +00:00
|
|
|
$this->misses++;
|
|
|
|
}
|
2019-07-07 13:07:11 +00:00
|
|
|
$_tracer->end(null, ["result"=>$res]);
|
2019-09-29 13:30:55 +00:00
|
|
|
return $val;
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function set(string $key, $val, int $time=0)
|
|
|
|
{
|
2019-07-07 12:58:39 +00:00
|
|
|
global $_tracer;
|
|
|
|
$_tracer->begin("Cache Set", ["key"=>$key, "time"=>$time]);
|
2019-05-28 16:59:38 +00:00
|
|
|
$this->engine->set($key, $val, $time);
|
2019-07-07 12:58:39 +00:00
|
|
|
$_tracer->end();
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function delete(string $key)
|
|
|
|
{
|
2019-07-07 12:58:39 +00:00
|
|
|
global $_tracer;
|
|
|
|
$_tracer->begin("Cache Delete", ["key"=>$key]);
|
2019-05-28 16:59:38 +00:00
|
|
|
$this->engine->delete($key);
|
2019-07-07 12:58:39 +00:00
|
|
|
$_tracer->end();
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function get_hits(): int
|
|
|
|
{
|
|
|
|
return $this->hits;
|
|
|
|
}
|
|
|
|
public function get_misses(): int
|
|
|
|
{
|
|
|
|
return $this->misses;
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|