friendica-5847 Console Cache List command doesn't work
- Added $prefix to all CacheDriver - Moved hostname magic to CacheDriver - Added test for getAllKeys()
This commit is contained in:
		
					parent
					
						
							
								1551570b7f
							
						
					
				
			
			
				commit
				
					
						3f0f3b6ae6
					
				
			
		
					 15 changed files with 131 additions and 48 deletions
				
			
		| 
						 | 
				
			
			@ -51,20 +51,15 @@ class Cache extends \Friendica\BaseObject
 | 
			
		|||
	/**
 | 
			
		||||
	 * @brief Returns all the cache keys sorted alphabetically
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param string $prefix Prefix of the keys (optional)
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return array|null Null if the driver doesn't support this feature
 | 
			
		||||
	 */
 | 
			
		||||
	public static function getAllKeys()
 | 
			
		||||
	public static function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		$time = microtime(true);
 | 
			
		||||
 | 
			
		||||
		$return = self::getDriver()->getAllKeys();
 | 
			
		||||
 | 
			
		||||
		// Keys are prefixed with the node hostname, let's remove it
 | 
			
		||||
		array_walk($return, function (&$value) {
 | 
			
		||||
			$value = preg_replace('/^' . self::getApp()->get_hostname() . ':/', '', $value);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		sort($return);
 | 
			
		||||
		$return = self::getDriver()->getAllKeys($prefix);
 | 
			
		||||
 | 
			
		||||
		self::getApp()->save_timestamp($time, 'cache');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,8 +17,55 @@ abstract class AbstractCacheDriver extends BaseObject
 | 
			
		|||
	 * @param string $key	The original key
 | 
			
		||||
	 * @return string		The cache key used for the cache
 | 
			
		||||
	 */
 | 
			
		||||
	protected function getCacheKey($key) {
 | 
			
		||||
	protected function getCacheKey($key)
 | 
			
		||||
	{
 | 
			
		||||
		// We fetch with the hostname as key to avoid problems with other applications
 | 
			
		||||
		return self::getApp()->get_hostname() . ":" . $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('/^' . self::getApp()->get_hostname() . ':/', '', $value);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			sort($keys);
 | 
			
		||||
 | 
			
		||||
			return $keys;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Filters a list for a given prefix
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param array $list the list
 | 
			
		||||
	 * @param string|null $prefix the prefix
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return array the filtered list
 | 
			
		||||
	 */
 | 
			
		||||
	protected function filterPrefix($list, $prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		if (empty($prefix)) {
 | 
			
		||||
			return array_keys($list);
 | 
			
		||||
		} else {
 | 
			
		||||
			$result = [];
 | 
			
		||||
 | 
			
		||||
			foreach (array_keys($list) as $key) {
 | 
			
		||||
				if (strpos($key, $prefix) === 0) {
 | 
			
		||||
					array_push($result, $key);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return $result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,9 +22,9 @@ class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver
 | 
			
		|||
	/**
 | 
			
		||||
	 * (@inheritdoc)
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys()
 | 
			
		||||
	public function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		return array_keys($this->cachedData);
 | 
			
		||||
		return $this->filterPrefix($this->cachedData, $prefix);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,11 +16,23 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver
 | 
			
		|||
	/**
 | 
			
		||||
	 * (@inheritdoc)
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys()
 | 
			
		||||
	public function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		$stmt = DBA::select('cache', ['k'], ['`expires` >= ?', DateTimeFormat::utcNow()]);
 | 
			
		||||
		if (empty($prefix)) {
 | 
			
		||||
			$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
 | 
			
		||||
		} else {
 | 
			
		||||
			$where = ['`expires` >= ? AND k LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return DBA::toArray($stmt);
 | 
			
		||||
		$stmt = DBA::select('cache', ['k'], $where);
 | 
			
		||||
 | 
			
		||||
		$list = [];
 | 
			
		||||
		while ($key = DBA::fetch($stmt)) {
 | 
			
		||||
			array_push($list, $key['k']);
 | 
			
		||||
		}
 | 
			
		||||
		DBA::close($stmt);
 | 
			
		||||
 | 
			
		||||
		return $list;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,9 +14,11 @@ interface ICacheDriver
 | 
			
		|||
	/**
 | 
			
		||||
	 * Lists all cache keys
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param string prefix optional a prefix to search
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return array|null Null if it isn't supported by the cache driver
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys();
 | 
			
		||||
	public function getAllKeys($prefix = null);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Fetches cached data according to the key
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri
 | 
			
		|||
	/**
 | 
			
		||||
	 * (@inheritdoc)
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys()
 | 
			
		||||
	public function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		$list = [];
 | 
			
		||||
		$allSlabs = $this->memcache->getExtendedStats('slabs');
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,9 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return $list;
 | 
			
		||||
		$list = $this->getOriginalKeys($list);
 | 
			
		||||
 | 
			
		||||
		return $this->filterPrefix($list, $prefix);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ namespace Friendica\Core\Cache;
 | 
			
		|||
use Friendica\Core\Cache;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Friendica\Network\HTTPException\InternalServerErrorException;
 | 
			
		||||
use Memcached;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,9 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr
 | 
			
		|||
 | 
			
		||||
		$this->memcached = new Memcached();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$this->memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, false);
 | 
			
		||||
 | 
			
		||||
		array_walk($memcached_hosts, function (&$value) {
 | 
			
		||||
			if (is_string($value)) {
 | 
			
		||||
				$value = array_map('trim', explode(',', $value));
 | 
			
		||||
| 
						 | 
				
			
			@ -56,9 +60,15 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr
 | 
			
		|||
	/**
 | 
			
		||||
	 * (@inheritdoc)
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys()
 | 
			
		||||
	public function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		return $this->memcached->getAllKeys();
 | 
			
		||||
		// Doesn't work because of https://github.com/php-memcached-dev/php-memcached/issues/367
 | 
			
		||||
		// returns everytime an empty array
 | 
			
		||||
		throw new InternalServerErrorException('getAllKeys for Memcached not supported yet');
 | 
			
		||||
 | 
			
		||||
		$list = $this->getOriginalKeys($this->memcached->getAllKeys());
 | 
			
		||||
 | 
			
		||||
		return $this->filterPrefix($list, $prefix);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,9 +41,17 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
 | 
			
		|||
	/**
 | 
			
		||||
	 * (@inheritdoc)
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAllKeys()
 | 
			
		||||
	public function getAllKeys($prefix = null)
 | 
			
		||||
	{
 | 
			
		||||
		return null;
 | 
			
		||||
		if (empty($prefix)) {
 | 
			
		||||
			$search = '*';
 | 
			
		||||
		} else {
 | 
			
		||||
			$search = $prefix . '*';
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$list = $this->redis->keys($this->getCacheKey($search));
 | 
			
		||||
 | 
			
		||||
		return $this->getOriginalKeys($list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ HELP;
 | 
			
		|||
	private function executeList()
 | 
			
		||||
	{
 | 
			
		||||
		$prefix = $this->getArgument(1);
 | 
			
		||||
		$keys = Core\Cache::getAllKeys();
 | 
			
		||||
		$keys = Core\Cache::getAllKeys($prefix);
 | 
			
		||||
 | 
			
		||||
		if (empty($prefix)) {
 | 
			
		||||
			$this->out('Listing all cache keys:');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,6 @@ use Friendica\Core\Cache\ArrayCache;
 | 
			
		|||
 | 
			
		||||
class ArrayCacheDriverTest extends MemoryCacheTest
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	private $cache;
 | 
			
		||||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache = new ArrayCache();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace Friendica\Test\src\Core\Cache;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Cache\MemcachedCacheDriver;
 | 
			
		||||
use Friendica\Core\Config;
 | 
			
		||||
use Friendica\Test\DatabaseTest;
 | 
			
		||||
use Friendica\Util\DateTimeFormat;
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +14,12 @@ abstract class CacheTest extends DatabaseTest
 | 
			
		|||
	 */
 | 
			
		||||
	protected $instance;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	protected $cache;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	abstract protected function getInstance();
 | 
			
		||||
 | 
			
		||||
	protected function setUp()
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +36,8 @@ abstract class CacheTest extends DatabaseTest
 | 
			
		|||
		Config::set('system', 'throttle_limit_week', 100);
 | 
			
		||||
		Config::set('system', 'throttle_limit_month', 100);
 | 
			
		||||
		Config::set('system', 'theme', 'system_theme');
 | 
			
		||||
 | 
			
		||||
		$this->instance->clear(false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -177,4 +186,27 @@ abstract class CacheTest extends DatabaseTest
 | 
			
		|||
		$received = $this->instance->get('objVal');
 | 
			
		||||
		$this->assertEquals($value, $received, 'Value type changed from ' . gettype($value) . ' to ' . gettype($received));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @small
 | 
			
		||||
	 */
 | 
			
		||||
	public function testGetAllKeys() {
 | 
			
		||||
		if ($this->cache instanceof MemcachedCacheDriver) {
 | 
			
		||||
			$this->markTestSkipped('Memcached doesn\'t support getAllKeys anymore');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$this->assertTrue($this->instance->set('value1', 'test'));
 | 
			
		||||
		$this->assertTrue($this->instance->set('value2', 'test'));
 | 
			
		||||
		$this->assertTrue($this->instance->set('test_value3', 'test'));
 | 
			
		||||
 | 
			
		||||
		$list = $this->instance->getAllKeys();
 | 
			
		||||
 | 
			
		||||
		$this->assertContains('value1', $list);
 | 
			
		||||
		$this->assertContains('value2', $list);
 | 
			
		||||
		$this->assertContains('test_value3', $list);
 | 
			
		||||
 | 
			
		||||
		$list = $this->instance->getAllKeys('test');
 | 
			
		||||
 | 
			
		||||
		$this->assertContains('test_value3', $list);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,11 +6,6 @@ use Friendica\Core\Cache\CacheDriverFactory;
 | 
			
		|||
 | 
			
		||||
class DatabaseCacheDriverTest extends CacheTest
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	private $cache;
 | 
			
		||||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache = CacheDriverFactory::create('database');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,11 +11,6 @@ use Friendica\Core\Cache\CacheDriverFactory;
 | 
			
		|||
 */
 | 
			
		||||
class MemcacheCacheDriverTest extends MemoryCacheTest
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	private $cache;
 | 
			
		||||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache = CacheDriverFactory::create('memcache');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,11 +11,6 @@ use Friendica\Core\Cache\CacheDriverFactory;
 | 
			
		|||
 */
 | 
			
		||||
class MemcachedCacheDriverTest extends MemoryCacheTest
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	private $cache;
 | 
			
		||||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache = CacheDriverFactory::create('memcached');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,11 +11,6 @@ use Friendica\Core\Cache\CacheDriverFactory;
 | 
			
		|||
 */
 | 
			
		||||
class RedisCacheDriverTest extends MemoryCacheTest
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var \Friendica\Core\Cache\IMemoryCacheDriver
 | 
			
		||||
	 */
 | 
			
		||||
	private $cache;
 | 
			
		||||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache = CacheDriverFactory::create('redis');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue