Add support for Memcached/Improve database cache

- Create Cache Driver interface
- Update cache table fields
- Add CacheSessionHandler
This commit is contained in:
Hypolite Petovan 2018-02-28 23:48:09 -05:00
parent 7bd4a52156
commit 3628b62aeb
9 changed files with 326 additions and 192 deletions

View file

@ -0,0 +1,56 @@
<?php
namespace Friendica\Core\Cache;
use dba;
use Friendica\Core\Cache;
use Friendica\Database\DBM;
use Friendica\Util\DateTimeFormat;
/**
* Database Cache Driver
*
* @author Hypolite Petovan <mrpetovan@gmail.com>
*/
class DatabaseCacheDriver implements ICacheDriver
{
public function get($key)
{
$cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= NOW()`', $key]);
if (DBM::is_result($cache)) {
$cached = $cache['v'];
$value = @unserialize($cached);
// Only return a value if the serialized value is valid.
// We also check if the db entry is a serialized
// boolean 'false' value (which we want to return).
if ($cached === serialize(false) || $value !== false) {
return $value;
}
}
return null;
}
public function set($key, $value, $duration = Cache::MONTH)
{
$fields = [
'v' => serialize($value),
'expires' => DateTimeFormat::utc('now + ' . Cache::duration($duration) . ' seconds'),
'updated' => DateTimeFormat::utcNow()
];
return dba::update('cache', $fields, ['k' => $key], true);
}
public function delete($key)
{
return dba::delete('cache', ['k' => $key]);
}
public function clear()
{
return dba::delete('cache', ['`expires` < NOW()']);
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Friendica\Core\Cache;
use Friendica\Core\Cache;
/**
* Cache Driver Interface
*
* @author Hypolite Petovan <mrpetovan@gmail.com>
*/
interface ICacheDriver
{
/**
* Fetches cached data according to the key
*
* @param string $key The key to the cached data
*
* @return mixed Cached $value or "null" if not found
*/
public function get($key);
/**
* Stores data in the cache identified by the key. The input $value can have multiple formats.
*
* @param string $key The cache key
* @param mixed $value The value to store
* @param integer $duration The cache lifespan, must be one of the Cache constants
*
* @return bool
*/
public function set($key, $value, $duration = Cache::MONTH);
/**
* Delete a key from the cache
*
* @param string $key
*
* @return bool
*/
public function delete($key);
/**
* Remove outdated data from the cache
*
* @return bool
*/
public function clear();
}

View file

@ -0,0 +1,77 @@
<?php
namespace Friendica\Core\Cache;
use Friendica\BaseObject;
use Friendica\Core\Cache;
/**
* Memcache Cache Driver
*
* @author Hypolite Petovan <mrpetovan@gmail.com>
*/
class MemcacheCacheDriver extends BaseObject implements ICacheDriver
{
/**
* @var Memcache
*/
private $memcache;
public function __construct($memcache_host, $memcache_port)
{
if (!class_exists('Memcache', false)) {
throw new \Exception('Memcache class isn\'t available');
}
$this->memcache = new \Memcache();
if (!$this->memcache->connect($memcache_host, $memcache_port)) {
throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
}
}
public function get($key)
{
$return = null;
// We fetch with the hostname as key to avoid problems with other applications
$cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key);
// @see http://php.net/manual/en/memcache.get.php#84275
if (is_bool($cached) || is_double($cached) || is_long($cached)) {
return $return;
}
$value = @unserialize($cached);
// Only return a value if the serialized value is valid.
// We also check if the db entry is a serialized
// boolean 'false' value (which we want to return).
if ($cached === serialize(false) || $value !== false) {
$return = $value;
}
return $return;
}
public function set($key, $value, $duration = Cache::MONTH)
{
// We store with the hostname as key to avoid problems with other applications
return $this->memcache->set(
self::getApp()->get_hostname() . ":" . $key,
serialize($value),
MEMCACHE_COMPRESSED,
Cache::duration($duration)
);
}
public function delete($key)
{
return $this->memcache->delete($key);
}
public function clear()
{
return true;
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace Friendica\Core\Cache;
use Friendica\BaseObject;
use Friendica\Core\Cache;
/**
* Memcached Cache Driver
*
* @author Hypolite Petovan <mrpetovan@gmail.com>
*/
class MemcachedCacheDriver extends BaseObject implements ICacheDriver
{
/**
* @var Memcached
*/
private $memcached;
public function __construct($memcached_host, $memcached_port)
{
if (!class_exists('Memcached', false)) {
throw new \Exception('Memcached class isn\'t available');
}
$this->memcached = new \Memcached();
if (!$this->memcached->addServer($memcached_host, $memcached_port)) {
throw new \Exception('Expected Memcached server at ' . $memcached_host . ':' . $memcached_port . ' isn\'t available');
}
}
public function get($key)
{
$return = null;
// We fetch with the hostname as key to avoid problems with other applications
$value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key);
if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) {
$return = $value;
}
return $return;
}
public function set($key, $value, $duration = Cache::MONTH)
{
// We store with the hostname as key to avoid problems with other applications
return $this->memcached->set(
self::getApp()->get_hostname() . ":" . $key,
$value,
Cache::duration($duration)
);
}
public function delete($key)
{
return $this->memcached->delete($key);
}
public function clear()
{
return true;
}
}