]> git.mxchange.org Git - friendica.git/commitdiff
Fix getAllKeys() method for memcache instances
authorPhilipp Holzer <admin+github@philipp.info>
Thu, 15 Aug 2019 11:58:01 +0000 (13:58 +0200)
committerPhilipp Holzer <admin+github@philipp.info>
Thu, 15 Aug 2019 12:26:05 +0000 (14:26 +0200)
src/Core/Cache/ArrayCache.php
src/Core/Cache/Cache.php
src/Core/Cache/MemcachedCache.php
src/Core/Lock/DatabaseLock.php
tests/src/Core/Cache/CacheTest.php

index 5add98cc2a8e69ef6929d52ce77d378ddaa91d39..c6f3983ee2586efed12aeed3a8db4d516ccef3f7 100644 (file)
@@ -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);
        }
 
        /**
index b40c129ae7fe20ba5716f3ba2de4513e5b02d550..cf5b15d052afb877b36ac0b3a47c38abcc2ac3e2 100644 (file)
@@ -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);
                                }
index ac0648a6ceeed06ff0ea702261cf1c37ce77c58e..89685c3f255ce44f83d5745e934eea4a6803c4b5 100644 (file)
@@ -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;
        }
 
        /**
index 2f409cd3d235fa94f1c6523b9ad02eb50f9455c5..07cf88c4948c68716e2114dad031de13aad4caf0 100644 (file)
@@ -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);
index 92fdaffa32754e9b82e31ab3126925a6c6ecfef0..9071a55c402b8dda7928df54e9f109957aa42226 100644 (file)
@@ -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);
        }
 }