Newer
Older
namespace Studip\Cache;
use Memcached;
use Psr\Cache\CacheItemInterface;
/**
* Cache implementation using memcached.
*
* @author Marcus Lunzenauer <mlunzena@uos.de>
* @license GPL2 or any later version
class MemcachedCache extends Cache
private Memcached $memcache;
/**
* @return string A translateable display name for this cache class.
*/
public static function getDisplayName(): string
{
return _('Memcached');
}
public function __construct($servers)
{
if (!extension_loaded('memcached')) {
throw new \Exception('Memcache extension missing.');
$prefix = \Config::get()->STUDIP_INSTALLATION_ID;
$this->memcache = new Memcached(md5(json_encode($servers)));
if (count($this->memcache->getServerList()) === 0) {
// Set options (see https://www.php.net/manual/en/memcached.addservers.php#118940)
$this->memcache->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$this->memcache->setOption(Memcached::OPT_SERVER_FAILURE_LIMIT, 2);
$this->memcache->setOption(Memcached::OPT_REMOVE_FAILED_SERVERS, true);
$this->memcache->setOption(Memcached::OPT_RETRY_TIMEOUT, 1);
$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, $prefix);
$status = $this->memcache->addServers(
array_map(
function ($server) {
return [$server['hostname'], (int) $server['port']];
},
$servers
)
);
if (!$status) {
throw new \Exception('Could not add memcached servers');
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
}
}
}
/**
* Expire item from the cache.
*
* Example:
*
* # expires foo
* $cache->expire('foo');
*
* @param string $arg a single key.
* @returns void
*/
public function expire($arg)
{
$key = $this->getCacheKey($arg);
$this->memcache->delete($key);
}
/**
* Expire all items from the cache.
*/
public function flush()
{
$this->memcache->flush();
}
/**
* Return statistics.
*
* @StudipCache::getStats()
*
* @return array|array[]
*/
public function getStats(): array
{
return $this->memcache->getStats();
}
/**
* Return the Vue component name and props that handle configuration.
*
* @see Cache::getConfig()
*
* @return array
*/
public static function getConfig(): array
{
$currentCache = \Config::get()->SYSTEMCACHE;
// Set default config for this cache
$currentConfig = [
'servers' => []
];
// If this cache is set as system cache, use config from global settings.
if ($currentCache['type'] == __CLASS__) {
$currentConfig = $currentCache['config'];
}
return [
'component' => 'MemcachedCacheConfig',
'props' => $currentConfig
];
}
/**
* @inheritDoc
*/
public function getItem(string $key): CacheItemInterface
{
$item = new Item($key);
$value = $this->memcache->get($this->getCacheKey($key));
if ($this->memcache->getResultCode() !== Memcached::RES_NOTFOUND) {
// Set the value, even if it is the boolean value false:
$item->setHit();
$item->set($value);
}
return $item;
}
/**
* @inheritDoc
*/
public function hasItem(string $key): bool
{
return $this->memcache->checkKey($this->getCacheKey($key));
}
/**
* @inheritDoc
*/
public function save(CacheItemInterface $item): bool
{
$expiration = $this->getExpiration($item);
if ($expiration < 1) {
// The item would expire immediately.
return false;
}
$real_key = $this->getCacheKey($item->getKey());
return $this->memcache->set($real_key, $item->get(), $expiration);
}