mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 16:04:25 +02:00
MDL-69121 core: Add ZSTD/Gzip compression options to Redis sessions
This commit is contained in:
parent
149fdcf075
commit
f2ee4599f7
@ -324,6 +324,9 @@ $CFG->admin = 'admin';
|
||||
// Use the igbinary serializer instead of the php default one. Note that phpredis must be compiled with
|
||||
// igbinary support to make the setting to work. Also, if you change the serializer you have to flush the database!
|
||||
// $CFG->session_redis_serializer_use_igbinary = false; // Optional, default is PHP builtin serializer.
|
||||
// $CFG->session_redis_compressor = 'none'; // Optional, possible values are:
|
||||
// // 'gzip' - PHP GZip compression
|
||||
// // 'zstd' - PHP Zstandard compression
|
||||
//
|
||||
// Please be aware that when selecting Memcached for sessions that it is advised to use a dedicated
|
||||
// memcache server. The memcached extension does not provide isolated environments for individual uses.
|
||||
|
@ -40,6 +40,19 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class redis extends handler {
|
||||
/**
|
||||
* Compressor: none.
|
||||
*/
|
||||
const COMPRESSION_NONE = 'none';
|
||||
/**
|
||||
* Compressor: PHP GZip.
|
||||
*/
|
||||
const COMPRESSION_GZIP = 'gzip';
|
||||
/**
|
||||
* Compressor: PHP Zstandard.
|
||||
*/
|
||||
const COMPRESSION_ZSTD = 'zstd';
|
||||
|
||||
/** @var string $host save_path string */
|
||||
protected $host = '';
|
||||
/** @var int $port The port to connect to */
|
||||
@ -56,6 +69,8 @@ class redis extends handler {
|
||||
protected $lockretry = 100;
|
||||
/** @var int $serializer The serializer to use */
|
||||
protected $serializer = \Redis::SERIALIZER_PHP;
|
||||
/** @var int $compressor The compressor to use */
|
||||
protected $compressor = self::COMPRESSION_NONE;
|
||||
/** @var string $lasthash hash of the session data content */
|
||||
protected $lasthash = null;
|
||||
|
||||
@ -122,6 +137,10 @@ class redis extends handler {
|
||||
if (isset($CFG->session_redis_lock_expire)) {
|
||||
$this->lockexpire = (int)$CFG->session_redis_lock_expire;
|
||||
}
|
||||
|
||||
if (isset($CFG->session_redis_compressor)) {
|
||||
$this->compressor = $CFG->session_redis_compressor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,7 +287,8 @@ class redis extends handler {
|
||||
if ($this->requires_write_lock()) {
|
||||
$this->lock_session($id);
|
||||
}
|
||||
$sessiondata = $this->connection->get($id);
|
||||
$sessiondata = $this->uncompress($this->connection->get($id));
|
||||
|
||||
if ($sessiondata === false) {
|
||||
if ($this->requires_write_lock()) {
|
||||
$this->unlock_session($id);
|
||||
@ -285,6 +305,53 @@ class redis extends handler {
|
||||
return $sessiondata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses session data.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
private function compress($value) {
|
||||
switch ($this->compressor) {
|
||||
case self::COMPRESSION_NONE:
|
||||
return $value;
|
||||
case self::COMPRESSION_GZIP:
|
||||
return gzencode($value);
|
||||
case self::COMPRESSION_ZSTD:
|
||||
return zstd_compress($value);
|
||||
default:
|
||||
debugging("Invalid compressor: {$this->compressor}");
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompresses session data.
|
||||
*
|
||||
* @param string $value
|
||||
* @return mixed
|
||||
*/
|
||||
private function uncompress($value) {
|
||||
if ($value === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($this->compressor) {
|
||||
case self::COMPRESSION_NONE:
|
||||
break;
|
||||
case self::COMPRESSION_GZIP:
|
||||
$value = gzdecode($value);
|
||||
break;
|
||||
case self::COMPRESSION_ZSTD:
|
||||
$value = zstd_uncompress($value);
|
||||
break;
|
||||
default:
|
||||
debugging("Invalid compressor: {$this->compressor}");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the serialized session data to our session store.
|
||||
*
|
||||
@ -312,6 +379,8 @@ class redis extends handler {
|
||||
// There can be race conditions on new sessions racing each other but we can
|
||||
// address that in the future.
|
||||
try {
|
||||
$data = $this->compress($data);
|
||||
|
||||
$this->connection->setex($id, $this->timeout, $data);
|
||||
} catch (RedisException $e) {
|
||||
error_log('Failed talking to redis: '.$e->getMessage());
|
||||
|
@ -116,6 +116,30 @@ class core_session_redis_testcase extends advanced_testcase {
|
||||
$this->assertSessionNoLocks();
|
||||
}
|
||||
|
||||
public function test_compression_read_and_write_works() {
|
||||
global $CFG;
|
||||
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_GZIP;
|
||||
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
$this->assertTrue($sess->handler_write('sess1', 'DATA'));
|
||||
$this->assertSame('DATA', $sess->handler_read('sess1'));
|
||||
$this->assertTrue($sess->handler_close());
|
||||
|
||||
if (extension_loaded('zstd')) {
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_ZSTD;
|
||||
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
$this->assertTrue($sess->handler_write('sess2', 'DATA'));
|
||||
$this->assertSame('DATA', $sess->handler_read('sess2'));
|
||||
$this->assertTrue($sess->handler_close());
|
||||
}
|
||||
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_NONE;
|
||||
}
|
||||
|
||||
public function test_session_blocks_with_existing_session() {
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
|
Loading…
x
Reference in New Issue
Block a user