diff --git a/cache/stores/redis/lang/en/cachestore_redis.php b/cache/stores/redis/lang/en/cachestore_redis.php index c9afbbd84f7..a52b93f93fd 100644 --- a/cache/stores/redis/lang/en/cachestore_redis.php +++ b/cache/stores/redis/lang/en/cachestore_redis.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); $string['compressor_none'] = 'No compression.'; $string['compressor_php_gzip'] = 'Use gzip compression.'; +$string['compressor_php_zstd'] = 'Use Zstandard compression.'; $string['pluginname'] = 'Redis'; $string['prefix'] = 'Key prefix'; $string['prefix_help'] = 'This prefix is used for all key names on the Redis server. diff --git a/cache/stores/redis/lib.php b/cache/stores/redis/lib.php index d1c85090397..bde6b9ecc0a 100644 --- a/cache/stores/redis/lib.php +++ b/cache/stores/redis/lib.php @@ -48,6 +48,11 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_ */ const COMPRESSOR_PHP_GZIP = 1; + /** + * Compressor: PHP Zstandard. + */ + const COMPRESSOR_PHP_ZSTD = 2; + /** * Name of this store. * @@ -597,10 +602,17 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_ * @return array */ public static function config_get_compressor_options() { - return [ + $arr = [ self::COMPRESSOR_NONE => get_string('compressor_none', 'cachestore_redis'), self::COMPRESSOR_PHP_GZIP => get_string('compressor_php_gzip', 'cachestore_redis'), ]; + + // Check if the Zstandard PHP extension is installed. + if (extension_loaded('zstd')) { + $arr[self::COMPRESSOR_PHP_ZSTD] = get_string('compressor_php_zstd', 'cachestore_redis'); + } + + return $arr; } /** @@ -619,6 +631,9 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_ case self::COMPRESSOR_PHP_GZIP: return gzencode($value); + case self::COMPRESSOR_PHP_ZSTD: + return zstd_compress($value); + default: debugging("Invalid compressor: {$this->compressor}"); return $value; @@ -642,6 +657,9 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_ case self::COMPRESSOR_PHP_GZIP: $value = gzdecode($value); break; + case self::COMPRESSOR_PHP_ZSTD: + $value = zstd_uncompress($value); + break; default: debugging("Invalid compressor: {$this->compressor}"); } diff --git a/cache/stores/redis/tests/compressor_test.php b/cache/stores/redis/tests/compressor_test.php index 53bfae5ea56..0d9a583938d 100644 --- a/cache/stores/redis/tests/compressor_test.php +++ b/cache/stores/redis/tests/compressor_test.php @@ -166,11 +166,11 @@ class cachestore_redis_compressor_test extends advanced_testcase { } /** - * Provider for serializer tests. + * Provider for set/get combination tests. * * @return array */ - public function provider_for_test_it_can_use_serializers() { + public function provider_for_tests_setget() { $data = [ ['none, none', Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_NONE, @@ -199,20 +199,41 @@ class cachestore_redis_compressor_test extends advanced_testcase { ]; } + if (extension_loaded('zstd')) { + $data[] = [ + 'none, zstd', + Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_PHP_ZSTD, + zstd_compress('value1'), zstd_compress('value2'), + ]; + $data[] = [ + 'php, zstd', + Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_PHP_ZSTD, + zstd_compress(serialize('value1')), zstd_compress(serialize('value2')), + ]; + + if (defined('Redis::SERIALIZER_IGBINARY')) { + $data[] = [ + 'igbinary, zstd', + Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_PHP_ZSTD, + zstd_compress(igbinary_serialize('value1')), zstd_compress(igbinary_serialize('value2')), + ]; + } + } + return $data; } /** - * Test it can use serializers with get and set. + * Test we can use get and set with all combinations. * - * @dataProvider provider_for_test_it_can_use_serializers + * @dataProvider provider_for_tests_setget * @param string $name * @param int $serializer * @param int $compressor * @param string $rawexpected1 * @param string $rawexpected2 */ - public function test_it_can_use_serializers_getset($name, $serializer, $compressor, $rawexpected1, $rawexpected2) { + public function test_it_can_use_getset($name, $serializer, $compressor, $rawexpected1, $rawexpected2) { // Create a connection with the desired serialisation. $store = $this->create_store($compressor, $serializer); $store->set('key', 'value1'); @@ -227,16 +248,16 @@ class cachestore_redis_compressor_test extends advanced_testcase { } /** - * Test it can use serializers with get and set many. + * Test we can use get and set many with all combinations. * - * @dataProvider provider_for_test_it_can_use_serializers + * @dataProvider provider_for_tests_setget * @param string $name * @param int $serializer * @param int $compressor * @param string $rawexpected1 * @param string $rawexpected2 */ - public function test_it_can_use_serializers_getsetmany($name, $serializer, $compressor, $rawexpected1, $rawexpected2) { + public function test_it_can_use_getsetmany($name, $serializer, $compressor, $rawexpected1, $rawexpected2) { $many = [ ['key' => 'key1', 'value' => 'value1'], ['key' => 'key2', 'value' => 'value2'], diff --git a/cache/upgrade.txt b/cache/upgrade.txt index 4a801daebd4..eaf6344da3d 100644 --- a/cache/upgrade.txt +++ b/cache/upgrade.txt @@ -1,6 +1,9 @@ This files describes API changes in /cache/stores/* - cache store plugins. Information provided here is intended especially for developers. +=== 3.8 === +* The Redis cache store can now make use of the Zstandard compression algorithm (see MDL-66428). + === 3.7 === * Upgraded MongoDB cache store to use the new lower level PHP-driver and MongoDB PHP Library. * The mongodb extension has replaced the old mongo extension. The mongodb pecl extension >= 1.5 must be installed to use MongoDB