Browse Source

Adding possibility to use a different cache-backend for locking and caching

- Renaming *LockDriver to *Lock since it isn't a "driver" anymore
tags/2019.09
Philipp Holzer 1 year ago
parent
commit
34e4968c06
No known key found for this signature in database GPG Key ID: D8365C3D36B77D90
19 changed files with 149 additions and 64 deletions
  1. +7
    -10
      src/Console/Cache.php
  2. +5
    -0
      src/Core/Cache/APCuCache.php
  3. +14
    -0
      src/Core/Cache/AbstractCache.php
  4. +5
    -0
      src/Core/Cache/ArrayCache.php
  5. +5
    -0
      src/Core/Cache/DatabaseCache.php
  6. +5
    -0
      src/Core/Cache/MemcacheCache.php
  7. +5
    -0
      src/Core/Cache/MemcachedCache.php
  8. +5
    -0
      src/Core/Cache/ProfilerCache.php
  9. +5
    -0
      src/Core/Cache/RedisCache.php
  10. +2
    -2
      src/Core/Lock/CacheLock.php
  11. +19
    -15
      src/Factory/CacheFactory.php
  12. +27
    -23
      src/Factory/LockFactory.php
  13. +6
    -3
      static/dependencies.config.php
  14. +29
    -1
      tests/functional/DependencyCheckTest.php
  15. +2
    -2
      tests/src/Core/Lock/APCuCacheLockTest.php
  16. +2
    -2
      tests/src/Core/Lock/ArrayCacheLockTest.php
  17. +2
    -2
      tests/src/Core/Lock/MemcacheCacheLockTest.php
  18. +2
    -2
      tests/src/Core/Lock/MemcachedCacheLockTest.php
  19. +2
    -2
      tests/src/Core/Lock/RedisCacheLockTest.php

+ 7
- 10
src/Console/Cache.php View File

@@ -5,8 +5,6 @@ namespace Friendica\Console;
use Asika\SimpleConsole\CommandArgsException;
use Friendica\App;
use Friendica\Core\Cache\ICache;
use Friendica\Core\Config\Configuration;
use Friendica\Factory\CacheDriverFactory;
use RuntimeException;

/**
@@ -71,13 +69,12 @@ HELP;
return $help;
}

public function __construct(App\Mode $appMode, Configuration $config, ICache $cache, array $argv = null)
public function __construct(App\Mode $appMode, ICache $cache, array $argv = null)
{
parent::__construct($argv);

$this->appMode = $appMode;
$this->cache = $cache;
$this->cacheDriverName = $config->get('system', 'cache_driver', CacheDriverFactory::DEFAULT_DRIVER);
$this->cache = $cache;
}

protected function doExecute()
@@ -94,7 +91,7 @@ HELP;
}

if ($this->getOption('v')) {
$this->out('Cache Driver Name: ' . $this->cacheDriverName);
$this->out('Cache Driver Name: ' . (string)$this->cache);
$this->out('Cache Driver Class: ' . get_class($this->cache));
}

@@ -127,7 +124,7 @@ HELP;
private function executeList()
{
$prefix = $this->getArgument(1);
$keys = $this->cache->getAllKeys($prefix);
$keys = $this->cache->getAllKeys($prefix);

if (empty($prefix)) {
$this->out('Listing all cache keys:');
@@ -147,7 +144,7 @@ HELP;
private function executeGet()
{
if (count($this->args) >= 2) {
$key = $this->getArgument(1);
$key = $this->getArgument(1);
$value = $this->cache->get($key);

$this->out("{$key} => " . var_export($value, true));
@@ -159,8 +156,8 @@ HELP;
private function executeSet()
{
if (count($this->args) >= 3) {
$key = $this->getArgument(1);
$value = $this->getArgument(2);
$key = $this->getArgument(1);
$value = $this->getArgument(2);
$duration = intval($this->getArgument(3, ICache::FIVE_MINUTES));

if (is_array($this->cache->get($key))) {


+ 5
- 0
src/Core/Cache/APCuCache.php View File

@@ -153,4 +153,9 @@ class APCuCache extends AbstractCache implements IMemoryCache

return true;
}

public function __toString()
{
return self::TYPE_APCU;
}
}

+ 14
- 0
src/Core/Cache/AbstractCache.php View File

@@ -11,6 +11,20 @@ namespace Friendica\Core\Cache;
*/
abstract class AbstractCache implements ICache
{
const TYPE_APCU = 'apcu';
const TYPE_ARRAY = 'array';
const TYPE_DATABASE = 'database';
const TYPE_MEMCACHE = 'memcache';
const TYPE_MEMCACHED = 'memcached';
const TYPE_REDIS = 'redis';

/**
* Force each Cache implementation to define the ToString method
*
* @return string
*/
abstract function __toString();

/**
* @var string The hostname
*/


+ 5
- 0
src/Core/Cache/ArrayCache.php View File

@@ -92,4 +92,9 @@ class ArrayCache extends AbstractCache implements IMemoryCache
return false;
}
}

public function __toString()
{
return self::TYPE_ARRAY;
}
}

+ 5
- 0
src/Core/Cache/DatabaseCache.php View File

@@ -110,4 +110,9 @@ class DatabaseCache extends AbstractCache implements ICache
return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
}
}

public function __toString()
{
return self::TYPE_DATABASE;
}
}

+ 5
- 0
src/Core/Cache/MemcacheCache.php View File

@@ -148,4 +148,9 @@ class MemcacheCache extends AbstractCache implements IMemoryCache
$cachekey = $this->getCacheKey($key);
return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
}

public function __toString()
{
return self::TYPE_MEMCACHE;
}
}

+ 5
- 0
src/Core/Cache/MemcachedCache.php View File

@@ -151,4 +151,9 @@ class MemcachedCache extends AbstractCache implements IMemoryCache
$cachekey = $this->getCacheKey($key);
return $this->memcached->add($cachekey, $value, $ttl);
}

public function __toString()
{
return self::TYPE_MEMCACHED;
}
}

+ 5
- 0
src/Core/Cache/ProfilerCache.php View File

@@ -152,4 +152,9 @@ class ProfilerCache implements ICache, IMemoryCache
return false;
}
}

public function __toString()
{
return (string)$this->cache . ' (with profiler)';
}
}

+ 5
- 0
src/Core/Cache/RedisCache.php View File

@@ -192,4 +192,9 @@ class RedisCache extends AbstractCache implements IMemoryCache
$this->redis->unwatch();
return false;
}

public function __toString()
{
return self::TYPE_REDIS;
}
}

src/Core/Lock/CacheLockDriver.php → src/Core/Lock/CacheLock.php View File

@@ -5,7 +5,7 @@ namespace Friendica\Core\Lock;
use Friendica\Core\Cache;
use Friendica\Core\Cache\IMemoryCache;

class CacheLockDriver extends AbstractLock
class CacheLock extends AbstractLock
{
/**
* @var \Friendica\Core\Cache\ICache;
@@ -13,7 +13,7 @@ class CacheLockDriver extends AbstractLock
private $cache;

/**
* CacheLockDriver constructor.
* CacheLock constructor.
*
* @param IMemoryCache $cache The CacheDriver for this type of lock
*/

src/Factory/CacheDriverFactory.php → src/Factory/CacheFactory.php View File

@@ -11,18 +11,18 @@ use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;

/**
* Class CacheDriverFactory
* Class CacheFactory
*
* @package Friendica\Core\Cache
*
* A basic class to generate a CacheDriver
*/
class CacheDriverFactory
class CacheFactory
{
/**
* @var string The default driver for caching
* @var string The default cache if nothing set
*/
const DEFAULT_DRIVER = 'database';
const DEFAULT_TYPE = Cache\AbstractCache::TYPE_DATABASE;

/**
* @var Configuration The configuration to read parameters out of the config
@@ -52,33 +52,37 @@ class CacheDriverFactory
public function __construct(BaseURL $baseURL, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
{
$this->hostname = $baseURL->getHostname();
$this->config = $config;
$this->dba = $dba;
$this->config = $config;
$this->dba = $dba;
$this->profiler = $profiler;
$this->logger = $logger;
$this->logger = $logger;
}

/**
* This method creates a CacheDriver for the given cache driver name
*
* @param string $type The cache type to create (default is per config)
*
* @return ICache The instance of the CacheDriver
* @throws \Exception The exception if something went wrong during the CacheDriver creation
*/
public function create()
public function create(string $type = null)
{
$driver = $this->config->get('system', 'cache_driver', self::DEFAULT_DRIVER);
if (empty($type)) {
$type = $this->config->get('system', 'cache_driver', self::DEFAULT_TYPE);
}

switch ($driver) {
case 'memcache':
switch ($type) {
case Cache\AbstractCache::TYPE_MEMCACHE:
$cache = new Cache\MemcacheCache($this->hostname, $this->config);
break;
case 'memcached':
case Cache\AbstractCache::TYPE_MEMCACHED:
$cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger);
break;
case 'redis':
case Cache\AbstractCache::TYPE_REDIS:
$cache = new Cache\RedisCache($this->hostname, $this->config);
break;
case 'apcu':
case Cache\AbstractCache::TYPE_APCU:
$cache = new Cache\APCuCache($this->hostname);
break;
default:
@@ -89,7 +93,7 @@ class CacheDriverFactory

// In case profiling is enabled, wrap the ProfilerCache around the current cache
if (isset($profiling) && $profiling !== false) {
return new Cache\ProfilerCache($cache, $this->profiler);
return new Cache\ProfilerCache($cache, $this->profiler);
} else {
return $cache;
}

src/Factory/LockDriverFactory.php → src/Factory/LockFactory.php View File

@@ -2,7 +2,7 @@

namespace Friendica\Factory;

use Friendica\Core\Cache\ICache;
use Friendica\Core\Cache\AbstractCache;
use Friendica\Core\Cache\IMemoryCache;
use Friendica\Core\Config\Configuration;
use Friendica\Core\Lock;
@@ -11,13 +11,13 @@ use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;

/**
* Class LockDriverFactory
* Class LockFactory
*
* @package Friendica\Core\Cache
*
* A basic class to generate a LockDriver
*/
class LockDriverFactory
class LockFactory
{
/**
* @var string The default driver for caching
@@ -35,9 +35,9 @@ class LockDriverFactory
private $dba;

/**
* @var ICache The memory cache driver in case we use it
* @var CacheFactory The memory cache driver in case we use it
*/
private $cacheDriver;
private $cacheFactory;

/**
* @var Profiler The optional profiler if the cached should be profiled
@@ -49,25 +49,29 @@ class LockDriverFactory
*/
private $logger;

public function __construct(ICache $cacheDriver, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
public function __construct(CacheFactory $cacheFactory, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
{
$this->cacheDriver = $cacheDriver;
$this->config = $config;
$this->dba = $dba;
$this->logger = $logger;
$this->cacheFactory = $cacheFactory;
$this->config = $config;
$this->dba = $dba;
$this->logger = $logger;
}

public function create()
{
$lock_driver = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);
$lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);

try {
switch ($lock_driver) {
case 'memcache':
case 'memcached':
case 'redis':
if ($this->cacheDriver instanceof IMemoryCache) {
return new Lock\CacheLockDriver($this->cacheDriver);
switch ($lock_type) {
case AbstractCache::TYPE_MEMCACHE:
case AbstractCache::TYPE_MEMCACHED:
case AbstractCache::TYPE_REDIS:
case AbstractCache::TYPE_APCU:
$cache = $this->cacheFactory->create($lock_type);
if ($cache instanceof IMemoryCache) {
return new Lock\CacheLock($cache);
} else {
throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type));
}
break;

@@ -83,7 +87,7 @@ class LockDriverFactory
return self::useAutoDriver();
}
} catch (\Exception $exception) {
$this->logger->alert('Driver \'' . $lock_driver . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
$this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
return self::useAutoDriver();
}
}
@@ -100,7 +104,6 @@ class LockDriverFactory
*/
private function useAutoDriver()
{

// 1. Try to use Semaphores for - local - locking
if (function_exists('sem_get')) {
try {
@@ -111,11 +114,12 @@ class LockDriverFactory
}

// 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
$cache_driver = $this->config->get('system', 'cache_driver', 'database');
if ($cache_driver != 'database') {
$cache_type = $this->config->get('system', 'cache_driver', 'database');
if ($cache_type != AbstractCache::TYPE_DATABASE) {
try {
if ($this->cacheDriver instanceof IMemoryCache) {
return new Lock\CacheLockDriver($this->cacheDriver);
$cache = $this->cacheFactory->create($cache_type);
if ($cache instanceof IMemoryCache) {
return new Lock\CacheLock($cache);
}
} catch (\Exception $exception) {
$this->logger->debug('Using Cache driver for locking failed.', ['exception' => $exception]);

+ 6
- 3
static/dependencies.config.php View File

@@ -119,16 +119,19 @@ return [
]
],
Cache\ICache::class => [
'instanceOf' => Factory\CacheDriverFactory::class,
'instanceOf' => Factory\CacheFactory::class,
'call' => [
['create', [], Dice::CHAIN_CALL],
],
],
Cache\IMemoryCache::class => [
'instanceOf' => Cache\ICache::class,
'instanceOf' => Factory\CacheFactory::class,
'call' => [
['create', [], Dice::CHAIN_CALL],
],
],
ILock::class => [
'instanceOf' => Factory\LockDriverFactory::class,
'instanceOf' => Factory\LockFactory::class,
'call' => [
['create', [], Dice::CHAIN_CALL],
],


+ 29
- 1
tests/functional/DependencyCheckTest.php View File

@@ -4,8 +4,11 @@ namespace functional;

use Dice\Dice;
use Friendica\App;
use Friendica\Core\Cache\ICache;
use Friendica\Core\Cache\IMemoryCache;
use Friendica\Core\Config\Cache\ConfigCache;
use Friendica\Core\Config\Configuration;
use Friendica\Core\Lock\ILock;
use Friendica\Database\Database;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\BasePath;
@@ -133,6 +136,31 @@ class dependencyCheck extends TestCase
/** @var LoggerInterface $logger */
$logger = $this->dice->create('$devLogger', ['dev']);

self::assertInstanceOf(LoggerInterface::class, $logger);
$this->assertInstanceOf(LoggerInterface::class, $logger);
}

public function testCache()
{
/** @var ICache $cache */
$cache = $this->dice->create(ICache::class);

$this->assertInstanceOf(ICache::class, $cache);
}

public function testMemoryCache()
{
/** @var IMemoryCache $cache */
$cache = $this->dice->create(IMemoryCache::class);

// We need to check "just" ICache, because the default Cache is DB-Cache, which isn't a memorycache
$this->assertInstanceOf(ICache::class, $cache);
}

public function testLock()
{
/** @var ILock $cache */
$lock = $this->dice->create(ILock::class);

$this->assertInstanceOf(ILock::class, $lock);
}
}

+ 2
- 2
tests/src/Core/Lock/APCuCacheLockTest.php View File

@@ -3,7 +3,7 @@
namespace Friendica\Test\src\Core\Lock;

use Friendica\Core\Cache\APCuCache;
use Friendica\Core\Lock\CacheLockDriver;
use Friendica\Core\Lock\CacheLock;

class APCuCacheLockTest extends LockTest
{
@@ -18,6 +18,6 @@ class APCuCacheLockTest extends LockTest

protected function getInstance()
{
return new CacheLockDriver(new APCuCache('localhost'));
return new CacheLock(new APCuCache('localhost'));
}
}

+ 2
- 2
tests/src/Core/Lock/ArrayCacheLockTest.php View File

@@ -3,13 +3,13 @@
namespace Friendica\Test\src\Core\Lock;

use Friendica\Core\Cache\ArrayCache;
use Friendica\Core\Lock\CacheLockDriver;
use Friendica\Core\Lock\CacheLock;

class ArrayCacheLockTest extends LockTest
{
protected function getInstance()
{
return new CacheLockDriver(new ArrayCache('localhost'));
return new CacheLock(new ArrayCache('localhost'));
}

public function testLockTTL()


+ 2
- 2
tests/src/Core/Lock/MemcacheCacheLockTest.php View File

@@ -5,7 +5,7 @@ namespace Friendica\Test\src\Core\Lock;

use Friendica\Core\Cache\MemcacheCache;
use Friendica\Core\Config\Configuration;
use Friendica\Core\Lock\CacheLockDriver;
use Friendica\Core\Lock\CacheLock;

/**
* @requires extension Memcache
@@ -25,6 +25,6 @@ class MemcacheCacheLockTest extends LockTest
->with('system', 'memcache_port')
->andReturn(11211);

return new CacheLockDriver(new MemcacheCache('localhost', $configMock));
return new CacheLock(new MemcacheCache('localhost', $configMock));
}
}

+ 2
- 2
tests/src/Core/Lock/MemcachedCacheLockTest.php View File

@@ -5,7 +5,7 @@ namespace Friendica\Test\src\Core\Lock;

use Friendica\Core\Cache\MemcachedCache;
use Friendica\Core\Config\Configuration;
use Friendica\Core\Lock\CacheLockDriver;
use Friendica\Core\Lock\CacheLock;
use Psr\Log\NullLogger;

/**
@@ -24,6 +24,6 @@ class MemcachedCacheLockTest extends LockTest

$logger = new NullLogger();

return new CacheLockDriver(new MemcachedCache('localhost', $configMock, $logger));
return new CacheLock(new MemcachedCache('localhost', $configMock, $logger));
}
}

+ 2
- 2
tests/src/Core/Lock/RedisCacheLockTest.php View File

@@ -5,7 +5,7 @@ namespace Friendica\Test\src\Core\Lock;

use Friendica\Core\Cache\RedisCache;
use Friendica\Core\Config\Configuration;
use Friendica\Core\Lock\CacheLockDriver;
use Friendica\Core\Lock\CacheLock;

/**
* @requires extension redis
@@ -34,6 +34,6 @@ class RedisCacheLockTest extends LockTest
->with('system', 'redis_password')
->andReturn(null);

return new CacheLockDriver(new RedisCache('localhost', $configMock));
return new CacheLock(new RedisCache('localhost', $configMock));
}
}

Loading…
Cancel
Save