Skip to content

Commit

Permalink
Merge branch 'MDL-69121-redis-session-store-compression' of git://git…
Browse files Browse the repository at this point in the history
…hub.com/jamie-catalyst/moodle into master
  • Loading branch information
stronk7 committed Nov 24, 2020
2 parents 01ac1cc + f2ee459 commit 93f4990
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
3 changes: 3 additions & 0 deletions config-dist.php
Expand Up @@ -324,6 +324,9 @@
// 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.
Expand Down
71 changes: 70 additions & 1 deletion lib/classes/session/redis.php
Expand Up @@ -40,6 +40,19 @@
* @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 */
Expand All @@ -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;

Expand Down Expand Up @@ -122,6 +137,10 @@ public function __construct() {
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;
}
}

/**
Expand Down Expand Up @@ -268,7 +287,8 @@ public function handler_read($id) {
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);
Expand All @@ -285,6 +305,53 @@ public function handler_read($id) {
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.
*
Expand Down Expand Up @@ -312,6 +379,8 @@ public function handler_write($id, $data) {
// 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());
Expand Down
24 changes: 24 additions & 0 deletions lib/tests/session_redis_test.php
Expand Up @@ -116,6 +116,30 @@ public function test_normal_session_start_stop_works() {
$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();
Expand Down

0 comments on commit 93f4990

Please sign in to comment.