Fix getAllKeys() method for memcache instances
This commit is contained in:
parent
41e2031e6b
commit
e2e109b8c1
|
@ -21,7 +21,7 @@ class ArrayCache extends Cache implements IMemoryCache
|
||||||
*/
|
*/
|
||||||
public function getAllKeys($prefix = null)
|
public function getAllKeys($prefix = null)
|
||||||
{
|
{
|
||||||
return $this->filterArrayKeysByPrefix($this->cachedData, $prefix);
|
return $this->filterArrayKeysByPrefix(array_keys($this->cachedData), $prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -84,19 +84,19 @@ abstract class Cache implements ICache
|
||||||
* Filters the keys of an array with a given prefix
|
* Filters the keys of an array with a given prefix
|
||||||
* Returns the filtered keys as an new array
|
* Returns the filtered keys as an new array
|
||||||
*
|
*
|
||||||
* @param array $array The array, which should get filtered
|
* @param array $keys The keys, which should get filtered
|
||||||
* @param string|null $prefix The prefix (if null, all keys will get returned)
|
* @param string|null $prefix The prefix (if null, all keys will get returned)
|
||||||
*
|
*
|
||||||
* @return array The filtered array with just the keys
|
* @return array The filtered array with just the keys
|
||||||
*/
|
*/
|
||||||
protected function filterArrayKeysByPrefix($array, $prefix = null)
|
protected function filterArrayKeysByPrefix(array $keys, string $prefix = null)
|
||||||
{
|
{
|
||||||
if (empty($prefix)) {
|
if (empty($prefix)) {
|
||||||
return array_keys($array);
|
return $keys;
|
||||||
} else {
|
} else {
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
foreach (array_keys($array) as $key) {
|
foreach ($keys as $key) {
|
||||||
if (strpos($key, $prefix) === 0) {
|
if (strpos($key, $prefix) === 0) {
|
||||||
array_push($result, $key);
|
array_push($result, $key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,17 @@ class MemcachedCache extends Cache implements IMemoryCache
|
||||||
*/
|
*/
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string First server address
|
||||||
|
*/
|
||||||
|
|
||||||
|
private $firstServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int First server port
|
||||||
|
*/
|
||||||
|
private $firstPort;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
|
* Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
|
||||||
* array {
|
* array {
|
||||||
|
@ -58,6 +69,9 @@ class MemcachedCache extends Cache implements IMemoryCache
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->firstServer = $memcached_hosts[0][0] ?? 'localhost';
|
||||||
|
$this->firstPort = $memcached_hosts[0][1] ?? 11211;
|
||||||
|
|
||||||
$this->memcached->addServers($memcached_hosts);
|
$this->memcached->addServers($memcached_hosts);
|
||||||
|
|
||||||
if (count($this->memcached->getServerList()) == 0) {
|
if (count($this->memcached->getServerList()) == 0) {
|
||||||
|
@ -70,14 +84,94 @@ class MemcachedCache extends Cache implements IMemoryCache
|
||||||
*/
|
*/
|
||||||
public function getAllKeys($prefix = null)
|
public function getAllKeys($prefix = null)
|
||||||
{
|
{
|
||||||
$keys = $this->getOriginalKeys($this->memcached->getAllKeys());
|
$keys = $this->getOriginalKeys($this->getMemcachedKeys());
|
||||||
|
|
||||||
if ($this->memcached->getResultCode() == Memcached::RES_SUCCESS) {
|
return $this->filterArrayKeysByPrefix($keys, $prefix);
|
||||||
return $this->filterArrayKeysByPrefix($keys, $prefix);
|
}
|
||||||
} else {
|
|
||||||
$this->logger->debug('Memcached \'getAllKeys\' failed', ['result' => $this->memcached->getResultMessage()]);
|
/**
|
||||||
return [];
|
* Get all memcached keys.
|
||||||
|
* Special function because getAllKeys() is broken since memcached 1.4.23.
|
||||||
|
*
|
||||||
|
* cleaned up version of code found on Stackoverflow.com by Maduka Jayalath
|
||||||
|
*
|
||||||
|
* @return array|int - all retrieved keys (or negative number on error)
|
||||||
|
*/
|
||||||
|
private function getMemcachedKeys()
|
||||||
|
{
|
||||||
|
$mem = @fsockopen($this->firstServer, $this->firstPort);
|
||||||
|
if ($mem === false) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retrieve distinct slab
|
||||||
|
$r = @fwrite($mem, 'stats items' . chr(10));
|
||||||
|
if ($r === false) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$slab = [];
|
||||||
|
while (($l = @fgets($mem, 1024)) !== false) {
|
||||||
|
// finished?
|
||||||
|
$l = trim($l);
|
||||||
|
if ($l == 'END') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$m = [];
|
||||||
|
// <STAT items:22:evicted_nonzero 0>
|
||||||
|
$r = preg_match('/^STAT\sitems\:(\d+)\:/', $l, $m);
|
||||||
|
if ($r != 1) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
$a_slab = $m[1];
|
||||||
|
|
||||||
|
if (!array_key_exists($a_slab, $slab)) {
|
||||||
|
$slab[$a_slab] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset($slab);
|
||||||
|
foreach ($slab as $a_slab_key => &$a_slab) {
|
||||||
|
$r = @fwrite($mem, 'stats cachedump ' . $a_slab_key . ' 100' . chr(10));
|
||||||
|
if ($r === false) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (($l = @fgets($mem, 1024)) !== false) {
|
||||||
|
// finished?
|
||||||
|
$l = trim($l);
|
||||||
|
if ($l == 'END') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$m = [];
|
||||||
|
// ITEM 42 [118 b; 1354717302 s]
|
||||||
|
$r = preg_match('/^ITEM\s([^\s]+)\s/', $l, $m);
|
||||||
|
if ($r != 1) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
$a_key = $m[1];
|
||||||
|
|
||||||
|
$a_slab[] = $a_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the connection
|
||||||
|
@fclose($mem);
|
||||||
|
unset($mem);
|
||||||
|
|
||||||
|
$keys = [];
|
||||||
|
reset($slab);
|
||||||
|
foreach ($slab AS &$a_slab) {
|
||||||
|
reset($a_slab);
|
||||||
|
foreach ($a_slab AS &$a_key) {
|
||||||
|
$keys[] = $a_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($slab);
|
||||||
|
|
||||||
|
return $keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -138,7 +138,7 @@ class DatabaseLock extends Lock
|
||||||
if (empty($prefix)) {
|
if (empty($prefix)) {
|
||||||
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
||||||
} else {
|
} else {
|
||||||
$where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
|
$where = ['`expires` >= ? AND `name` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $this->dba->select('locks', ['name'], $where);
|
$stmt = $this->dba->select('locks', ['name'], $where);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace Friendica\Test\src\Core\Cache;
|
namespace Friendica\Test\src\Core\Cache;
|
||||||
|
|
||||||
use Friendica\Core\Cache\MemcachedCache;
|
|
||||||
use Friendica\Test\MockedTest;
|
use Friendica\Test\MockedTest;
|
||||||
use Friendica\Util\PidFile;
|
use Friendica\Util\PidFile;
|
||||||
|
|
||||||
|
@ -202,10 +201,6 @@ abstract class CacheTest extends MockedTest
|
||||||
*/
|
*/
|
||||||
public function testGetAllKeys($value1, $value2, $value3)
|
public function testGetAllKeys($value1, $value2, $value3)
|
||||||
{
|
{
|
||||||
if ($this->cache instanceof MemcachedCache) {
|
|
||||||
$this->markTestSkipped('Memcached doesn\'t support getAllKeys anymore');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertTrue($this->instance->set('value1', $value1));
|
$this->assertTrue($this->instance->set('value1', $value1));
|
||||||
$this->assertTrue($this->instance->set('value2', $value2));
|
$this->assertTrue($this->instance->set('value2', $value2));
|
||||||
$this->assertTrue($this->instance->set('test_value3', $value3));
|
$this->assertTrue($this->instance->set('test_value3', $value3));
|
||||||
|
@ -219,5 +214,7 @@ abstract class CacheTest extends MockedTest
|
||||||
$list = $this->instance->getAllKeys('test');
|
$list = $this->instance->getAllKeys('test');
|
||||||
|
|
||||||
$this->assertContains('test_value3', $list);
|
$this->assertContains('test_value3', $list);
|
||||||
|
$this->assertNotContains('value1', $list);
|
||||||
|
$this->assertNotContains('value2', $list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue