1
0
Fork 0

Move Cache to strategies

This commit is contained in:
Philipp Holzer 2023-07-22 23:57:38 +02:00
parent f1da323b07
commit f2c02a79b9
Signed by: nupplaPhil
GPG key ID: 24A7501396EB5432
12 changed files with 98 additions and 119 deletions

View file

@ -21,16 +21,14 @@
namespace Friendica\Core\Cache\Factory; namespace Friendica\Core\Cache\Factory;
use Friendica\App\BaseURL;
use Friendica\Core\Cache\Enum; use Friendica\Core\Cache\Enum;
use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\CachePersistenceException;
use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
use Friendica\Core\Cache\Type; use Friendica\Core\Cache\Type;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Database\Database; use Friendica\Core\Hooks\Capabilities\ICanCreateInstances;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/** /**
* Class CacheFactory * Class CacheFactory
@ -45,39 +43,18 @@ class Cache
* @var string The default cache if nothing set * @var string The default cache if nothing set
*/ */
const DEFAULT_TYPE = Enum\Type::DATABASE; const DEFAULT_TYPE = Enum\Type::DATABASE;
/** @var ICanCreateInstances */
protected $instanceCreator;
/** @var IManageConfigValues */
protected $config;
/** @var Profiler */
protected $profiler;
/** public function __construct(ICanCreateInstances $instanceCreator, IManageConfigValues $config, Profiler $profiler)
* @var IManageConfigValues The IConfiguration to read parameters out of the config
*/
private $config;
/**
* @var Database The database connection in case that the cache is used the dba connection
*/
private $dba;
/**
* @var string The hostname, used as Prefix for Caching
*/
private $hostname;
/**
* @var Profiler The optional profiler if the cached should be profiled
*/
private $profiler;
/**
* @var LoggerInterface The Friendica Logger
*/
private $logger;
public function __construct(BaseURL $baseURL, IManageConfigValues $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
{ {
$this->hostname = $baseURL->getHost(); $this->config = $config;
$this->config = $config; $this->instanceCreator = $instanceCreator;
$this->dba = $dba; $this->profiler = $profiler;
$this->profiler = $profiler;
$this->logger = $logger;
} }
/** /**
@ -92,7 +69,7 @@ class Cache
*/ */
public function createDistributed(string $type = null): ICanCache public function createDistributed(string $type = null): ICanCache
{ {
if ($type === Enum\Type::APCU) { if ($type === Type\APCuCache::$NAME) {
throw new InvalidCacheDriverException('apcu doesn\'t support distributed caching.'); throw new InvalidCacheDriverException('apcu doesn\'t support distributed caching.');
} }
@ -117,31 +94,17 @@ class Cache
/** /**
* Creates a new Cache instance * Creates a new Cache instance
* *
* @param string $type The type of cache * @param string $strategy The strategy, which cache instance should be used
* *
* @return ICanCache * @return ICanCache
* *
* @throws InvalidCacheDriverException In case the underlying cache driver isn't valid or not configured properly * @throws InvalidCacheDriverException In case the underlying cache driver isn't valid or not configured properly
* @throws CachePersistenceException In case the underlying cache has errors during persistence * @throws CachePersistenceException In case the underlying cache has errors during persistence
*/ */
protected function create(string $type): ICanCache protected function create(string $strategy): ICanCache
{ {
switch ($type) { /** @var ICanCache $cache */
case Enum\Type::MEMCACHE: $cache = $this->instanceCreator->create(ICanCache::class, $strategy);
$cache = new Type\MemcacheCache($this->hostname, $this->config);
break;
case Enum\Type::MEMCACHED:
$cache = new Type\MemcachedCache($this->hostname, $this->config, $this->logger);
break;
case Enum\Type::REDIS:
$cache = new Type\RedisCache($this->hostname, $this->config);
break;
case Enum\Type::APCU:
$cache = new Type\APCuCache($this->hostname);
break;
default:
$cache = new Type\DatabaseCache($this->hostname, $this->dba);
}
$profiling = $this->config->get('system', 'profiling', false); $profiling = $this->config->get('system', 'profiling', false);

View file

@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Cache\Capability\ICanCacheInMemory; use Friendica\Core\Cache\Capability\ICanCacheInMemory;
use Friendica\Core\Cache\Enum\Type;
use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
/** /**
@ -31,12 +30,12 @@ use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
*/ */
class APCuCache extends AbstractCache implements ICanCacheInMemory class APCuCache extends AbstractCache implements ICanCacheInMemory
{ {
public static $NAME = 'apcu';
use CompareSetTrait; use CompareSetTrait;
use CompareDeleteTrait; use CompareDeleteTrait;
/** /**
* @param string $hostname
*
* @throws InvalidCacheDriverException * @throws InvalidCacheDriverException
*/ */
public function __construct(string $hostname) public function __construct(string $hostname)
@ -173,12 +172,4 @@ class APCuCache extends AbstractCache implements ICanCacheInMemory
return true; return true;
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Type::APCU;
}
} }

View file

@ -28,6 +28,8 @@ use Friendica\Core\Cache\Capability\ICanCache;
*/ */
abstract class AbstractCache implements ICanCache abstract class AbstractCache implements ICanCache
{ {
public static $NAME = '';
/** /**
* @var string The hostname * @var string The hostname
*/ */
@ -105,4 +107,10 @@ abstract class AbstractCache implements ICanCache
return $result; return $result;
} }
} }
/** {@inheritDoc} */
public function getName(): string
{
return static::$NAME;
}
} }

View file

@ -29,6 +29,8 @@ use Friendica\Core\Cache\Enum;
*/ */
class ArrayCache extends AbstractCache implements ICanCacheInMemory class ArrayCache extends AbstractCache implements ICanCacheInMemory
{ {
public static $NAME = 'array';
use CompareDeleteTrait; use CompareDeleteTrait;
/** @var array Array with the cached data */ /** @var array Array with the cached data */
@ -108,12 +110,4 @@ class ArrayCache extends AbstractCache implements ICanCacheInMemory
return false; return false;
} }
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Enum\Type::ARRAY;
}
} }

View file

@ -32,6 +32,8 @@ use Friendica\Util\DateTimeFormat;
*/ */
class DatabaseCache extends AbstractCache implements ICanCache class DatabaseCache extends AbstractCache implements ICanCache
{ {
public static $NAME = 'database';
/** /**
* @var Database * @var Database
*/ */
@ -154,12 +156,4 @@ class DatabaseCache extends AbstractCache implements ICanCache
throw new CachePersistenceException('Cannot clear cache', $exception); throw new CachePersistenceException('Cannot clear cache', $exception);
} }
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Enum\Type::DATABASE;
}
} }

View file

@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Cache\Capability\ICanCacheInMemory; use Friendica\Core\Cache\Capability\ICanCacheInMemory;
use Friendica\Core\Cache\Enum\Type;
use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\CachePersistenceException;
use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
@ -34,6 +33,8 @@ use Memcache;
*/ */
class MemcacheCache extends AbstractCache implements ICanCacheInMemory class MemcacheCache extends AbstractCache implements ICanCacheInMemory
{ {
static $NAME = 'memcached';
use CompareSetTrait; use CompareSetTrait;
use CompareDeleteTrait; use CompareDeleteTrait;
use MemcacheCommandTrait; use MemcacheCommandTrait;
@ -169,12 +170,4 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory
$cacheKey = $this->getCacheKey($key); $cacheKey = $this->getCacheKey($key);
return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl); return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Type::MEMCACHE;
}
} }

View file

@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Cache\Capability\ICanCacheInMemory; use Friendica\Core\Cache\Capability\ICanCacheInMemory;
use Friendica\Core\Cache\Enum\Type;
use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\CachePersistenceException;
use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
@ -35,6 +34,8 @@ use Psr\Log\LoggerInterface;
*/ */
class MemcachedCache extends AbstractCache implements ICanCacheInMemory class MemcachedCache extends AbstractCache implements ICanCacheInMemory
{ {
static $NAME = 'memcached';
use CompareSetTrait; use CompareSetTrait;
use CompareDeleteTrait; use CompareDeleteTrait;
use MemcacheCommandTrait; use MemcacheCommandTrait;
@ -185,12 +186,4 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory
$cacheKey = $this->getCacheKey($key); $cacheKey = $this->getCacheKey($key);
return $this->memcached->add($cacheKey, $value, $ttl); return $this->memcached->add($cacheKey, $value, $ttl);
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Type::MEMCACHED;
}
} }

View file

@ -21,10 +21,8 @@
namespace Friendica\Core\Cache\Type; namespace Friendica\Core\Cache\Type;
use Exception;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Cache\Capability\ICanCacheInMemory; use Friendica\Core\Cache\Capability\ICanCacheInMemory;
use Friendica\Core\Cache\Enum\Type;
use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\CachePersistenceException;
use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
@ -35,6 +33,8 @@ use Redis;
*/ */
class RedisCache extends AbstractCache implements ICanCacheInMemory class RedisCache extends AbstractCache implements ICanCacheInMemory
{ {
public static $NAME = 'redis';
/** /**
* @var Redis * @var Redis
*/ */
@ -59,18 +59,23 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory
$redis_pw = $config->get('system', 'redis_password'); $redis_pw = $config->get('system', 'redis_password');
$redis_db = $config->get('system', 'redis_db', 0); $redis_db = $config->get('system', 'redis_db', 0);
if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { try {
throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
} elseif (!@$this->redis->connect($redis_host)) {
throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available');
}
if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) {
throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port); throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
} } else if (!@$this->redis->connect($redis_host)) {
throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available');
}
if ($redis_db !== 0 && !$this->redis->select($redis_db)) { if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) {
throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port); throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
}
if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
}
} catch (\RedisException $exception) {
throw new CachePersistenceException('Redis connection fails unexpectedly', $exception);
} }
} }
@ -211,12 +216,4 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory
$this->redis->unwatch(); $this->redis->unwatch();
return false; return false;
} }
/**
* {@inheritDoc}
*/
public function getName(): string
{
return Type::REDIS;
}
} }

View file

@ -178,6 +178,20 @@ return [
$_SERVER, $_SERVER,
], ],
], ],
'$hostname' => [
'instanceOf' => App\BaseURL::class,
'constructParams' => [
$_SERVER,
],
'call' => [
['getHost', [], Dice::CHAIN_CALL],
],
],
Cache\Type\AbstractCache::class => [
'constructParams' => [
[Dice::INSTANCE => '$hostname'],
],
],
App\Page::class => [ App\Page::class => [
'constructParams' => [ 'constructParams' => [
[Dice::INSTANCE => '$basepath'], [Dice::INSTANCE => '$basepath'],

View file

@ -19,7 +19,7 @@
* *
*/ */
use Friendica\Core\Hooks\Capabilities\BehavioralHookType as H; use Friendica\Core\Cache;
use Friendica\Core\Logger\Type; use Friendica\Core\Logger\Type;
use Psr\Log; use Psr\Log;
@ -29,4 +29,11 @@ return [
Type\SyslogLogger::class => ['syslog'], Type\SyslogLogger::class => ['syslog'],
Type\StreamLogger::class => ['stream'], Type\StreamLogger::class => ['stream'],
], ],
Cache\Capability\ICanCache::class => [
Cache\Type\APCuCache::class => ['apcu'],
Cache\Type\DatabaseCache::class => ['database', ''],
Cache\Type\MemcacheCache::class => ['memcache'],
Cache\Type\MemcachedCache::class => ['memcached'],
Cache\Type\RedisCache::class => ['redis'],
]
]; ];

24
tests/phpunit-addons.xml Normal file
View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="bootstrap.php"
verbose="true"
timeoutForSmallTests="900"
timeoutForMediumTests="900"
timeoutForLargeTests="900"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<testsuite name="friendica-addons">
<directory suffix=".php">../addon/*/tests/</directory>
</testsuite>
<!-- Filters for Code Coverage -->
<coverage>
<include>
<directory suffix=".php">../addon/</directory>
</include>
<exclude>
<directory suffix=".php">../addon/*/tests/</directory>
<directory suffix=".php">../addon/*/view/</directory>
<directory suffix=".php">../addon/*/vendor/</directory>
</exclude>
</coverage>
</phpunit>

View file

@ -21,6 +21,7 @@
namespace Friendica\Test\src\Core\Cache; namespace Friendica\Test\src\Core\Cache;
use Friendica\App\BaseURL;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Test\DatabaseTestTrait; use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\CreateDatabaseTrait; use Friendica\Test\Util\CreateDatabaseTrait;