diff --git a/README.md b/README.md index a3ba530..914b520 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,13 @@ If your Redis instance is remote, you can use this syntax: Port is optional, default is 6379 (default Redis port). +Use persistent connections +-------------------------- + +This mode needs the following setting: + + $settings['redis.connection']['persistent'] = TRUE; + Compression ------------------------- Compressing the data stored in redis can massively reduce the nedeed storage. diff --git a/composer.json b/composer.json index ff18a35..3f468b7 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,11 @@ { "name": "drupal/redis", "type": "drupal-module", + "description": "Integration of Drupal with the Redis key-value store.", "suggest": { "predis/predis": "^1.1.1" }, - "license": "GPL-2.0", + "license": "GPL-2.0-or-later", "autoload": { "psr-4": { "Drupal\\redis\\": "src" diff --git a/modules/redis_sessions/README.md b/modules/redis_sessions/README.md new file mode 100644 index 0000000..a796aa4 --- /dev/null +++ b/modules/redis_sessions/README.md @@ -0,0 +1,41 @@ +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Installation + * Configuration + + +INTRODUCTION +------------ + +The Redis Sessions module creates an alternative to database storage for user +sessions. It uses a PHP Redis sessions manager and custom settings to +use Redis for sessions handling and storage. + + +REQUIREMENTS +------------ + +This module requires the following modules: + + * Redis (https://drupal.org/project/redis) + + +INSTALLATION +------------ + + * Install as you would normally install a contributed Drupal module. See: + https://www.drupal.org/docs/8/extending-drupal-8/installing-modules + for further information. + + +CONFIGURATION +------------- + +Either include the default example.services.yml from the module, which will +replace all supported backend services (check the file for the current list) +or copy the service definitions into a site specific services.yml. + + $settings['container_yamls'][] = 'modules/redis/modules/redis_sessions/example.services.yml'; diff --git a/modules/redis_sessions/example.services.yml b/modules/redis_sessions/example.services.yml new file mode 100644 index 0000000..0ced19e --- /dev/null +++ b/modules/redis_sessions/example.services.yml @@ -0,0 +1,14 @@ +# This file contains example services overrides. +# +# Enable with this line in settings.php +# $settings['container_yamls'][] = 'modules/redis/modules/redis_sessions/example.services.yml'; +# +# Or copy & paste the desired services into sites/default/services.yml. +# +# Note that the redis module must be enabled for this to work. + +services: + # Replaces the default session handler storage with a redis implementation. + session_handler.storage: + class: SessionHandlerInterface + factory: ['@redis_sessions.session_handler.factory', get] diff --git a/modules/redis_sessions/redis_sessions.info.yml b/modules/redis_sessions/redis_sessions.info.yml new file mode 100644 index 0000000..e58b491 --- /dev/null +++ b/modules/redis_sessions/redis_sessions.info.yml @@ -0,0 +1,7 @@ +name: "Redis Sessions" +description: "A module to change PHP's session handling to use Redis." +package: "Performance" +type: module +core_version_requirement: ^8.8 || ^9 +dependencies: + - redis:redis diff --git a/modules/redis_sessions/redis_sessions.services.yml b/modules/redis_sessions/redis_sessions.services.yml new file mode 100644 index 0000000..7ff05aa --- /dev/null +++ b/modules/redis_sessions/redis_sessions.services.yml @@ -0,0 +1,4 @@ +services: + redis_sessions.session_handler.factory: + class: Drupal\redis_sessions\Session\SessionHandlerFactory + arguments: ['@redis.factory'] diff --git a/modules/redis_sessions/src/Session/SessionHandlerFactory.php b/modules/redis_sessions/src/Session/SessionHandlerFactory.php new file mode 100644 index 0000000..6d01dd9 --- /dev/null +++ b/modules/redis_sessions/src/Session/SessionHandlerFactory.php @@ -0,0 +1,41 @@ +clientFactory = $client_factory; + } + + /** + * Get actual session handler. + * + * @return \SessionHandlerInterface + * Return the redis session handler. + */ + public function get() { + $client = $this->clientFactory->getClient(); + return new RedisSessionHandler($client); + } + +} diff --git a/modules/redis_sessions/tests/src/Functional/RedisSessionWebTest.php b/modules/redis_sessions/tests/src/Functional/RedisSessionWebTest.php new file mode 100644 index 0000000..340b9c6 --- /dev/null +++ b/modules/redis_sessions/tests/src/Functional/RedisSessionWebTest.php @@ -0,0 +1,49 @@ +siteDirectory . '/settings.php'; + chmod($filename, 0666); + $contents = file_get_contents($filename); + + // Add the container_yaml and cache definition. + $contents .= "\n\n" . '$settings["container_yamls"][] = "' . drupal_get_path('module', 'redis_sessions') . '/example.services.yml";'; + file_put_contents($filename, $contents); + OpCodeCache::invalidate(DRUPAL_ROOT . '/' . $filename); + + $this->rebuildContainer(); + } + +} diff --git a/redis.info.yml b/redis.info.yml index b227ae2..9348aa6 100644 --- a/redis.info.yml +++ b/redis.info.yml @@ -1,6 +1,7 @@ -name: Redis -description: Provide a module placeholder, for using as dependency for module that needs Redis. -package: Performance +name: "Redis" +description: "Provide a module placeholder, for using as dependency for module that needs Redis." +package: "Performance" type: module core_version_requirement: ^8.8 || ^9 configure: redis.admin_display +php: 7.1.0 diff --git a/redis.install b/redis.install index 3730606..173f6b6 100644 --- a/redis.install +++ b/redis.install @@ -32,7 +32,7 @@ function redis_requirements($phase) { 'title' => "Redis", 'value' => t("Not connected."), 'severity' => REQUIREMENT_WARNING, - 'description' => t("No Redis client connected, this module is useless thereof. Ensure that you enabled module using it or disable it."), + 'description' => t("No Redis client connected, this module is therefore not used. Ensure that Redis is configured correctly, or disable this module."), ]; } diff --git a/src/Cache/CacheBase.php b/src/Cache/CacheBase.php index fbe5089..61b2d74 100644 --- a/src/Cache/CacheBase.php +++ b/src/Cache/CacheBase.php @@ -357,7 +357,7 @@ protected function expandEntry(array $values, $allow_invalid) { * * @return array */ - protected function createEntryHash($cid, $data, $expire = Cache::PERMANENT, array $tags) { + protected function createEntryHash($cid, $data, $expire, array $tags) { // Always add a cache tag for the current bin, so that we can use that for // invalidateAll(). $tags[] = $this->getTagForBin(); diff --git a/src/Cache/RedisCacheTagsChecksum.php b/src/Cache/RedisCacheTagsChecksum.php index cdbae31..a5f03dd 100644 --- a/src/Cache/RedisCacheTagsChecksum.php +++ b/src/Cache/RedisCacheTagsChecksum.php @@ -82,7 +82,8 @@ protected function getTagInvalidationCounts(array $tags) { // The mget command returns the values as an array with numeric keys, // combine it with the tags array to get the expected return value and run // it through intval() to convert to integers and FALSE to 0. - return array_map('intval', array_combine($tags, $this->client->mget($keys))); + $values = $this->client->mget($keys); + return $values ? array_map('intval', array_combine($tags, $values)) : []; } /** diff --git a/src/Client/PhpRedis.php b/src/Client/PhpRedis.php index f9fc11c..7fe1141 100644 --- a/src/Client/PhpRedis.php +++ b/src/Client/PhpRedis.php @@ -14,7 +14,7 @@ class PhpRedis implements ClientInterface { /** * {@inheritdoc} */ - public function getClient($host = NULL, $port = NULL, $base = NULL, $password = NULL) { + public function getClient($host = NULL, $port = NULL, $base = NULL, $password = NULL, $replicationHosts = [], $persistent = FALSE) { $client = new \Redis(); // Sentinel mode, get the real master. @@ -25,7 +25,12 @@ public function getClient($host = NULL, $port = NULL, $base = NULL, $password = } } - $client->connect($host, $port); + if ($persistent) { + $client->pconnect($host, $port); + } + else { + $client->connect($host, $port); + } if (isset($password)) { $client->auth($password); diff --git a/src/Client/Predis.php b/src/Client/Predis.php index 747d73a..9d5d444 100644 --- a/src/Client/Predis.php +++ b/src/Client/Predis.php @@ -11,12 +11,13 @@ */ class Predis implements ClientInterface { - public function getClient($host = NULL, $port = NULL, $base = NULL, $password = NULL, $replicationHosts = NULL) { + public function getClient($host = NULL, $port = NULL, $base = NULL, $password = NULL, $replicationHosts = [], $persistent = FALSE) { $connectionInfo = [ 'password' => $password, 'host' => $host, 'port' => $port, - 'database' => $base + 'database' => $base, + 'persistent' => $persistent ]; foreach ($connectionInfo as $key => $value) { @@ -32,17 +33,19 @@ public function getClient($host = NULL, $port = NULL, $base = NULL, $password = date_default_timezone_set(@date_default_timezone_get()); // If we are passed in an array of $replicationHosts, we should attempt a clustered client connection. - if ($replicationHosts !== NULL) { + if (!empty($replicationHosts)) { $parameters = []; foreach ($replicationHosts as $replicationHost) { + $param = 'tcp://' . $replicationHost['host'] . ':' . $replicationHost['port'] + . '?persistent=' . (($persistent) ? 'true' : 'false'); + // Configure master. if ($replicationHost['role'] === 'primary') { - $parameters[] = 'tcp://' . $replicationHost['host'] . ':' . $replicationHost['port'] . '?alias=master'; - } - else { - $parameters[] = 'tcp://' . $replicationHost['host'] . ':' . $replicationHost['port']; + $param .= '&alias=master'; } + + $parameters[] = $param; } $options = ['replication' => true]; diff --git a/src/ClientFactory.php b/src/ClientFactory.php index e8df702..0120ebc 100644 --- a/src/ClientFactory.php +++ b/src/ClientFactory.php @@ -150,6 +150,7 @@ public static function getClient() { 'port' => self::REDIS_DEFAULT_PORT, 'base' => self::REDIS_DEFAULT_BASE, 'password' => self::REDIS_DEFAULT_PASSWORD, + 'persistent' => FALSE, ]; // If using replication, lets create the client appropriately. @@ -165,14 +166,17 @@ public static function getClient() { $settings['port'], $settings['base'], $settings['password'], - $settings['replication.host']); + $settings['replication.host'], + $settings['persistent']); } else { self::$_client = self::getClientInterface()->getClient( $settings['host'], $settings['port'], $settings['base'], - $settings['password']); + $settings['password'], + [], // There are no replication hosts. + $settings['persistent']); } } diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 38b314f..2ecd895 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -12,7 +12,7 @@ interface ClientInterface { * @return mixed * Real client depends from the library behind. */ - public function getClient($host = NULL, $port = NULL, $base = NULL); + public function getClient($host = NULL, $port = NULL, $base = NULL, $password = NULL, $replicationHosts = [], $persistent = FALSE); /** * Get underlying library name used. diff --git a/src/Controller/ReportController.php b/src/Controller/ReportController.php index 4a4415c..9ff362a 100755 --- a/src/Controller/ReportController.php +++ b/src/Controller/ReportController.php @@ -65,7 +65,7 @@ public static function create(ContainerInterface $container) { public function overview() { $build['report'] = [ - '#theme' => 'status_report', + '#type' => 'status_report', '#requirements' => [], ]; @@ -171,9 +171,9 @@ public function overview() { if ($memory_config['maxmemory']) { $memory_value = $this->t('@used_memory / @max_memory (@used_percentage%), maxmemory policy: @policy', [ - '@used_memory' => $info['used_memory_human'], + '@used_memory' => $info['used_memory_human'] ?? $info['Memory']['used_memory_human'], '@max_memory' => format_size($memory_config['maxmemory']), - '@used_percentage' => (int) ($info['used_memory'] / $memory_config['maxmemory'] * 100), + '@used_percentage' => (int) ($info['used_memory'] ?? $info['Memory']['used_memory'] / $memory_config['maxmemory'] * 100), '@policy' => $memory_config['maxmemory-policy'], ]); } diff --git a/tests/src/Kernel/RedisLockTest.php b/tests/src/Kernel/RedisLockTest.php index f3a9a8e..7594fcf 100644 --- a/tests/src/Kernel/RedisLockTest.php +++ b/tests/src/Kernel/RedisLockTest.php @@ -41,7 +41,7 @@ public function register(ContainerBuilder $container) { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->lock = $this->container->get('lock'); }