]> git.mxchange.org Git - friendica.git/commitdiff
Adding possibility to use a different cache-backend for locking and caching
authorPhilipp Holzer <admin+github@philipp.info>
Sun, 4 Aug 2019 13:42:39 +0000 (15:42 +0200)
committerPhilipp Holzer <admin+github@philipp.info>
Sun, 4 Aug 2019 13:42:39 +0000 (15:42 +0200)
- Renaming *LockDriver to *Lock since it isn't a "driver" anymore

22 files changed:
src/Console/Cache.php
src/Core/Cache/APCuCache.php
src/Core/Cache/AbstractCache.php
src/Core/Cache/ArrayCache.php
src/Core/Cache/DatabaseCache.php
src/Core/Cache/MemcacheCache.php
src/Core/Cache/MemcachedCache.php
src/Core/Cache/ProfilerCache.php
src/Core/Cache/RedisCache.php
src/Core/Lock/CacheLock.php [new file with mode: 0644]
src/Core/Lock/CacheLockDriver.php [deleted file]
src/Factory/CacheDriverFactory.php [deleted file]
src/Factory/CacheFactory.php [new file with mode: 0644]
src/Factory/LockDriverFactory.php [deleted file]
src/Factory/LockFactory.php [new file with mode: 0644]
static/dependencies.config.php
tests/functional/DependencyCheckTest.php
tests/src/Core/Lock/APCuCacheLockTest.php
tests/src/Core/Lock/ArrayCacheLockTest.php
tests/src/Core/Lock/MemcacheCacheLockTest.php
tests/src/Core/Lock/MemcachedCacheLockTest.php
tests/src/Core/Lock/RedisCacheLockTest.php

index 5f508da7a8239a08b76da999d39e6a592073e2e4..754b871dbb311f8dc66a73991fda5f0a8a6e0872 100644 (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))) {
index 350c8fa067197779263ed884f366233d0cab8e14..eb879590e79cfe58db79b134865367b8bdf05240 100644 (file)
@@ -153,4 +153,9 @@ class APCuCache extends AbstractCache implements IMemoryCache
 
                return true;
        }
+
+       public function __toString()
+       {
+               return self::TYPE_APCU;
+       }
 }
index c60615f089b5f26a005251a0a77e704bd0b7be98..c1cd9643c0311aa82ee38fa2e13a775783681dc0 100644 (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
         */
index 76f867f70048f27ec71aaffac6a88213918b8843..451fec363d1d0684b5943f52bb312dedaa90803c 100644 (file)
@@ -92,4 +92,9 @@ class ArrayCache extends AbstractCache implements IMemoryCache
                        return false;
                }
        }
+
+       public function __toString()
+       {
+               return self::TYPE_ARRAY;
+       }
 }
index 0289ada867ceb5730e7ce61424dc530abfe175ec..42f40ab1ed693d8b4a69bff5196aee37e183efb2 100644 (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;
+       }
 }
index b5b835f48812117c18ded24c6414e2547b172d55..57c1698c9a1d25f62f60ac44d0ab95b5ec9d35cf 100644 (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;
+       }
 }
index f841cae2cee94a70d52254d2fb0bd3f70f418369..e4c4ef352ad2c72d299e8a3d92c8b282de886b1d 100644 (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;
+       }
 }
index 72d72b2716a2275fd87e1432d58bd75e1cb4d001..67f606958a35ddbdfc0375196425857dbbcc26d3 100644 (file)
@@ -152,4 +152,9 @@ class ProfilerCache implements ICache, IMemoryCache
                        return false;
                }
        }
+
+       public function __toString()
+       {
+               return (string)$this->cache . ' (with profiler)';
+       }
 }
index 6f3a647c5579240ec2a9a05a100e726b9266e6c6..40cb56d35cdaa9939c7cc998f006b0059125ede4 100644 (file)
@@ -192,4 +192,9 @@ class RedisCache extends AbstractCache implements IMemoryCache
                $this->redis->unwatch();
                return false;
        }
+
+       public function __toString()
+       {
+               return self::TYPE_REDIS;
+       }
 }
diff --git a/src/Core/Lock/CacheLock.php b/src/Core/Lock/CacheLock.php
new file mode 100644 (file)
index 0000000..b38c5ed
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache;
+use Friendica\Core\Cache\IMemoryCache;
+
+class CacheLock extends AbstractLock
+{
+       /**
+        * @var \Friendica\Core\Cache\ICache;
+        */
+       private $cache;
+
+       /**
+        * CacheLock constructor.
+        *
+        * @param IMemoryCache $cache The CacheDriver for this type of lock
+        */
+       public function __construct(IMemoryCache $cache)
+       {
+               $this->cache = $cache;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
+       {
+               $got_lock = false;
+               $start    = time();
+
+               $cachekey = self::getLockKey($key);
+
+               do {
+                       $lock = $this->cache->get($cachekey);
+                       // When we do want to lock something that was already locked by us.
+                       if ((int)$lock == getmypid()) {
+                               $got_lock = true;
+                       }
+
+                       // When we do want to lock something new
+                       if (is_null($lock)) {
+                               // At first initialize it with "0"
+                               $this->cache->add($cachekey, 0);
+                               // Now the value has to be "0" because otherwise the key was used by another process meanwhile
+                               if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
+                                       $got_lock = true;
+                                       $this->markAcquire($key);
+                               }
+                       }
+
+                       if (!$got_lock && ($timeout > 0)) {
+                               usleep(rand(10000, 200000));
+                       }
+               } while (!$got_lock && ((time() - $start) < $timeout));
+
+               return $got_lock;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function releaseLock($key, $override = false)
+       {
+               $cachekey = self::getLockKey($key);
+
+               if ($override) {
+                       $return = $this->cache->delete($cachekey);
+               } else {
+                       $return = $this->cache->compareDelete($cachekey, getmypid());
+               }
+               $this->markRelease($key);
+
+               return $return;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function isLocked($key)
+       {
+               $cachekey = self::getLockKey($key);
+               $lock     = $this->cache->get($cachekey);
+               return isset($lock) && ($lock !== false);
+       }
+
+       /**
+        * @param string $key The original key
+        *
+        * @return string        The cache key used for the cache
+        */
+       private static function getLockKey($key)
+       {
+               return "lock:" . $key;
+       }
+}
diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php
deleted file mode 100644 (file)
index 69db1c2..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-namespace Friendica\Core\Lock;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Cache\IMemoryCache;
-
-class CacheLockDriver extends AbstractLock
-{
-       /**
-        * @var \Friendica\Core\Cache\ICache;
-        */
-       private $cache;
-
-       /**
-        * CacheLockDriver constructor.
-        *
-        * @param IMemoryCache $cache The CacheDriver for this type of lock
-        */
-       public function __construct(IMemoryCache $cache)
-       {
-               $this->cache = $cache;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
-       {
-               $got_lock = false;
-               $start    = time();
-
-               $cachekey = self::getLockKey($key);
-
-               do {
-                       $lock = $this->cache->get($cachekey);
-                       // When we do want to lock something that was already locked by us.
-                       if ((int)$lock == getmypid()) {
-                               $got_lock = true;
-                       }
-
-                       // When we do want to lock something new
-                       if (is_null($lock)) {
-                               // At first initialize it with "0"
-                               $this->cache->add($cachekey, 0);
-                               // Now the value has to be "0" because otherwise the key was used by another process meanwhile
-                               if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
-                                       $got_lock = true;
-                                       $this->markAcquire($key);
-                               }
-                       }
-
-                       if (!$got_lock && ($timeout > 0)) {
-                               usleep(rand(10000, 200000));
-                       }
-               } while (!$got_lock && ((time() - $start) < $timeout));
-
-               return $got_lock;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function releaseLock($key, $override = false)
-       {
-               $cachekey = self::getLockKey($key);
-
-               if ($override) {
-                       $return = $this->cache->delete($cachekey);
-               } else {
-                       $return = $this->cache->compareDelete($cachekey, getmypid());
-               }
-               $this->markRelease($key);
-
-               return $return;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function isLocked($key)
-       {
-               $cachekey = self::getLockKey($key);
-               $lock     = $this->cache->get($cachekey);
-               return isset($lock) && ($lock !== false);
-       }
-
-       /**
-        * @param string $key The original key
-        *
-        * @return string        The cache key used for the cache
-        */
-       private static function getLockKey($key)
-       {
-               return "lock:" . $key;
-       }
-}
diff --git a/src/Factory/CacheDriverFactory.php b/src/Factory/CacheDriverFactory.php
deleted file mode 100644 (file)
index f604a05..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-namespace Friendica\Factory;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Cache\ICache;
-use Friendica\Core\Config\Configuration;
-use Friendica\Database\Database;
-use Friendica\Util\BaseURL;
-use Friendica\Util\Profiler;
-use Psr\Log\LoggerInterface;
-
-/**
- * Class CacheDriverFactory
- *
- * @package Friendica\Core\Cache
- *
- * A basic class to generate a CacheDriver
- */
-class CacheDriverFactory
-{
-       /**
-        * @var string The default driver for caching
-        */
-       const DEFAULT_DRIVER = 'database';
-
-       /**
-        * @var Configuration The configuration 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, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
-       {
-               $this->hostname = $baseURL->getHostname();
-               $this->config = $config;
-               $this->dba = $dba;
-               $this->profiler = $profiler;
-               $this->logger = $logger;
-       }
-
-       /**
-        * This method creates a CacheDriver for the given cache driver name
-        *
-        * @return ICache  The instance of the CacheDriver
-        * @throws \Exception    The exception if something went wrong during the CacheDriver creation
-        */
-       public function create()
-       {
-               $driver = $this->config->get('system', 'cache_driver', self::DEFAULT_DRIVER);
-
-               switch ($driver) {
-                       case 'memcache':
-                               $cache = new Cache\MemcacheCache($this->hostname, $this->config);
-                               break;
-                       case 'memcached':
-                               $cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger);
-                               break;
-                       case 'redis':
-                               $cache = new Cache\RedisCache($this->hostname, $this->config);
-                               break;
-                       case 'apcu':
-                               $cache = new Cache\APCuCache($this->hostname);
-                               break;
-                       default:
-                               $cache = new Cache\DatabaseCache($this->hostname, $this->dba);
-               }
-
-               $profiling = $this->config->get('system', 'profiling', false);
-
-               // In case profiling is enabled, wrap the ProfilerCache around the current cache
-               if (isset($profiling) && $profiling !== false) {
-                        return new Cache\ProfilerCache($cache, $this->profiler);
-               } else {
-                       return $cache;
-               }
-       }
-}
diff --git a/src/Factory/CacheFactory.php b/src/Factory/CacheFactory.php
new file mode 100644 (file)
index 0000000..afb799e
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Cache;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Database\Database;
+use Friendica\Util\BaseURL;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class CacheFactory
+ *
+ * @package Friendica\Core\Cache
+ *
+ * A basic class to generate a CacheDriver
+ */
+class CacheFactory
+{
+       /**
+        * @var string The default cache if nothing set
+        */
+       const DEFAULT_TYPE = Cache\AbstractCache::TYPE_DATABASE;
+
+       /**
+        * @var Configuration The configuration 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, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
+       {
+               $this->hostname = $baseURL->getHostname();
+               $this->config   = $config;
+               $this->dba      = $dba;
+               $this->profiler = $profiler;
+               $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(string $type = null)
+       {
+               if (empty($type)) {
+                       $type = $this->config->get('system', 'cache_driver', self::DEFAULT_TYPE);
+               }
+
+               switch ($type) {
+                       case Cache\AbstractCache::TYPE_MEMCACHE:
+                               $cache = new Cache\MemcacheCache($this->hostname, $this->config);
+                               break;
+                       case Cache\AbstractCache::TYPE_MEMCACHED:
+                               $cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger);
+                               break;
+                       case Cache\AbstractCache::TYPE_REDIS:
+                               $cache = new Cache\RedisCache($this->hostname, $this->config);
+                               break;
+                       case Cache\AbstractCache::TYPE_APCU:
+                               $cache = new Cache\APCuCache($this->hostname);
+                               break;
+                       default:
+                               $cache = new Cache\DatabaseCache($this->hostname, $this->dba);
+               }
+
+               $profiling = $this->config->get('system', 'profiling', false);
+
+               // In case profiling is enabled, wrap the ProfilerCache around the current cache
+               if (isset($profiling) && $profiling !== false) {
+                       return new Cache\ProfilerCache($cache, $this->profiler);
+               } else {
+                       return $cache;
+               }
+       }
+}
diff --git a/src/Factory/LockDriverFactory.php b/src/Factory/LockDriverFactory.php
deleted file mode 100644 (file)
index b0c87cf..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-
-namespace Friendica\Factory;
-
-use Friendica\Core\Cache\ICache;
-use Friendica\Core\Cache\IMemoryCache;
-use Friendica\Core\Config\Configuration;
-use Friendica\Core\Lock;
-use Friendica\Database\Database;
-use Friendica\Util\Profiler;
-use Psr\Log\LoggerInterface;
-
-/**
- * Class LockDriverFactory
- *
- * @package Friendica\Core\Cache
- *
- * A basic class to generate a LockDriver
- */
-class LockDriverFactory
-{
-       /**
-        * @var string The default driver for caching
-        */
-       const DEFAULT_DRIVER = 'default';
-
-       /**
-        * @var Configuration The configuration 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 ICache The memory cache driver in case we use it
-        */
-       private $cacheDriver;
-
-       /**
-        * @var Profiler The optional profiler if the cached should be profiled
-        */
-       private $profiler;
-
-       /**
-        * @var LoggerInterface The Friendica Logger
-        */
-       private $logger;
-
-       public function __construct(ICache $cacheDriver, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
-       {
-               $this->cacheDriver = $cacheDriver;
-               $this->config      = $config;
-               $this->dba         = $dba;
-               $this->logger      = $logger;
-       }
-
-       public function create()
-       {
-               $lock_driver = $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);
-                                       }
-                                       break;
-
-                               case 'database':
-                                       return new Lock\DatabaseLock($this->dba);
-                                       break;
-
-                               case 'semaphore':
-                                       return new Lock\SemaphoreLock();
-                                       break;
-
-                               default:
-                                       return self::useAutoDriver();
-                       }
-               } catch (\Exception $exception) {
-                       $this->logger->alert('Driver \'' . $lock_driver . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
-                       return self::useAutoDriver();
-               }
-       }
-
-       /**
-        * @brief This method tries to find the best - local - locking method for Friendica
-        *
-        * The following sequence will be tried:
-        * 1. Semaphore Locking
-        * 2. Cache Locking
-        * 3. Database Locking
-        *
-        * @return Lock\ILock
-        */
-       private function useAutoDriver()
-       {
-
-               // 1. Try to use Semaphores for - local - locking
-               if (function_exists('sem_get')) {
-                       try {
-                               return new Lock\SemaphoreLock();
-                       } catch (\Exception $exception) {
-                               $this->logger->debug('Using Semaphore driver for locking failed.', ['exception' => $exception]);
-                       }
-               }
-
-               // 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') {
-                       try {
-                               if ($this->cacheDriver instanceof IMemoryCache) {
-                                       return new Lock\CacheLockDriver($this->cacheDriver);
-                               }
-                       } catch (\Exception $exception) {
-                               $this->logger->debug('Using Cache driver for locking failed.', ['exception' => $exception]);
-                       }
-               }
-
-               // 3. Use Database Locking as a Fallback
-               return new Lock\DatabaseLock($this->dba);
-       }
-}
diff --git a/src/Factory/LockFactory.php b/src/Factory/LockFactory.php
new file mode 100644 (file)
index 0000000..c1e76f6
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Cache\AbstractCache;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock;
+use Friendica\Database\Database;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class LockFactory
+ *
+ * @package Friendica\Core\Cache
+ *
+ * A basic class to generate a LockDriver
+ */
+class LockFactory
+{
+       /**
+        * @var string The default driver for caching
+        */
+       const DEFAULT_DRIVER = 'default';
+
+       /**
+        * @var Configuration The configuration 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 CacheFactory The memory cache driver in case we use it
+        */
+       private $cacheFactory;
+
+       /**
+        * @var Profiler The optional profiler if the cached should be profiled
+        */
+       private $profiler;
+
+       /**
+        * @var LoggerInterface The Friendica Logger
+        */
+       private $logger;
+
+       public function __construct(CacheFactory $cacheFactory, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
+       {
+               $this->cacheFactory = $cacheFactory;
+               $this->config       = $config;
+               $this->dba          = $dba;
+               $this->logger       = $logger;
+       }
+
+       public function create()
+       {
+               $lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);
+
+               try {
+                       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;
+
+                               case 'database':
+                                       return new Lock\DatabaseLock($this->dba);
+                                       break;
+
+                               case 'semaphore':
+                                       return new Lock\SemaphoreLock();
+                                       break;
+
+                               default:
+                                       return self::useAutoDriver();
+                       }
+               } catch (\Exception $exception) {
+                       $this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
+                       return self::useAutoDriver();
+               }
+       }
+
+       /**
+        * @brief This method tries to find the best - local - locking method for Friendica
+        *
+        * The following sequence will be tried:
+        * 1. Semaphore Locking
+        * 2. Cache Locking
+        * 3. Database Locking
+        *
+        * @return Lock\ILock
+        */
+       private function useAutoDriver()
+       {
+               // 1. Try to use Semaphores for - local - locking
+               if (function_exists('sem_get')) {
+                       try {
+                               return new Lock\SemaphoreLock();
+                       } catch (\Exception $exception) {
+                               $this->logger->debug('Using Semaphore driver for locking failed.', ['exception' => $exception]);
+                       }
+               }
+
+               // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
+               $cache_type = $this->config->get('system', 'cache_driver', 'database');
+               if ($cache_type != AbstractCache::TYPE_DATABASE) {
+                       try {
+                               $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]);
+                       }
+               }
+
+               // 3. Use Database Locking as a Fallback
+               return new Lock\DatabaseLock($this->dba);
+       }
+}
index 1399fe728512288e8abb1d3dca5e7f8c4b5a8a62..1d0908f32507252b0fdb6881d8442fab9f2401e3 100644 (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],
                ],
index 9fe469d5e88f29140a5a8342eb0724f30270fec2..bc8d256a78f821c3f4c98ba182c0102ba50d33f4 100644 (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);
        }
 }
index c9610132548bdbc5705c59bee12d08960cb83316..3fbb3605a195eac0c2e2ea86a72cc03678ab9a56 100644 (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'));
        }
 }
index aa4ca47538914bf6ba65c2cba9cf7d12566b808b..cc35d7f5e66e152b15f7520058705fd112f190dc 100644 (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()
index b4272b0d2511a4d36810b704a0e88a564752e4e4..f550ac51a6949554dbe6f17f083d66025005256b 100644 (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));
        }
 }
index ab5d678d68bed0f73aaa03e8aeb80947b045d8e1..8b59f91bb79a14b09f2670cc4fb3b4d71ddd47c7 100644 (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));
        }
 }
index dab31f5e3c523f834251de2c64f5ba4dd5c84054..0ebc02160e6a6915055ef34655f9460d5f5cf8ff 100644 (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));
        }
 }