2024-10-02 21:49:51 +02:00
|
|
|
<?php
|
|
|
|
|
namespace Vichan\Data\Driver;
|
|
|
|
|
|
|
|
|
|
defined('TINYBOARD') or exit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MemcachedCacheDriver implements CacheDriver {
|
2025-05-29 23:55:04 +02:00
|
|
|
use CacheDriverTrait;
|
|
|
|
|
|
2024-10-02 21:49:51 +02:00
|
|
|
private \Memcached $inner;
|
|
|
|
|
|
2025-05-29 23:55:04 +02:00
|
|
|
|
|
|
|
|
public function __construct(string $prefix, string $server_uri, int $server_port, int $server_weight) {
|
2024-10-02 21:49:51 +02:00
|
|
|
$this->inner = new \Memcached();
|
|
|
|
|
if (!$this->inner->setOption(\Memcached::OPT_BINARY_PROTOCOL, true)) {
|
|
|
|
|
throw new \RuntimeException('Unable to set the memcached protocol!');
|
|
|
|
|
}
|
|
|
|
|
if (!$this->inner->setOption(\Memcached::OPT_PREFIX_KEY, $prefix)) {
|
|
|
|
|
throw new \RuntimeException('Unable to set the memcached prefix!');
|
|
|
|
|
}
|
2025-05-29 23:55:04 +02:00
|
|
|
|
|
|
|
|
$maybe_unix_path = self::asUnixSocketPath($server_uri);
|
|
|
|
|
$is_unix = $maybe_unix_path !== null;
|
|
|
|
|
if ($is_unix) {
|
|
|
|
|
$server_uri = $maybe_unix_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Memcached keeps the server connections open across requests.
|
|
|
|
|
$current_servers = $this->inner->getServerList();
|
|
|
|
|
$found_in_curr = false;
|
|
|
|
|
foreach ($current_servers as $curr) {
|
|
|
|
|
// Ignore the port if the server is connected with a unix socket.
|
|
|
|
|
if ($curr['host'] === $server_uri && ($is_unix || $curr['port'] === $server_port)) {
|
|
|
|
|
$found_in_curr = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$found_in_curr) {
|
|
|
|
|
if (!empty($current_servers)) {
|
|
|
|
|
if ($this->inner->resetServerList()) {
|
|
|
|
|
throw new \RuntimeException('Unable to reset the memcached server list!');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->inner->addServer($server_uri, $server_port, $server_weight)) {
|
|
|
|
|
throw new \RuntimeException('Unable to add memcached servers!');
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-02 21:49:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function get(string $key): mixed {
|
|
|
|
|
$ret = $this->inner->get($key);
|
|
|
|
|
// If the returned value is false but the retrival was a success, then the value stored was a boolean false.
|
|
|
|
|
if ($ret === false && $this->inner->getResultCode() !== \Memcached::RES_SUCCESS) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
|
|
|
|
$this->inner->set($key, $value, (int)$expires);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function delete(string $key): void {
|
|
|
|
|
$this->inner->delete($key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function flush(): void {
|
|
|
|
|
$this->inner->flush();
|
|
|
|
|
}
|
|
|
|
|
}
|