Fix getAllKeys() method for memcache instances
This commit is contained in:
parent
41e2031e6b
commit
e2e109b8c1
5 changed files with 108 additions and 17 deletions
|
@ -21,7 +21,7 @@ class ArrayCache extends Cache implements IMemoryCache
|
|||
*/
|
||||
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
|
||||
* 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)
|
||||
*
|
||||
* @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)) {
|
||||
return array_keys($array);
|
||||
return $keys;
|
||||
} else {
|
||||
$result = [];
|
||||
|
||||
foreach (array_keys($array) as $key) {
|
||||
foreach ($keys as $key) {
|
||||
if (strpos($key, $prefix) === 0) {
|
||||
array_push($result, $key);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,17 @@ class MemcachedCache extends Cache implements IMemoryCache
|
|||
*/
|
||||
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:
|
||||
* 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);
|
||||
|
||||
if (count($this->memcached->getServerList()) == 0) {
|
||||
|
@ -70,14 +84,94 @@ class MemcachedCache extends Cache implements IMemoryCache
|
|||
*/
|
||||
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);
|
||||
} else {
|
||||
$this->logger->debug('Memcached \'getAllKeys\' failed', ['result' => $this->memcached->getResultMessage()]);
|
||||
return [];
|
||||
return $this->filterArrayKeysByPrefix($keys, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
||||
} 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);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Friendica\Test\src\Core\Cache;
|
||||
|
||||
use Friendica\Core\Cache\MemcachedCache;
|
||||
use Friendica\Test\MockedTest;
|
||||
use Friendica\Util\PidFile;
|
||||
|
||||
|
@ -202,10 +201,6 @@ abstract class CacheTest extends MockedTest
|
|||
*/
|
||||
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('value2', $value2));
|
||||
$this->assertTrue($this->instance->set('test_value3', $value3));
|
||||
|
@ -219,5 +214,7 @@ abstract class CacheTest extends MockedTest
|
|||
$list = $this->instance->getAllKeys('test');
|
||||
|
||||
$this->assertContains('test_value3', $list);
|
||||
$this->assertNotContains('value1', $list);
|
||||
$this->assertNotContains('value2', $list);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue