Restructure Cache to follow new paradigm
authorPhilipp <admin@philipp.info>
Sat, 23 Oct 2021 08:49:27 +0000 (10:49 +0200)
committerPhilipp <admin@philipp.info>
Tue, 26 Oct 2021 20:11:06 +0000 (22:11 +0200)
66 files changed:
mod/ping.php
src/App/Router.php
src/Console/Cache.php
src/Content/OEmbed.php
src/Content/Widget.php
src/Core/BaseCache.php [deleted file]
src/Core/Cache/APCuCache.php [deleted file]
src/Core/Cache/ArrayCache.php [deleted file]
src/Core/Cache/DatabaseCache.php [deleted file]
src/Core/Cache/Duration.php [deleted file]
src/Core/Cache/Enum/Duration.php [new file with mode: 0644]
src/Core/Cache/Enum/Type.php [new file with mode: 0644]
src/Core/Cache/Factory/CacheFactory.php [new file with mode: 0644]
src/Core/Cache/ICache.php
src/Core/Cache/IMemoryCache.php
src/Core/Cache/MemcacheCache.php [deleted file]
src/Core/Cache/MemcachedCache.php [deleted file]
src/Core/Cache/ProfilerCache.php [deleted file]
src/Core/Cache/RedisCache.php [deleted file]
src/Core/Cache/TraitCompareDelete.php [deleted file]
src/Core/Cache/TraitCompareSet.php [deleted file]
src/Core/Cache/TraitMemcacheCommand.php [deleted file]
src/Core/Cache/Type.php [deleted file]
src/Core/Cache/Type/APCuCache.php [new file with mode: 0644]
src/Core/Cache/Type/ArrayCache.php [new file with mode: 0644]
src/Core/Cache/Type/BaseCache.php [new file with mode: 0644]
src/Core/Cache/Type/DatabaseCache.php [new file with mode: 0644]
src/Core/Cache/Type/MemcacheCache.php [new file with mode: 0644]
src/Core/Cache/Type/MemcachedCache.php [new file with mode: 0644]
src/Core/Cache/Type/ProfilerCache.php [new file with mode: 0644]
src/Core/Cache/Type/RedisCache.php [new file with mode: 0644]
src/Core/Cache/Type/TraitCompareDelete.php [new file with mode: 0644]
src/Core/Cache/Type/TraitCompareSet.php [new file with mode: 0644]
src/Core/Cache/Type/TraitMemcacheCommand.php [new file with mode: 0644]
src/Core/Lock/CacheLock.php
src/Core/Lock/DatabaseLock.php
src/Core/Lock/ILock.php
src/Core/Lock/SemaphoreLock.php
src/Core/Lock/Type.php
src/Core/Update.php
src/Factory/CacheFactory.php [deleted file]
src/Factory/LockFactory.php
src/Factory/SessionFactory.php
src/Model/APContact.php
src/Model/Photo.php
src/Model/Profile.php
src/Model/Tag.php
src/Module/Search/Index.php
src/Protocol/ActivityPub/Transmitter.php
src/Protocol/Diaspora.php
src/Protocol/Feed.php
src/Protocol/OStatus.php
src/Util/JsonLD.php
src/Worker/SearchDirectory.php
static/dependencies.config.php
tests/src/Core/Cache/APCuCacheTest.php
tests/src/Core/Cache/ArrayCacheTest.php
tests/src/Core/Cache/DatabaseCacheTest.php
tests/src/Core/Cache/MemcacheCacheTest.php
tests/src/Core/Cache/MemcachedCacheTest.php
tests/src/Core/Cache/RedisCacheTest.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 2143f73af283181f4bb09f5c7dc4bf1edec9df0a..c12594902ae6acee3270d407ea15ad6aef32f735 100644 (file)
@@ -22,7 +22,7 @@
 use Friendica\App;
 use Friendica\Content\ForumManager;
 use Friendica\Content\Text\BBCode;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Hook;
 use Friendica\Database\DBA;
 use Friendica\DI;
index ad4b33d084a3f24435f869a2eea53ab899eadd5c..50768395303555625ac21efbad6516b5af5135b7 100644 (file)
@@ -26,7 +26,7 @@ use FastRoute\DataGenerator\GroupCountBased;
 use FastRoute\Dispatcher;
 use FastRoute\RouteCollector;
 use FastRoute\RouteParser\Std;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Cache\ICache;
 use Friendica\Core\Hook;
 use Friendica\Core\L10n;
index 049ffd0ffb39825e2606efe8b07d863f70f2fe5f..a9452435eb89c6170fed98abe1c794d945e89a74 100644 (file)
@@ -23,7 +23,7 @@ namespace Friendica\Console;
 
 use Asika\SimpleConsole\CommandArgsException;
 use Friendica\App;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Cache\ICache;
 use RuntimeException;
 
index 313a2628dbf5ea7f1fd01298c6df716975ddb73b..14e910ebab70e9c853931d4cdd7294142824f66d 100644 (file)
@@ -26,7 +26,7 @@ use DOMNode;
 use DOMText;
 use DOMXPath;
 use Exception;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Hook;
 use Friendica\Core\Renderer;
 use Friendica\Database\Database;
index daa34a8b00b2d3a8c3a9681df3519e3e1b498483..4a3e9186741d57ac6a1c6b6d27ed97445dec8d98 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Content;
 
 use Friendica\Core\Addon;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Protocol;
 use Friendica\Core\Renderer;
 use Friendica\Database\DBA;
diff --git a/src/Core/BaseCache.php b/src/Core/BaseCache.php
deleted file mode 100644 (file)
index c6c6b60..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core;
-
-use Friendica\Core\Cache\ICache;
-
-/**
- * Abstract class for common used functions
- */
-abstract class BaseCache implements ICache
-{
-       /**
-        * @var string The hostname
-        */
-       private $hostName;
-
-       public function __construct(string $hostName)
-       {
-               $this->hostName = $hostName;
-       }
-
-       /**
-        * Returns the prefix (to avoid namespace conflicts)
-        *
-        * @return string
-        * @throws \Exception
-        */
-       protected function getPrefix()
-       {
-               // We fetch with the hostname as key to avoid problems with other applications
-               return $this->hostName;
-       }
-
-       /**
-        * @param string $key The original key
-        * @return string        The cache key used for the cache
-        * @throws \Exception
-        */
-       protected function getCacheKey($key)
-       {
-               return $this->getPrefix() . ":" . $key;
-       }
-
-       /**
-        * @param array $keys   A list of cached keys
-        * @return array        A list of original keys
-        */
-       protected function getOriginalKeys($keys)
-       {
-               if (empty($keys)) {
-                       return [];
-               } else {
-                       // Keys are prefixed with the node hostname, let's remove it
-                       array_walk($keys, function (&$value) {
-                               $value = preg_replace('/^' . $this->hostName . ':/', '', $value);
-                       });
-
-                       sort($keys);
-
-                       return $keys;
-               }
-       }
-
-       /**
-        * Filters the keys of an array with a given prefix
-        * Returns the filtered keys as an new array
-        *
-        * @param array $keys The keys, which should get filtered
-        * @param string|null $prefix The prefix (if null, all keys will get returned)
-        *
-        * @return array The filtered array with just the keys
-        */
-       protected function filterArrayKeysByPrefix(array $keys, string $prefix = null)
-       {
-               if (empty($prefix)) {
-                       return $keys;
-               } else {
-                       $result = [];
-
-                       foreach ($keys as $key) {
-                               if (strpos($key, $prefix) === 0) {
-                                       array_push($result, $key);
-                               }
-                       }
-
-                       return $result;
-               }
-       }
-}
diff --git a/src/Core/Cache/APCuCache.php b/src/Core/Cache/APCuCache.php
deleted file mode 100644 (file)
index 7d819b4..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Exception;
-use Friendica\Core\BaseCache;
-
-/**
- * APCu Cache.
- */
-class APCuCache extends BaseCache implements IMemoryCache
-{
-       use TraitCompareSet;
-       use TraitCompareDelete;
-
-       /**
-        * @throws Exception
-        */
-       public function __construct(string $hostname)
-       {
-               if (!self::isAvailable()) {
-                       throw new Exception('APCu is not available.');
-               }
-
-               parent::__construct($hostname);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               $ns = $this->getCacheKey($prefix);
-               $ns = preg_quote($ns, '/');
-
-               if (class_exists('\APCIterator')) {
-                       $iterator = new \APCIterator('user', '/^' . $ns. '/', APC_ITER_KEY);
-               } else {
-                       $iterator = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
-               }
-
-               $keys = [];
-               foreach ($iterator as $item) {
-                       array_push($keys, $item['key']);
-               }
-
-               return $this->getOriginalKeys($keys);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               $return = null;
-               $cachekey = $this->getCacheKey($key);
-
-               $cached = apcu_fetch($cachekey, $success);
-               if (!$success) {
-                       return null;
-               }
-
-               $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;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               $cached = serialize($value);
-
-               if ($ttl > 0) {
-                       return apcu_store(
-                               $cachekey,
-                               $cached,
-                               $ttl
-                       );
-               } else {
-                       return apcu_store(
-                               $cachekey,
-                               $cached
-                       );
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               $cachekey = $this->getCacheKey($key);
-               return apcu_delete($cachekey);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               if ($outdated) {
-                       return true;
-               } else {
-                       $prefix = $this->getPrefix();
-                       $prefix = preg_quote($prefix, '/');
-
-                       if (class_exists('\APCIterator')) {
-                               $iterator = new \APCIterator('user', '/^' . $prefix . '/', APC_ITER_KEY);
-                       } else {
-                               $iterator = new \APCUIterator('/^' . $prefix . '/', APC_ITER_KEY);
-                       }
-
-                       return apcu_delete($iterator);
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-               $cached = serialize($value);
-
-               return apcu_add($cachekey, $cached);
-       }
-
-       public static function isAvailable()
-       {
-               if (!extension_loaded('apcu')) {
-                       return false;
-               } elseif (!ini_get('apc.enabled') && !ini_get('apc.enable_cli')) {
-                       return false;
-               } elseif (
-                       version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
-                       version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
-               ) {
-                       return false;
-               }
-
-               return true;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::APCU;
-       }
-}
diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php
deleted file mode 100644 (file)
index 5970500..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\BaseCache;
-
-/**
- * Implementation of the IMemoryCache mainly for testing purpose
- */
-class ArrayCache extends BaseCache implements IMemoryCache
-{
-       use TraitCompareDelete;
-
-       /** @var array Array with the cached data */
-       protected $cachedData = array();
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               return $this->filterArrayKeysByPrefix(array_keys($this->cachedData), $prefix);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               if (isset($this->cachedData[$key])) {
-                       return $this->cachedData[$key];
-               }
-               return null;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $this->cachedData[$key] = $value;
-               return true;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               unset($this->cachedData[$key]);
-               return true;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               // Array doesn't support TTL so just don't delete something
-               if ($outdated) {
-                       return true;
-               }
-
-               $this->cachedData = [];
-               return true;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               if (isset($this->cachedData[$key])) {
-                       return false;
-               } else {
-                       return $this->set($key, $value, $ttl);
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
-       {
-               if ($this->get($key) === $oldValue) {
-                       return $this->set($key, $newValue);
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::ARRAY;
-       }
-}
diff --git a/src/Core/Cache/DatabaseCache.php b/src/Core/Cache/DatabaseCache.php
deleted file mode 100644 (file)
index 8dcfae8..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Database\Database;
-use Friendica\Util\DateTimeFormat;
-use Friendica\Core\BaseCache;
-
-/**
- * Database Cache
- */
-class DatabaseCache extends BaseCache implements ICache
-{
-       /**
-        * @var Database
-        */
-       private $dba;
-
-       public function __construct(string $hostname, Database $dba)
-       {
-               parent::__construct($hostname);
-
-               $this->dba = $dba;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               if (empty($prefix)) {
-                       $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
-               } else {
-                       $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
-               }
-
-               $stmt = $this->dba->select('cache', ['k'], $where);
-
-               $keys = [];
-               while ($key = $this->dba->fetch($stmt)) {
-                       array_push($keys, $key['k']);
-               }
-               $this->dba->close($stmt);
-
-               return $keys;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               $cache = $this->dba->selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]);
-
-               if ($this->dba->isResult($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;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               if ($ttl > 0) {
-                       $fields = [
-                               'v' => serialize($value),
-                               'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
-                               'updated' => DateTimeFormat::utcNow()
-                       ];
-               } else {
-                       $fields = [
-                               'v' => serialize($value),
-                               'expires' => -1,
-                               'updated' => DateTimeFormat::utcNow()
-                       ];
-               }
-
-               return $this->dba->update('cache', $fields, ['k' => $key], true);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               return $this->dba->delete('cache', ['k' => $key]);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               if ($outdated) {
-                       return $this->dba->delete('cache', ['`expires` < NOW()']);
-               } else {
-                       return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
-               }
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::DATABASE;
-       }
-}
diff --git a/src/Core/Cache/Duration.php b/src/Core/Cache/Duration.php
deleted file mode 100644 (file)
index fcbaadd..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-/**
- * Enumeration for cache durations
- */
-abstract class Duration
-{
-       const MONTH        = 2592000;
-       const HOUR         = 3600;
-       const HALF_HOUR    = 1800;
-       const QUARTER_HOUR = 900;
-       const MINUTE       = 60;
-       const WEEK         = 604800;
-       const INFINITE     = 0;
-       const DAY          = 86400;
-       const FIVE_MINUTES = 300;
-}
diff --git a/src/Core/Cache/Enum/Duration.php b/src/Core/Cache/Enum/Duration.php
new file mode 100644 (file)
index 0000000..c5771c7
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Enum;
+
+/**
+ * Enumeration for cache durations
+ */
+abstract class Duration
+{
+       const MONTH        = 2592000;
+       const HOUR         = 3600;
+       const HALF_HOUR    = 1800;
+       const QUARTER_HOUR = 900;
+       const MINUTE       = 60;
+       const WEEK         = 604800;
+       const INFINITE     = 0;
+       const DAY          = 86400;
+       const FIVE_MINUTES = 300;
+}
diff --git a/src/Core/Cache/Enum/Type.php b/src/Core/Cache/Enum/Type.php
new file mode 100644 (file)
index 0000000..9bdfed5
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Enum;
+
+/**
+ * Enumeration for cache types
+ */
+abstract class Type
+{
+       const APCU      = 'apcu';
+       const REDIS     = 'redis';
+       const ARRAY     = 'array';
+       const MEMCACHE  = 'memcache';
+       const DATABASE  = 'database';
+       const MEMCACHED = 'memcached';
+}
diff --git a/src/Core/Cache/Factory/CacheFactory.php b/src/Core/Cache/Factory/CacheFactory.php
new file mode 100644 (file)
index 0000000..2e99180
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Factory;
+
+use Friendica\App\BaseURL;
+use Friendica\Core\Cache;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Config\IConfig;
+use Friendica\Database\Database;
+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\Enum\Type::DATABASE;
+
+       /**
+        * @var IConfig 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, IConfig $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\Enum\Type::MEMCACHE:
+                               $cache = new Cache\Type\MemcacheCache($this->hostname, $this->config);
+                               break;
+                       case Cache\Enum\Type::MEMCACHED:
+                               $cache = new Cache\Type\MemcachedCache($this->hostname, $this->config, $this->logger);
+                               break;
+                       case Cache\Enum\Type::REDIS:
+                               $cache = new Cache\Type\RedisCache($this->hostname, $this->config);
+                               break;
+                       case Cache\Enum\Type::APCU:
+                               $cache = new Cache\Type\APCuCache($this->hostname);
+                               break;
+                       default:
+                               $cache = new Cache\Type\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\Type\ProfilerCache($cache, $this->profiler);
+               } else {
+                       return $cache;
+               }
+       }
+}
index 0589f4506bbb8d1ae4587b6faa6276b75403debe..3918b0089367a99553e0dd0a23733a918690aa3e 100644 (file)
@@ -21,6 +21,8 @@
 
 namespace Friendica\Core\Cache;
 
+use Friendica\Core\Cache\Enum\Duration;
+
 /**
  * Cache Interface
  */
index 248908d80105cc6fbada87210c683a6b1b0351c6..a46db0b011ef65fc15810dd7b6274559692bf91b 100644 (file)
@@ -21,6 +21,8 @@
 
 namespace Friendica\Core\Cache;
 
+use Friendica\Core\Cache\Enum\Duration;
+
 /**
  * This interface defines methods for Memory-Caches only
  */
diff --git a/src/Core/Cache/MemcacheCache.php b/src/Core/Cache/MemcacheCache.php
deleted file mode 100644 (file)
index ac826ea..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Exception;
-use Friendica\Core\BaseCache;
-use Friendica\Core\Config\IConfig;
-use Memcache;
-
-/**
- * Memcache Cache
- */
-class MemcacheCache extends BaseCache implements IMemoryCache
-{
-       use TraitCompareSet;
-       use TraitCompareDelete;
-       use TraitMemcacheCommand;
-
-       /**
-        * @var Memcache
-        */
-       private $memcache;
-
-       /**
-        * @throws Exception
-        */
-       public function __construct(string $hostname, IConfig $config)
-       {
-               if (!class_exists('Memcache', false)) {
-                       throw new Exception('Memcache class isn\'t available');
-               }
-
-               parent::__construct($hostname);
-
-               $this->memcache = new Memcache();
-
-               $this->server = $config->get('system', 'memcache_host');;
-               $this->port = $config->get('system', 'memcache_port');
-
-               if (!@$this->memcache->connect($this->server, $this->port)) {
-                       throw new Exception('Expected Memcache server at ' . $this->server . ':' . $this->port . ' isn\'t available');
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               $keys = $this->getOriginalKeys($this->getMemcacheKeys());
-
-               return $this->filterArrayKeysByPrefix($keys, $prefix);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               $return   = null;
-               $cachekey = $this->getCacheKey($key);
-
-               // We fetch with the hostname as key to avoid problems with other applications
-               $cached = $this->memcache->get($cachekey);
-
-               // @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;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               // We store with the hostname as key to avoid problems with other applications
-               if ($ttl > 0) {
-                       return $this->memcache->set(
-                               $cachekey,
-                               serialize($value),
-                               MEMCACHE_COMPRESSED,
-                               time() + $ttl
-                       );
-               } else {
-                       return $this->memcache->set(
-                               $cachekey,
-                               serialize($value),
-                               MEMCACHE_COMPRESSED
-                       );
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               $cachekey = $this->getCacheKey($key);
-               return $this->memcache->delete($cachekey);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               if ($outdated) {
-                       return true;
-               } else {
-                       return $this->memcache->flush();
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-               return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::MEMCACHE;
-       }
-}
diff --git a/src/Core/Cache/MemcachedCache.php b/src/Core/Cache/MemcachedCache.php
deleted file mode 100644 (file)
index 5ce64e9..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Exception;
-use Friendica\Core\BaseCache;
-use Friendica\Core\Config\IConfig;
-use Memcached;
-use Psr\Log\LoggerInterface;
-
-/**
- * Memcached Cache
- */
-class MemcachedCache extends BaseCache implements IMemoryCache
-{
-       use TraitCompareSet;
-       use TraitCompareDelete;
-       use TraitMemcacheCommand;
-
-       /**
-        * @var \Memcached
-        */
-       private $memcached;
-
-       /**
-        * @var LoggerInterface
-        */
-       private $logger;
-
-       /**
-        * Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
-        * array {
-        *   0 => "hostname, port(, weight)",
-        *   1 => ...
-        * }
-        *
-        * @param array $memcached_hosts
-        *
-        * @throws \Exception
-        */
-       public function __construct(string $hostname, IConfig $config, LoggerInterface $logger)
-       {
-               if (!class_exists('Memcached', false)) {
-                       throw new Exception('Memcached class isn\'t available');
-               }
-
-               parent::__construct($hostname);
-
-               $this->logger = $logger;
-
-               $this->memcached = new Memcached();
-
-               $memcached_hosts = $config->get('system', 'memcached_hosts');
-
-               array_walk($memcached_hosts, function (&$value) {
-                       if (is_string($value)) {
-                               $value = array_map('trim', explode(',', $value));
-                       }
-               });
-
-               $this->server = $memcached_hosts[0][0] ?? 'localhost';
-               $this->port = $memcached_hosts[0][1] ?? 11211;
-
-               $this->memcached->addServers($memcached_hosts);
-
-               if (count($this->memcached->getServerList()) == 0) {
-                       throw new Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               $keys = $this->getOriginalKeys($this->getMemcacheKeys());
-
-               return $this->filterArrayKeysByPrefix($keys, $prefix);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               $return   = null;
-               $cachekey = $this->getCacheKey($key);
-
-               // We fetch with the hostname as key to avoid problems with other applications
-               $value = $this->memcached->get($cachekey);
-
-               if ($this->memcached->getResultCode() === Memcached::RES_SUCCESS) {
-                       $return = $value;
-               } else {
-                       $this->logger->debug('Memcached \'get\' failed', ['result' => $this->memcached->getResultMessage()]);
-               }
-
-               return $return;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               // We store with the hostname as key to avoid problems with other applications
-               if ($ttl > 0) {
-                       return $this->memcached->set(
-                               $cachekey,
-                               $value,
-                               $ttl
-                       );
-               } else {
-                       return $this->memcached->set(
-                               $cachekey,
-                               $value
-                       );
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               $cachekey = $this->getCacheKey($key);
-               return $this->memcached->delete($cachekey);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               if ($outdated) {
-                       return true;
-               } else {
-                       return $this->memcached->flush();
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-               return $this->memcached->add($cachekey, $value, $ttl);
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::MEMCACHED;
-       }
-}
diff --git a/src/Core/Cache/ProfilerCache.php b/src/Core/Cache/ProfilerCache.php
deleted file mode 100644 (file)
index a8c9f15..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\System;
-use Friendica\Util\Profiler;
-
-/**
- * This class wraps cache driver so they can get profiled - in case the profiler is enabled
- *
- * It is using the decorator pattern (@see
- */
-class ProfilerCache implements ICache, IMemoryCache
-{
-       /**
-        * @var ICache The original cache driver
-        */
-       private $cache;
-
-       /**
-        * @var Profiler The profiler of Friendica
-        */
-       private $profiler;
-
-       public function __construct(ICache $cache, Profiler $profiler)
-       {
-               $this->cache    = $cache;
-               $this->profiler = $profiler;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getAllKeys($prefix = null)
-       {
-               $this->profiler->startRecording('cache');
-
-               $return = $this->cache->getAllKeys($prefix);
-
-               $this->profiler->stopRecording();
-
-               return $return;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function get($key)
-       {
-               $this->profiler->startRecording('cache');
-
-               $return = $this->cache->get($key);
-
-               $this->profiler->stopRecording();
-
-               return $return;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $this->profiler->startRecording('cache');
-
-               $return = $this->cache->set($key, $value, $ttl);
-
-               $this->profiler->stopRecording();
-
-               return $return;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function delete($key)
-       {
-               $this->profiler->startRecording('cache');
-
-               $return = $this->cache->delete($key);
-
-               $this->profiler->stopRecording();
-
-               return $return;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function clear($outdated = true)
-       {
-               $this->profiler->startRecording('cache');
-
-               $return = $this->cache->clear($outdated);
-
-               $this->profiler->stopRecording();
-
-               return $return;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               if ($this->cache instanceof IMemoryCache) {
-                       $this->profiler->startRecording('cache');
-
-                       $return = $this->cache->add($key, $value, $ttl);
-
-                       $this->profiler->stopRecording();
-
-                       return $return;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
-       {
-               if ($this->cache instanceof IMemoryCache) {
-                       $this->profiler->startRecording('cache');
-
-                       $return = $this->cache->compareSet($key, $oldValue, $newValue, $ttl);
-
-                       $this->profiler->stopRecording();
-
-                       return $return;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function compareDelete($key, $value)
-       {
-               if ($this->cache instanceof IMemoryCache) {
-                       $this->profiler->startRecording('cache');
-
-                       $return = $this->cache->compareDelete($key, $value);
-
-                       $this->profiler->stopRecording();
-
-                       return $return;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function GetName()
-       {
-               return $this->cache->getName() . ' (with profiler)';
-       }
-}
diff --git a/src/Core/Cache/RedisCache.php b/src/Core/Cache/RedisCache.php
deleted file mode 100644 (file)
index ce081d7..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Exception;
-use Friendica\Core\BaseCache;
-use Friendica\Core\Config\IConfig;
-use Redis;
-
-/**
- * Redis Cache. This driver is based on Memcache driver
- */
-class RedisCache extends BaseCache implements IMemoryCache
-{
-       /**
-        * @var Redis
-        */
-       private $redis;
-
-       /**
-        * @throws Exception
-        */
-       public function __construct(string $hostname, IConfig $config)
-       {
-               if (!class_exists('Redis', false)) {
-                       throw new Exception('Redis class isn\'t available');
-               }
-
-               parent::__construct($hostname);
-
-               $this->redis = new Redis();
-
-               $redis_host = $config->get('system', 'redis_host');
-               $redis_port = $config->get('system', 'redis_port');
-               $redis_pw   = $config->get('system', 'redis_password');
-               $redis_db   = $config->get('system', 'redis_db', 0);
-
-               if (isset($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) {
-                       throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
-               } elseif (!@$this->redis->connect($redis_host)) {
-                       throw new Exception('Expected Redis server at ' . $redis_host . ' isn\'t available');
-               }
-
-               if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
-                       throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
-               }
-
-               if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
-                       throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function getAllKeys($prefix = null)
-       {
-               if (empty($prefix)) {
-                       $search = '*';
-               } else {
-                       $search = $prefix . '*';
-               }
-
-               $list = $this->redis->keys($this->getCacheKey($search));
-
-               return $this->getOriginalKeys($list);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function get($key)
-       {
-               $return = null;
-               $cachekey = $this->getCacheKey($key);
-
-               $cached = $this->redis->get($cachekey);
-               if ($cached === false && !$this->redis->exists($cachekey)) {
-                       return null;
-               }
-
-               $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;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               $cached = serialize($value);
-
-               if ($ttl > 0) {
-                       return $this->redis->setex(
-                               $cachekey,
-                               $ttl,
-                               $cached
-                       );
-               } else {
-                       return $this->redis->set(
-                               $cachekey,
-                               $cached
-                       );
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function delete($key)
-       {
-               $cachekey = $this->getCacheKey($key);
-               $this->redis->del($cachekey);
-               // Redis doesn't have an error state for del()
-               return true;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function clear($outdated = true)
-       {
-               if ($outdated) {
-                       return true;
-               } else {
-                       return $this->redis->flushAll();
-               }
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-               $cached = serialize($value);
-
-               return $this->redis->setnx($cachekey, $cached);
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               $newCached = serialize($newValue);
-
-               $this->redis->watch($cachekey);
-               // If the old value isn't what we expected, somebody else changed the key meanwhile
-               if ($this->get($key) === $oldValue) {
-                       if ($ttl > 0) {
-                               $result = $this->redis->multi()
-                                       ->setex($cachekey, $ttl, $newCached)
-                                       ->exec();
-                       } else {
-                               $result = $this->redis->multi()
-                                       ->set($cachekey, $newCached)
-                                       ->exec();
-                       }
-                       return $result !== false;
-               }
-               $this->redis->unwatch();
-               return false;
-       }
-
-       /**
-        * (@inheritdoc)
-        */
-       public function compareDelete($key, $value)
-       {
-               $cachekey = $this->getCacheKey($key);
-
-               $this->redis->watch($cachekey);
-               // If the old value isn't what we expected, somebody else changed the key meanwhile
-               if ($this->get($key) === $value) {
-                       $result = $this->redis->multi()
-                               ->del($cachekey)
-                               ->exec();
-                       return $result !== false;
-               }
-               $this->redis->unwatch();
-               return false;
-       }
-
-       /**
-        * {@inheritDoc}
-        */
-       public function getName()
-       {
-               return Type::REDIS;
-       }
-}
diff --git a/src/Core/Cache/TraitCompareDelete.php b/src/Core/Cache/TraitCompareDelete.php
deleted file mode 100644 (file)
index 31c3e7c..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-/**
- * Trait TraitCompareSetDelete
- *
- * This Trait is to compensate non native "exclusive" sets/deletes in caches
- */
-trait TraitCompareDelete
-{
-       abstract public function get($key);
-
-       abstract public function set($key, $value, $ttl = Duration::FIVE_MINUTES);
-
-       abstract public function delete($key);
-
-       abstract public function add($key, $value, $ttl = Duration::FIVE_MINUTES);
-
-       /**
-        * NonNative - Compares if the old value is set and removes it
-        *
-        * @param string $key          The cache key
-        * @param mixed  $value        The old value we know and want to delete
-        * @return bool
-        */
-       public function compareDelete($key, $value) {
-               if ($this->add($key . "_lock", true)) {
-                       if ($this->get($key) === $value) {
-                               $this->delete($key);
-                               $this->delete($key . "_lock");
-                               return true;
-                       } else {
-                               $this->delete($key . "_lock");
-                               return false;
-                       }
-               } else {
-                       return false;
-               }
-       }
-}
diff --git a/src/Core/Cache/TraitCompareSet.php b/src/Core/Cache/TraitCompareSet.php
deleted file mode 100644 (file)
index fa20bd9..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-/**
- * Trait TraitCompareSetDelete
- *
- * This Trait is to compensate non native "exclusive" sets/deletes in caches
- */
-trait TraitCompareSet
-{
-       abstract public function get($key);
-
-       abstract public function set($key, $value, $ttl = Duration::FIVE_MINUTES);
-
-       abstract public function delete($key);
-
-       abstract public function add($key, $value, $ttl = Duration::FIVE_MINUTES);
-
-       /**
-        * NonNative - Compares if the old value is set and sets the new value
-        *
-        * @param string $key         The cache key
-        * @param mixed  $oldValue    The old value we know from the cache
-        * @param mixed  $newValue    The new value we want to set
-        * @param int    $ttl      The cache lifespan, must be one of the Cache constants
-        *
-        * @return bool
-        */
-       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES) {
-               if ($this->add($key . "_lock", true)) {
-                       if ($this->get($key) === $oldValue) {
-                               $this->set($key, $newValue, $ttl);
-                               $this->delete($key . "_lock");
-                               return true;
-                       } else {
-                               $this->delete($key . "_lock");
-                               return false;
-                       }
-               } else {
-                       return false;
-               }
-       }
-}
diff --git a/src/Core/Cache/TraitMemcacheCommand.php b/src/Core/Cache/TraitMemcacheCommand.php
deleted file mode 100644 (file)
index abc41ce..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Network\HTTPException\InternalServerErrorException;
-
-/**
- * Trait for Memcache to add a custom version of the
- * method getAllKeys() since this isn't working anymore
- *
- * Adds the possibility to directly communicate with the memcache too
- */
-trait TraitMemcacheCommand
-{
-       /**
-        * @var string server address
-        */
-       protected $server;
-
-       /**
-        * @var int server port
-        */
-       protected $port;
-
-       /**
-        * Retrieves the stored keys of the memcache instance
-        * Uses custom commands, which aren't bound to the used instance of the class
-        *
-        * @todo Due the fact that we use a custom command, there are race conditions possible:
-        *       - $this->memcache(d) adds a key
-        *       - $this->getMemcacheKeys is called directly "after"
-        *       - But $this->memcache(d) isn't finished adding the key, so getMemcacheKeys doesn't find it
-        *
-        * @return array All keys of the memcache instance
-        *
-        * @throws InternalServerErrorException
-        */
-       protected function getMemcacheKeys()
-       {
-               $string = $this->sendMemcacheCommand("stats items");
-               $lines  = explode("\r\n", $string);
-               $slabs  = [];
-               $keys   = [];
-
-               foreach ($lines as $line) {
-
-                       if (preg_match("/STAT items:([\d]+):number ([\d]+)/", $line, $matches) &&
-                           isset($matches[1]) &&
-                           !in_array($matches[1], $keys)) {
-
-                               $slabs[] = $matches[1];
-                               $string  = $this->sendMemcacheCommand("stats cachedump " . $matches[1] . " " . $matches[2]);
-                               preg_match_all("/ITEM (.*?) /", $string, $matches);
-                               $keys = array_merge($keys, $matches[1]);
-                       }
-               }
-
-               return $keys;
-       }
-
-       /**
-        * Taken directly from memcache PECL source
-        * Sends a command to the memcache instance and returns the result
-        * as a string
-        *
-        * http://pecl.php.net/package/memcache
-        *
-        * @param string $command The command to send to the Memcache server
-        *
-        * @return string The returned buffer result
-        *
-        * @throws InternalServerErrorException In case the memcache server isn't available (anymore)
-        */
-       protected function sendMemcacheCommand(string $command)
-       {
-               $s = @fsockopen($this->server, $this->port);
-               if (!$s) {
-                       throw new InternalServerErrorException("Cant connect to:" . $this->server . ':' . $this->port);
-               }
-
-               fwrite($s, $command . "\r\n");
-               $buf = '';
-
-               while (!feof($s)) {
-
-                       $buf .= fgets($s, 256);
-
-                       if (strpos($buf, "END\r\n") !== false) { // stat says end
-                               break;
-                       }
-
-                       if (strpos($buf, "DELETED\r\n") !== false || strpos($buf, "NOT_FOUND\r\n") !== false) { // delete says these
-                               break;
-                       }
-
-                       if (strpos($buf, "OK\r\n") !== false) { // flush_all says ok
-                               break;
-                       }
-               }
-
-               fclose($s);
-               return ($buf);
-       }
-}
diff --git a/src/Core/Cache/Type.php b/src/Core/Cache/Type.php
deleted file mode 100644 (file)
index 5153aca..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Cache;
-
-/**
- * Enumeration for cache types
- */
-abstract class Type
-{
-       const APCU      = 'apcu';
-       const REDIS     = 'redis';
-       const ARRAY     = 'array';
-       const MEMCACHE  = 'memcache';
-       const DATABASE  = 'database';
-       const MEMCACHED = 'memcached';
-}
diff --git a/src/Core/Cache/Type/APCuCache.php b/src/Core/Cache/Type/APCuCache.php
new file mode 100644 (file)
index 0000000..b473f68
--- /dev/null
@@ -0,0 +1,185 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Exception;
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Cache\Type\TraitCompareDelete;
+use Friendica\Core\Cache\Type\TraitCompareSet;
+use Friendica\Core\Cache\Enum\Type;
+
+/**
+ * APCu Cache.
+ */
+class APCuCache extends BaseCache implements IMemoryCache
+{
+       use TraitCompareSet;
+       use TraitCompareDelete;
+
+       /**
+        * @throws Exception
+        */
+       public function __construct(string $hostname)
+       {
+               if (!self::isAvailable()) {
+                       throw new Exception('APCu is not available.');
+               }
+
+               parent::__construct($hostname);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               $ns = $this->getCacheKey($prefix);
+               $ns = preg_quote($ns, '/');
+
+               if (class_exists('\APCIterator')) {
+                       $iterator = new \APCIterator('user', '/^' . $ns. '/', APC_ITER_KEY);
+               } else {
+                       $iterator = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
+               }
+
+               $keys = [];
+               foreach ($iterator as $item) {
+                       array_push($keys, $item['key']);
+               }
+
+               return $this->getOriginalKeys($keys);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               $return = null;
+               $cachekey = $this->getCacheKey($key);
+
+               $cached = apcu_fetch($cachekey, $success);
+               if (!$success) {
+                       return null;
+               }
+
+               $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;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               $cached = serialize($value);
+
+               if ($ttl > 0) {
+                       return apcu_store(
+                               $cachekey,
+                               $cached,
+                               $ttl
+                       );
+               } else {
+                       return apcu_store(
+                               $cachekey,
+                               $cached
+                       );
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return apcu_delete($cachekey);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               if ($outdated) {
+                       return true;
+               } else {
+                       $prefix = $this->getPrefix();
+                       $prefix = preg_quote($prefix, '/');
+
+                       if (class_exists('\APCIterator')) {
+                               $iterator = new \APCIterator('user', '/^' . $prefix . '/', APC_ITER_KEY);
+                       } else {
+                               $iterator = new \APCUIterator('/^' . $prefix . '/', APC_ITER_KEY);
+                       }
+
+                       return apcu_delete($iterator);
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               $cached = serialize($value);
+
+               return apcu_add($cachekey, $cached);
+       }
+
+       public static function isAvailable()
+       {
+               if (!extension_loaded('apcu')) {
+                       return false;
+               } elseif (!ini_get('apc.enabled') && !ini_get('apc.enable_cli')) {
+                       return false;
+               } elseif (
+                       version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
+                       version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
+               ) {
+                       return false;
+               }
+
+               return true;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::APCU;
+       }
+}
diff --git a/src/Core/Cache/Type/ArrayCache.php b/src/Core/Cache/Type/ArrayCache.php
new file mode 100644 (file)
index 0000000..dd0985a
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Cache\Type\TraitCompareDelete;
+use Friendica\Core\Cache\Enum\Type;
+
+/**
+ * Implementation of the IMemoryCache mainly for testing purpose
+ */
+class ArrayCache extends BaseCache implements IMemoryCache
+{
+       use TraitCompareDelete;
+
+       /** @var array Array with the cached data */
+       protected $cachedData = array();
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               return $this->filterArrayKeysByPrefix(array_keys($this->cachedData), $prefix);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               if (isset($this->cachedData[$key])) {
+                       return $this->cachedData[$key];
+               }
+               return null;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $this->cachedData[$key] = $value;
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               unset($this->cachedData[$key]);
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               // Array doesn't support TTL so just don't delete something
+               if ($outdated) {
+                       return true;
+               }
+
+               $this->cachedData = [];
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               if (isset($this->cachedData[$key])) {
+                       return false;
+               } else {
+                       return $this->set($key, $value, $ttl);
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
+       {
+               if ($this->get($key) === $oldValue) {
+                       return $this->set($key, $newValue);
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::ARRAY;
+       }
+}
diff --git a/src/Core/Cache/Type/BaseCache.php b/src/Core/Cache/Type/BaseCache.php
new file mode 100644 (file)
index 0000000..a52f1e9
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\ICache;
+
+/**
+ * Abstract class for common used functions
+ */
+abstract class BaseCache implements ICache
+{
+       /**
+        * @var string The hostname
+        */
+       private $hostName;
+
+       public function __construct(string $hostName)
+       {
+               $this->hostName = $hostName;
+       }
+
+       /**
+        * Returns the prefix (to avoid namespace conflicts)
+        *
+        * @return string
+        * @throws \Exception
+        */
+       protected function getPrefix()
+       {
+               // We fetch with the hostname as key to avoid problems with other applications
+               return $this->hostName;
+       }
+
+       /**
+        * @param string $key The original key
+        * @return string        The cache key used for the cache
+        * @throws \Exception
+        */
+       protected function getCacheKey($key)
+       {
+               return $this->getPrefix() . ":" . $key;
+       }
+
+       /**
+        * @param array $keys   A list of cached keys
+        * @return array        A list of original keys
+        */
+       protected function getOriginalKeys($keys)
+       {
+               if (empty($keys)) {
+                       return [];
+               } else {
+                       // Keys are prefixed with the node hostname, let's remove it
+                       array_walk($keys, function (&$value) {
+                               $value = preg_replace('/^' . $this->hostName . ':/', '', $value);
+                       });
+
+                       sort($keys);
+
+                       return $keys;
+               }
+       }
+
+       /**
+        * Filters the keys of an array with a given prefix
+        * Returns the filtered keys as an new array
+        *
+        * @param array $keys The keys, which should get filtered
+        * @param string|null $prefix The prefix (if null, all keys will get returned)
+        *
+        * @return array The filtered array with just the keys
+        */
+       protected function filterArrayKeysByPrefix(array $keys, string $prefix = null)
+       {
+               if (empty($prefix)) {
+                       return $keys;
+               } else {
+                       $result = [];
+
+                       foreach ($keys as $key) {
+                               if (strpos($key, $prefix) === 0) {
+                                       array_push($result, $key);
+                               }
+                       }
+
+                       return $result;
+               }
+       }
+}
diff --git a/src/Core/Cache/Type/DatabaseCache.php b/src/Core/Cache/Type/DatabaseCache.php
new file mode 100644 (file)
index 0000000..a3c83c8
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Cache\Enum\Type;
+use Friendica\Database\Database;
+use Friendica\Util\DateTimeFormat;
+
+/**
+ * Database Cache
+ */
+class DatabaseCache extends BaseCache implements ICache
+{
+       /**
+        * @var Database
+        */
+       private $dba;
+
+       public function __construct(string $hostname, Database $dba)
+       {
+               parent::__construct($hostname);
+
+               $this->dba = $dba;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               if (empty($prefix)) {
+                       $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
+               } else {
+                       $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
+               }
+
+               $stmt = $this->dba->select('cache', ['k'], $where);
+
+               $keys = [];
+               while ($key = $this->dba->fetch($stmt)) {
+                       array_push($keys, $key['k']);
+               }
+               $this->dba->close($stmt);
+
+               return $keys;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               $cache = $this->dba->selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]);
+
+               if ($this->dba->isResult($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;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               if ($ttl > 0) {
+                       $fields = [
+                               'v' => serialize($value),
+                               'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
+                               'updated' => DateTimeFormat::utcNow()
+                       ];
+               } else {
+                       $fields = [
+                               'v' => serialize($value),
+                               'expires' => -1,
+                               'updated' => DateTimeFormat::utcNow()
+                       ];
+               }
+
+               return $this->dba->update('cache', $fields, ['k' => $key], true);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               return $this->dba->delete('cache', ['k' => $key]);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               if ($outdated) {
+                       return $this->dba->delete('cache', ['`expires` < NOW()']);
+               } else {
+                       return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::DATABASE;
+       }
+}
diff --git a/src/Core/Cache/Type/MemcacheCache.php b/src/Core/Cache/Type/MemcacheCache.php
new file mode 100644 (file)
index 0000000..f991517
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Exception;
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Cache\Type\TraitCompareDelete;
+use Friendica\Core\Cache\Type\TraitCompareSet;
+use Friendica\Core\Cache\Type\TraitMemcacheCommand;
+use Friendica\Core\Cache\Enum\Type;
+use Friendica\Core\Config\IConfig;
+use Memcache;
+
+/**
+ * Memcache Cache
+ */
+class MemcacheCache extends BaseCache implements IMemoryCache
+{
+       use TraitCompareSet;
+       use TraitCompareDelete;
+       use TraitMemcacheCommand;
+
+       /**
+        * @var Memcache
+        */
+       private $memcache;
+
+       /**
+        * @throws Exception
+        */
+       public function __construct(string $hostname, IConfig $config)
+       {
+               if (!class_exists('Memcache', false)) {
+                       throw new Exception('Memcache class isn\'t available');
+               }
+
+               parent::__construct($hostname);
+
+               $this->memcache = new Memcache();
+
+               $this->server = $config->get('system', 'memcache_host');;
+               $this->port = $config->get('system', 'memcache_port');
+
+               if (!@$this->memcache->connect($this->server, $this->port)) {
+                       throw new Exception('Expected Memcache server at ' . $this->server . ':' . $this->port . ' isn\'t available');
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               $keys = $this->getOriginalKeys($this->getMemcacheKeys());
+
+               return $this->filterArrayKeysByPrefix($keys, $prefix);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               $return   = null;
+               $cachekey = $this->getCacheKey($key);
+
+               // We fetch with the hostname as key to avoid problems with other applications
+               $cached = $this->memcache->get($cachekey);
+
+               // @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;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               // We store with the hostname as key to avoid problems with other applications
+               if ($ttl > 0) {
+                       return $this->memcache->set(
+                               $cachekey,
+                               serialize($value),
+                               MEMCACHE_COMPRESSED,
+                               time() + $ttl
+                       );
+               } else {
+                       return $this->memcache->set(
+                               $cachekey,
+                               serialize($value),
+                               MEMCACHE_COMPRESSED
+                       );
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcache->delete($cachekey);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               if ($outdated) {
+                       return true;
+               } else {
+                       return $this->memcache->flush();
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::MEMCACHE;
+       }
+}
diff --git a/src/Core/Cache/Type/MemcachedCache.php b/src/Core/Cache/Type/MemcachedCache.php
new file mode 100644 (file)
index 0000000..ded53ee
--- /dev/null
@@ -0,0 +1,184 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Exception;
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Cache\Type\TraitCompareDelete;
+use Friendica\Core\Cache\Type\TraitCompareSet;
+use Friendica\Core\Cache\Type\TraitMemcacheCommand;
+use Friendica\Core\Cache\Enum\Type;
+use Friendica\Core\Config\IConfig;
+use Memcached;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Memcached Cache
+ */
+class MemcachedCache extends BaseCache implements IMemoryCache
+{
+       use TraitCompareSet;
+       use TraitCompareDelete;
+       use TraitMemcacheCommand;
+
+       /**
+        * @var \Memcached
+        */
+       private $memcached;
+
+       /**
+        * @var LoggerInterface
+        */
+       private $logger;
+
+       /**
+        * Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
+        * array {
+        *   0 => "hostname, port(, weight)",
+        *   1 => ...
+        * }
+        *
+        * @param array $memcached_hosts
+        *
+        * @throws \Exception
+        */
+       public function __construct(string $hostname, IConfig $config, LoggerInterface $logger)
+       {
+               if (!class_exists('Memcached', false)) {
+                       throw new Exception('Memcached class isn\'t available');
+               }
+
+               parent::__construct($hostname);
+
+               $this->logger = $logger;
+
+               $this->memcached = new Memcached();
+
+               $memcached_hosts = $config->get('system', 'memcached_hosts');
+
+               array_walk($memcached_hosts, function (&$value) {
+                       if (is_string($value)) {
+                               $value = array_map('trim', explode(',', $value));
+                       }
+               });
+
+               $this->server = $memcached_hosts[0][0] ?? 'localhost';
+               $this->port = $memcached_hosts[0][1] ?? 11211;
+
+               $this->memcached->addServers($memcached_hosts);
+
+               if (count($this->memcached->getServerList()) == 0) {
+                       throw new Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               $keys = $this->getOriginalKeys($this->getMemcacheKeys());
+
+               return $this->filterArrayKeysByPrefix($keys, $prefix);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               $return   = null;
+               $cachekey = $this->getCacheKey($key);
+
+               // We fetch with the hostname as key to avoid problems with other applications
+               $value = $this->memcached->get($cachekey);
+
+               if ($this->memcached->getResultCode() === Memcached::RES_SUCCESS) {
+                       $return = $value;
+               } else {
+                       $this->logger->debug('Memcached \'get\' failed', ['result' => $this->memcached->getResultMessage()]);
+               }
+
+               return $return;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               // We store with the hostname as key to avoid problems with other applications
+               if ($ttl > 0) {
+                       return $this->memcached->set(
+                               $cachekey,
+                               $value,
+                               $ttl
+                       );
+               } else {
+                       return $this->memcached->set(
+                               $cachekey,
+                               $value
+                       );
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcached->delete($cachekey);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               if ($outdated) {
+                       return true;
+               } else {
+                       return $this->memcached->flush();
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcached->add($cachekey, $value, $ttl);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::MEMCACHED;
+       }
+}
diff --git a/src/Core/Cache/Type/ProfilerCache.php b/src/Core/Cache/Type/ProfilerCache.php
new file mode 100644 (file)
index 0000000..fd00385
--- /dev/null
@@ -0,0 +1,183 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Util\Profiler;
+
+/**
+ * This class wraps cache driver so they can get profiled - in case the profiler is enabled
+ *
+ * It is using the decorator pattern (@see
+ */
+class ProfilerCache implements ICache, IMemoryCache
+{
+       /**
+        * @var ICache The original cache driver
+        */
+       private $cache;
+
+       /**
+        * @var Profiler The profiler of Friendica
+        */
+       private $profiler;
+
+       public function __construct(ICache $cache, Profiler $profiler)
+       {
+               $this->cache    = $cache;
+               $this->profiler = $profiler;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getAllKeys($prefix = null)
+       {
+               $this->profiler->startRecording('cache');
+
+               $return = $this->cache->getAllKeys($prefix);
+
+               $this->profiler->stopRecording();
+
+               return $return;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function get($key)
+       {
+               $this->profiler->startRecording('cache');
+
+               $return = $this->cache->get($key);
+
+               $this->profiler->stopRecording();
+
+               return $return;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $this->profiler->startRecording('cache');
+
+               $return = $this->cache->set($key, $value, $ttl);
+
+               $this->profiler->stopRecording();
+
+               return $return;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function delete($key)
+       {
+               $this->profiler->startRecording('cache');
+
+               $return = $this->cache->delete($key);
+
+               $this->profiler->stopRecording();
+
+               return $return;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function clear($outdated = true)
+       {
+               $this->profiler->startRecording('cache');
+
+               $return = $this->cache->clear($outdated);
+
+               $this->profiler->stopRecording();
+
+               return $return;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               if ($this->cache instanceof IMemoryCache) {
+                       $this->profiler->startRecording('cache');
+
+                       $return = $this->cache->add($key, $value, $ttl);
+
+                       $this->profiler->stopRecording();
+
+                       return $return;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
+       {
+               if ($this->cache instanceof IMemoryCache) {
+                       $this->profiler->startRecording('cache');
+
+                       $return = $this->cache->compareSet($key, $oldValue, $newValue, $ttl);
+
+                       $this->profiler->stopRecording();
+
+                       return $return;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function compareDelete($key, $value)
+       {
+               if ($this->cache instanceof IMemoryCache) {
+                       $this->profiler->startRecording('cache');
+
+                       $return = $this->cache->compareDelete($key, $value);
+
+                       $this->profiler->stopRecording();
+
+                       return $return;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function GetName()
+       {
+               return $this->cache->getName() . ' (with profiler)';
+       }
+}
diff --git a/src/Core/Cache/Type/RedisCache.php b/src/Core/Cache/Type/RedisCache.php
new file mode 100644 (file)
index 0000000..a4cc419
--- /dev/null
@@ -0,0 +1,225 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Exception;
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Cache\Enum\Type;
+use Friendica\Core\Config\IConfig;
+use Redis;
+
+/**
+ * Redis Cache. This driver is based on Memcache driver
+ */
+class RedisCache extends BaseCache implements IMemoryCache
+{
+       /**
+        * @var Redis
+        */
+       private $redis;
+
+       /**
+        * @throws Exception
+        */
+       public function __construct(string $hostname, IConfig $config)
+       {
+               if (!class_exists('Redis', false)) {
+                       throw new Exception('Redis class isn\'t available');
+               }
+
+               parent::__construct($hostname);
+
+               $this->redis = new Redis();
+
+               $redis_host = $config->get('system', 'redis_host');
+               $redis_port = $config->get('system', 'redis_port');
+               $redis_pw   = $config->get('system', 'redis_password');
+               $redis_db   = $config->get('system', 'redis_db', 0);
+
+               if (isset($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) {
+                       throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
+               } elseif (!@$this->redis->connect($redis_host)) {
+                       throw new Exception('Expected Redis server at ' . $redis_host . ' isn\'t available');
+               }
+
+               if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
+                       throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
+               }
+
+               if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
+                       throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function getAllKeys($prefix = null)
+       {
+               if (empty($prefix)) {
+                       $search = '*';
+               } else {
+                       $search = $prefix . '*';
+               }
+
+               $list = $this->redis->keys($this->getCacheKey($search));
+
+               return $this->getOriginalKeys($list);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               $return = null;
+               $cachekey = $this->getCacheKey($key);
+
+               $cached = $this->redis->get($cachekey);
+               if ($cached === false && !$this->redis->exists($cachekey)) {
+                       return null;
+               }
+
+               $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;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               $cached = serialize($value);
+
+               if ($ttl > 0) {
+                       return $this->redis->setex(
+                               $cachekey,
+                               $ttl,
+                               $cached
+                       );
+               } else {
+                       return $this->redis->set(
+                               $cachekey,
+                               $cached
+                       );
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               $cachekey = $this->getCacheKey($key);
+               $this->redis->del($cachekey);
+               // Redis doesn't have an error state for del()
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear($outdated = true)
+       {
+               if ($outdated) {
+                       return true;
+               } else {
+                       return $this->redis->flushAll();
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               $cached = serialize($value);
+
+               return $this->redis->setnx($cachekey, $cached);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               $newCached = serialize($newValue);
+
+               $this->redis->watch($cachekey);
+               // If the old value isn't what we expected, somebody else changed the key meanwhile
+               if ($this->get($key) === $oldValue) {
+                       if ($ttl > 0) {
+                               $result = $this->redis->multi()
+                                       ->setex($cachekey, $ttl, $newCached)
+                                       ->exec();
+                       } else {
+                               $result = $this->redis->multi()
+                                       ->set($cachekey, $newCached)
+                                       ->exec();
+                       }
+                       return $result !== false;
+               }
+               $this->redis->unwatch();
+               return false;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function compareDelete($key, $value)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               $this->redis->watch($cachekey);
+               // If the old value isn't what we expected, somebody else changed the key meanwhile
+               if ($this->get($key) === $value) {
+                       $result = $this->redis->multi()
+                               ->del($cachekey)
+                               ->exec();
+                       return $result !== false;
+               }
+               $this->redis->unwatch();
+               return false;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public function getName()
+       {
+               return Type::REDIS;
+       }
+}
diff --git a/src/Core/Cache/Type/TraitCompareDelete.php b/src/Core/Cache/Type/TraitCompareDelete.php
new file mode 100644 (file)
index 0000000..4873638
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\Enum\Duration;
+
+/**
+ * Trait TraitCompareSetDelete
+ *
+ * This Trait is to compensate non native "exclusive" sets/deletes in caches
+ */
+trait TraitCompareDelete
+{
+       abstract public function get($key);
+
+       abstract public function set($key, $value, $ttl = Duration::FIVE_MINUTES);
+
+       abstract public function delete($key);
+
+       abstract public function add($key, $value, $ttl = Duration::FIVE_MINUTES);
+
+       /**
+        * NonNative - Compares if the old value is set and removes it
+        *
+        * @param string $key          The cache key
+        * @param mixed  $value        The old value we know and want to delete
+        * @return bool
+        */
+       public function compareDelete($key, $value) {
+               if ($this->add($key . "_lock", true)) {
+                       if ($this->get($key) === $value) {
+                               $this->delete($key);
+                               $this->delete($key . "_lock");
+                               return true;
+                       } else {
+                               $this->delete($key . "_lock");
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Cache/Type/TraitCompareSet.php b/src/Core/Cache/Type/TraitCompareSet.php
new file mode 100644 (file)
index 0000000..86aef92
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Core\Cache\Enum\Duration;
+
+/**
+ * Trait TraitCompareSetDelete
+ *
+ * This Trait is to compensate non native "exclusive" sets/deletes in caches
+ */
+trait TraitCompareSet
+{
+       abstract public function get($key);
+
+       abstract public function set($key, $value, $ttl = Duration::FIVE_MINUTES);
+
+       abstract public function delete($key);
+
+       abstract public function add($key, $value, $ttl = Duration::FIVE_MINUTES);
+
+       /**
+        * NonNative - Compares if the old value is set and sets the new value
+        *
+        * @param string $key         The cache key
+        * @param mixed  $oldValue    The old value we know from the cache
+        * @param mixed  $newValue    The new value we want to set
+        * @param int    $ttl      The cache lifespan, must be one of the Cache constants
+        *
+        * @return bool
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Duration::FIVE_MINUTES) {
+               if ($this->add($key . "_lock", true)) {
+                       if ($this->get($key) === $oldValue) {
+                               $this->set($key, $newValue, $ttl);
+                               $this->delete($key . "_lock");
+                               return true;
+                       } else {
+                               $this->delete($key . "_lock");
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Cache/Type/TraitMemcacheCommand.php b/src/Core/Cache/Type/TraitMemcacheCommand.php
new file mode 100644 (file)
index 0000000..73495e2
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Cache\Type;
+
+use Friendica\Network\HTTPException\InternalServerErrorException;
+
+/**
+ * Trait for Memcache to add a custom version of the
+ * method getAllKeys() since this isn't working anymore
+ *
+ * Adds the possibility to directly communicate with the memcache too
+ */
+trait TraitMemcacheCommand
+{
+       /**
+        * @var string server address
+        */
+       protected $server;
+
+       /**
+        * @var int server port
+        */
+       protected $port;
+
+       /**
+        * Retrieves the stored keys of the memcache instance
+        * Uses custom commands, which aren't bound to the used instance of the class
+        *
+        * @todo Due the fact that we use a custom command, there are race conditions possible:
+        *       - $this->memcache(d) adds a key
+        *       - $this->getMemcacheKeys is called directly "after"
+        *       - But $this->memcache(d) isn't finished adding the key, so getMemcacheKeys doesn't find it
+        *
+        * @return array All keys of the memcache instance
+        *
+        * @throws InternalServerErrorException
+        */
+       protected function getMemcacheKeys()
+       {
+               $string = $this->sendMemcacheCommand("stats items");
+               $lines  = explode("\r\n", $string);
+               $slabs  = [];
+               $keys   = [];
+
+               foreach ($lines as $line) {
+
+                       if (preg_match("/STAT items:([\d]+):number ([\d]+)/", $line, $matches) &&
+                           isset($matches[1]) &&
+                           !in_array($matches[1], $keys)) {
+
+                               $slabs[] = $matches[1];
+                               $string  = $this->sendMemcacheCommand("stats cachedump " . $matches[1] . " " . $matches[2]);
+                               preg_match_all("/ITEM (.*?) /", $string, $matches);
+                               $keys = array_merge($keys, $matches[1]);
+                       }
+               }
+
+               return $keys;
+       }
+
+       /**
+        * Taken directly from memcache PECL source
+        * Sends a command to the memcache instance and returns the result
+        * as a string
+        *
+        * http://pecl.php.net/package/memcache
+        *
+        * @param string $command The command to send to the Memcache server
+        *
+        * @return string The returned buffer result
+        *
+        * @throws InternalServerErrorException In case the memcache server isn't available (anymore)
+        */
+       protected function sendMemcacheCommand(string $command)
+       {
+               $s = @fsockopen($this->server, $this->port);
+               if (!$s) {
+                       throw new InternalServerErrorException("Cant connect to:" . $this->server . ':' . $this->port);
+               }
+
+               fwrite($s, $command . "\r\n");
+               $buf = '';
+
+               while (!feof($s)) {
+
+                       $buf .= fgets($s, 256);
+
+                       if (strpos($buf, "END\r\n") !== false) { // stat says end
+                               break;
+                       }
+
+                       if (strpos($buf, "DELETED\r\n") !== false || strpos($buf, "NOT_FOUND\r\n") !== false) { // delete says these
+                               break;
+                       }
+
+                       if (strpos($buf, "OK\r\n") !== false) { // flush_all says ok
+                               break;
+                       }
+               }
+
+               fclose($s);
+               return ($buf);
+       }
+}
index 31c7d1ee12b8a19810d6bd051b323ac05a9c1c2f..20705e06e90241c2a404240f4c82ec54466a7741 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Core\Lock;
 
 use Friendica\Core\BaseLock;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Cache\IMemoryCache;
 
 class CacheLock extends BaseLock
index 688a00dac783098a4e5ea01949e44a19cd94ab07..14e78f625a4c9a2c26c416a9049a2e4ed292f4c9 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Core\Lock;
 
 use Friendica\Core\BaseLock;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Database\Database;
 use Friendica\Util\DateTimeFormat;
 
index 7369e5b5aaa043f75321bd93548dafc6a29e3b7b..35e21305ee80c03cd8ac6f7b6f2b7ba6e451c401 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Core\Lock;
 
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 
 /**
  * Lock Interface
index 219a4d738bb47fa3aa2371f2f3bbc36929dfad3e..fa5cf5e876a9a43ebabafbe3d932b78296c5b7f9 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Core\Lock;
 
 use Friendica\Core\BaseLock;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 
 class SemaphoreLock extends BaseLock
 {
index 259b7d0ce27ee5f754e5c22189ddf9621bbc606f..769bad12eb33ceb0fd3a6f851acb2dace45649f3 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Core\Lock;
 
-use Friendica\Core\Cache\Type as CacheType;
+use Friendica\Core\Cache\Enum\Type as CacheType;
 
 /**
  * Enumeration for lock types
index fa3c6b62d0fa15121791e04d85686ccffd292176..f3ea743117cc68cfc44f33ec6779b2d41403bf5f 100644 (file)
@@ -132,7 +132,7 @@ class Update
 
                                // Compare the current structure with the defined structure
                                // If the Lock is acquired, never release it automatically to avoid double updates
-                               if (DI::lock()->acquire('dbupdate', 0, Cache\Duration::INFINITE)) {
+                               if (DI::lock()->acquire('dbupdate', 0, Cache\Enum\Duration::INFINITE)) {
 
                                        Logger::notice('Update starting.', ['from' => $stored, 'to' => $current]);
 
@@ -246,7 +246,7 @@ class Update
                        // If the update fails or times-out completely you may need to
                        // delete the config entry to try again.
 
-                       if (DI::lock()->acquire('dbupdate_function', 120, Cache\Duration::INFINITE)) {
+                       if (DI::lock()->acquire('dbupdate_function', 120, Cache\Enum\Duration::INFINITE)) {
 
                                // call the specific update
                                Logger::notice('Pre update function start.', ['function' => $funcname]);
diff --git a/src/Factory/CacheFactory.php b/src/Factory/CacheFactory.php
deleted file mode 100644 (file)
index 1e93b5e..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Factory;
-
-use Friendica\App\BaseURL;
-use Friendica\Core\Cache;
-use Friendica\Core\Cache\ICache;
-use Friendica\Core\Config\IConfig;
-use Friendica\Database\Database;
-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\Type::DATABASE;
-
-       /**
-        * @var IConfig 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, IConfig $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\Type::MEMCACHE:
-                               $cache = new Cache\MemcacheCache($this->hostname, $this->config);
-                               break;
-                       case Cache\Type::MEMCACHED:
-                               $cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger);
-                               break;
-                       case Cache\Type::REDIS:
-                               $cache = new Cache\RedisCache($this->hostname, $this->config);
-                               break;
-                       case Cache\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;
-               }
-       }
-}
index 0ac7525035160cecc01a169f6712a6be8ad08e03..2a54910d45f0ba5482c22308af7c2587893c8836 100644 (file)
@@ -21,8 +21,9 @@
 
 namespace Friendica\Factory;
 
+use Friendica\Core\Cache\Factory\CacheFactory;
 use Friendica\Core\Cache\IMemoryCache;
-use Friendica\Core\Cache\Type;
+use Friendica\Core\Cache\Enum\Type;
 use Friendica\Core\Config\IConfig;
 use Friendica\Core\Lock;
 use Friendica\Database\Database;
index 491573033bd4b22994ddda1ce06381d47be5f199..82161fb55405dd471f5865a503bd1df87d0d026a 100644 (file)
@@ -23,7 +23,7 @@ namespace Friendica\Factory;
 
 use Friendica\App;
 use Friendica\Core\Cache\ICache;
-use Friendica\Core\Cache\Type;
+use Friendica\Core\Cache\Enum\Type;
 use Friendica\Core\Config\IConfig;
 use Friendica\Core\Session;
 use Friendica\Core\System;
index a919a67f30e740c88d1e2e13b7d5bd73be34a9ae..5e992075e8d3c8999dcb1f22b67fadf2f30fa8e6 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Model;
 
 use Friendica\Content\Text\HTML;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
index e72004029f8ec3e93674aaa176e6ca4d6f92fdc7..ebd278753b9a17acc2a3e09204fa1010bdc508c5 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Model;
 
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
index d089ada3cd172f87908412237ad2fc42f057bc99..bcd7d54973e9c83d59611e9234234810357eae1f 100644 (file)
@@ -24,7 +24,7 @@ namespace Friendica\Model;
 use Friendica\App;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Widget\ContactBlock;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
index ab7845c2c633ed623ace2e431c2408bc96b4ea4d..fb301d1436299e828913503dcbd55537c7dd4cc6 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Model;
 
 use Friendica\Content\Text\BBCode;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
index 7be5058c2b27041354234fd58e045997fa0b66f7..39bf940972aa7fd36b8b7fece42655e4ff6a635c 100644 (file)
@@ -25,7 +25,7 @@ use Friendica\Content\Nav;
 use Friendica\Content\Pager;
 use Friendica\Content\Text\HTML;
 use Friendica\Content\Widget;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Renderer;
 use Friendica\Core\Search;
index 5e6f772472512fe84f0cdbb91c28face38bc3f05..238aa3c16fc89a2a2042b5fba9b10bc30869debd 100644 (file)
@@ -23,7 +23,7 @@ namespace Friendica\Protocol\ActivityPub;
 
 use Friendica\Content\Feature;
 use Friendica\Content\Text\BBCode;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
index 84f0c6de8218b31d66bf874efbf822dbea60a44e..02d6d270a696fd1ee468ccb14f21215387d3a8a3 100644 (file)
@@ -24,7 +24,7 @@ namespace Friendica\Protocol;
 use Friendica\Content\Feature;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\Markdown;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
index cdecbcf1b07436db6cbe49a59b4862abc75c9b25..a9e50d532ca9cdf749b668ef1dffc24bcf75440b 100644 (file)
@@ -26,7 +26,7 @@ use DOMXPath;
 use Friendica\Content\PageInfo;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Database\DBA;
index c40193e1b08e8c356aad6d138d052f802264ae64..46f68086b196bd667906ace246b9a40f2e0ef348 100644 (file)
@@ -25,7 +25,7 @@ use DOMDocument;
 use DOMXPath;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Database\DBA;
index 6ffe9a0a0f6b06dbede9883fe1306020bd63c5bf..e8c4751c4387266eba55eb35b84b0192a04e3444 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Util;
 
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Exception;
 use Friendica\DI;
index bb69969b9e644a7f257f0ee9766a0ca48af530bd..5e1b1590fd5c906c5e4bd0b4d87eca1fc9b0a2a1 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Worker;
 
-use Friendica\Core\Cache\Duration;
+use Friendica\Core\Cache\Enum\Duration;
 use Friendica\Core\Logger;
 use Friendica\Core\Search;
 use Friendica\DI;
index bf7b412c2ff4c198eb1157a117e7ae305afc5bf5..39aae97fd188e99fd033e199538f6bf5a0207be5 100644 (file)
@@ -158,13 +158,13 @@ return [
                ]
        ],
        Cache\ICache::class             => [
-               'instanceOf' => Factory\CacheFactory::class,
+               'instanceOf' => Cache\Factory\CacheFactory::class,
                'call'       => [
                        ['create', [], Dice::CHAIN_CALL],
                ],
        ],
        Cache\IMemoryCache::class       => [
-               'instanceOf' => Factory\CacheFactory::class,
+               'instanceOf' => Cache\Factory\CacheFactory::class,
                'call'       => [
                        ['create', [], Dice::CHAIN_CALL],
                ],
index d8fe59da03ac0e416f9bd1a0f1086e2dc28e4c60..2f957a5d5b5dc22cefa0d28501c49a62724a81d7 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Test\src\Core\Cache;
 
-use Friendica\Core\Cache\APCuCache;
+use Friendica\Core\Cache\Type\APCuCache;
 
 /**
  * @group APCU
index c2e92806ce94920342366f3203f1048e614d85dd..3623fe0c185872c63ad60a36245fcce3f7df342b 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Test\src\Core\Cache;
 
-use Friendica\Core\Cache\ArrayCache;
+use Friendica\Core\Cache\Type\ArrayCache;
 
 class ArrayCacheTest extends MemoryCacheTest
 {
index 37859ef785ab3228a5c180f1ab0035ccc7c1f94b..8d404b3552be0754df5dd7f584309b8b12f9becf 100644 (file)
@@ -60,7 +60,7 @@ class DatabaseCacheTest extends CacheTest
 
                $dba = new StaticDatabase($configCache, $profiler, $logger);
 
-               $this->cache = new Cache\DatabaseCache('database', $dba);
+               $this->cache = new Cache\Type\DatabaseCache('database', $dba);
                return $this->cache;
        }
 
index 4947186ccb3a14fa58459e002ef151a8e5239116..6916f51695e29194404d3fd322f2cc508d14ef4c 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Cache;
 
 use Exception;
-use Friendica\Core\Cache\MemcacheCache;
+use Friendica\Core\Cache\Type\MemcacheCache;
 use Friendica\Core\Config\IConfig;
 use Mockery;
 
index 842e33d082b2272ee3e9d474f956413876cef734..cc912e364d09e8d73cc1fc143d64b7699f2c4579 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Cache;
 
 use Exception;
-use Friendica\Core\Cache\MemcachedCache;
+use Friendica\Core\Cache\Type\MemcachedCache;
 use Friendica\Core\Config\IConfig;
 use Mockery;
 use Psr\Log\NullLogger;
index 146dca6d9f05986743f3516e1a6373ab78d426b3..f5c540d32d79941f6a9803a43e8381967a3170ba 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Cache;
 
 use Exception;
-use Friendica\Core\Cache\RedisCache;
+use Friendica\Core\Cache\Type\RedisCache;
 use Friendica\Core\Config\IConfig;
 use Mockery;
 
@@ -58,7 +58,7 @@ class RedisCacheTest extends MemoryCacheTest
                        ->andReturn(null);
 
                try {
-                       $this->cache = new RedisCache($host, $configMock);
+                       $this->cache = new \Friendica\Core\Cache\Type\RedisCache($host, $configMock);
                } catch (Exception $e) {
                        static::markTestSkipped('Redis is not available. Failure: ' . $e->getMessage());
                }
index 9f893ab32408a5fd94cf9b2bf6ed7fe43aca3150..750748975a76cb3bf824b7adf50d693bf831371c 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Test\src\Core\Lock;
 
-use Friendica\Core\Cache\APCuCache;
+use Friendica\Core\Cache\Type\APCuCache;
 use Friendica\Core\Lock\CacheLock;
 
 /**
index 11ea794c686e1327346bec09867b6c0c48cc3774..93c2c20526bc344853ca09fb2697c2b3b855a376 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Test\src\Core\Lock;
 
-use Friendica\Core\Cache\ArrayCache;
+use Friendica\Core\Cache\Type\ArrayCache;
 use Friendica\Core\Lock\CacheLock;
 
 class ArrayCacheLockTest extends LockTest
index 98266852f9b808a3e5fd4b258adb69f5120a0403..efb27dcabab60b28846f65e38c2193b121c40ce0 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
-use Friendica\Core\Cache\MemcacheCache;
+use Friendica\Core\Cache\Type\MemcacheCache;
 use Friendica\Core\Config\IConfig;
 use Friendica\Core\Lock\CacheLock;
 use Mockery;
index 67d3097fab58266f7b568e052914574968b575f5..f729364847ec6ff961b0b15ea61a06ea6dc184e8 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
-use Friendica\Core\Cache\MemcachedCache;
+use Friendica\Core\Cache\Type\MemcachedCache;
 use Friendica\Core\Config\IConfig;
 use Friendica\Core\Lock\CacheLock;
 use Mockery;
index 360fa74fb2b1a043d7d25542684d6270e4d22d61..6fdbd1eeb9953451055c0f03b9fcb59f67de3bd9 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
-use Friendica\Core\Cache\RedisCache;
+use Friendica\Core\Cache\Type\RedisCache;
 use Friendica\Core\Config\IConfig;
 use Friendica\Core\Lock\CacheLock;
 use Mockery;