Separate compression and create utility methods

This commit splits compression and serialization into two distinct parts
and adds some utility functions so the user can compress/uncompress
or pack/unpack data explicily.

See #1939
This commit is contained in:
michael-grunder
2021-04-18 15:27:59 -07:00
parent 2d72c55d7d
commit 4cb4cd0ee2
10 changed files with 330 additions and 75 deletions

137
library.c
View File

@@ -2820,19 +2820,7 @@ static uint8_t crc8(unsigned char *input, size_t len) {
#endif
PHP_REDIS_API int
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
{
char *buf;
int valfree;
size_t len;
valfree = redis_serialize(redis_sock, z, &buf, &len);
if (redis_sock->compression == REDIS_COMPRESSION_NONE) {
*val = buf;
*val_len = len;
return valfree;
}
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
@@ -2845,9 +2833,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
size = len + MIN(UINT_MAX - len, MAX(LZF_MARGIN, len / 25));
data = emalloc(size);
if ((res = lzf_compress(buf, len, data, size)) > 0) {
if (valfree) efree(buf);
*val = data;
*val_len = res;
*dst = data;
*dstlen = res;
return 1;
}
efree(data);
@@ -2877,10 +2864,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
data = emalloc(size);
size = ZSTD_compress(data, size, buf, len, level);
if (!ZSTD_isError(size)) {
if (valfree) efree(buf);
data = erealloc(data, size);
*val = data;
*val_len = size;
*dst = erealloc(data, size);
*dstlen = size;
return 1;
}
efree(data);
@@ -2928,22 +2913,21 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
break;
}
if (valfree) efree(buf);
*val = lz4buf;
*val_len = lz4len + REDIS_LZ4_HDR_SIZE;
*dst = lz4buf;
*dstlen = lz4len + REDIS_LZ4_HDR_SIZE;
return 1;
}
#endif
break;
}
*val = buf;
*val_len = len;
return valfree;
*dst = buf;
*dstlen = len;
return 0;
}
PHP_REDIS_API int
redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
{
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
@@ -2952,24 +2936,27 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
int i;
uint32_t res;
if (val_len == 0)
if (len == 0)
break;
/* start from two-times bigger buffer and
* increase it exponentially if needed */
errno = E2BIG;
for (i = 2; errno == E2BIG; i *= 2) {
data = emalloc(i * val_len);
if ((res = lzf_decompress(val, val_len, data, i * val_len)) == 0) {
data = emalloc(i * len);
if ((res = lzf_decompress(src, len, data, i * len)) == 0) {
/* errno != E2BIG will brake for loop */
efree(data);
continue;
} else if (redis_unserialize(redis_sock, data, res, z_ret) == 0) {
ZVAL_STRINGL(z_ret, data, res);
}
efree(data);
*dst = data;
*dstlen = res;
return 1;
}
efree(data);
break;
}
#endif
break;
@@ -2977,25 +2964,21 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
#ifdef HAVE_REDIS_ZSTD
{
char *data;
unsigned long long len;
unsigned long long zlen;
len = ZSTD_getFrameContentSize(val, val_len);
zlen = ZSTD_getFrameContentSize(src, len);
if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
break;
if (len != ZSTD_CONTENTSIZE_ERROR && len != ZSTD_CONTENTSIZE_UNKNOWN && len <= INT_MAX)
{
size_t zlen;
data = emalloc(len);
zlen = ZSTD_decompress(data, len, val, val_len);
if (ZSTD_isError(zlen) || zlen != len) {
efree(data);
break;
} else if (redis_unserialize(redis_sock, data, zlen, z_ret) == 0) {
ZVAL_STRINGL(z_ret, data, zlen);
}
data = emalloc(zlen);
*dstlen = ZSTD_decompress(data, zlen, src, len);
if (ZSTD_isError(*dstlen) || *dstlen != zlen) {
efree(data);
return 1;
break;
}
*dst = data;
return 1;
}
#endif
break;
@@ -3008,12 +2991,12 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
/* We must have at least enough bytes for our header, and can't have more than
* INT_MAX + our header size. */
if (val_len < REDIS_LZ4_HDR_SIZE || val_len > INT_MAX + REDIS_LZ4_HDR_SIZE)
if (len < REDIS_LZ4_HDR_SIZE || len > INT_MAX + REDIS_LZ4_HDR_SIZE)
break;
/* Operate on copies in case our CRC fails */
const char *copy = val;
size_t copylen = val_len;
const char *copy = src;
size_t copylen = len;
/* Read in our header bytes */
memcpy(&lz4crc, copy, sizeof(uint8_t));
@@ -3028,23 +3011,59 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
/* Finally attempt decompression */
data = emalloc(datalen);
if (LZ4_decompress_safe(copy, data, copylen, datalen) > 0) {
if (redis_unserialize(redis_sock, data, datalen, z_ret) == 0) {
ZVAL_STRINGL(z_ret, data, datalen);
}
efree(data);
*dst = data;
*dstlen = datalen;
return 1;
}
efree(data);
}
#endif
break;
}
return redis_unserialize(redis_sock, val, val_len, z_ret);
*dst = (char*)src;
*dstlen = len;
return 0;
}
PHP_REDIS_API int
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len
)
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) {
size_t tmplen;
int tmpfree;
char *tmp;
/* First serialize */
tmpfree = redis_serialize(redis_sock, z, &tmp, &tmplen);
/* Now attempt compression */
if (redis_compress(redis_sock, val, val_len, tmp, tmplen)) {
if (tmpfree) efree(tmp);
return 1;
}
return tmpfree;
}
PHP_REDIS_API int
redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) {
size_t len;
char *buf;
/* Uncompress, then unserialize */
if (redis_uncompress(redis_sock, &buf, &len, src, srclen)) {
if (!redis_unserialize(redis_sock, buf, len, zdst)) {
ZVAL_STRINGL(zdst, buf, len);
}
efree(buf);
return 1;
}
return redis_unserialize(redis_sock, buf, len, zdst);
}
PHP_REDIS_API int
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
{
php_serialize_data_t ht;

View File

@@ -121,6 +121,11 @@ redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len);
PHP_REDIS_API int
redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
PHP_REDIS_API int
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len);
PHP_REDIS_API int
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len);
PHP_REDIS_API int redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len);
PHP_REDIS_API int redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);

View File

@@ -165,9 +165,15 @@ PHP_METHOD(Redis, role);
PHP_METHOD(Redis, getLastError);
PHP_METHOD(Redis, clearLastError);
PHP_METHOD(Redis, _prefix);
PHP_METHOD(Redis, _pack);
PHP_METHOD(Redis, _unpack);
PHP_METHOD(Redis, _serialize);
PHP_METHOD(Redis, _unserialize);
PHP_METHOD(Redis, _compress);
PHP_METHOD(Redis, _uncompress);
PHP_METHOD(Redis, mset);
PHP_METHOD(Redis, msetnx);
PHP_METHOD(Redis, rpoplpush);

49
redis.c
View File

@@ -286,6 +286,10 @@ static zend_function_entry redis_functions[] = {
PHP_ME(Redis, _prefix, arginfo_key, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _pack, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _compress, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, acl, arginfo_acl, ZEND_ACC_PUBLIC)
PHP_ME(Redis, append, arginfo_key_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, auth, arginfo_auth, ZEND_ACC_PUBLIC)
@@ -3294,6 +3298,51 @@ PHP_METHOD(Redis, _unserialize) {
redis_exception_ce);
}
PHP_METHOD(Redis, _compress) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
PHP_METHOD(Redis, _uncompress) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
redis_exception_ce);
}
PHP_METHOD(Redis, _pack) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
PHP_METHOD(Redis, _unpack) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
/* {{{ proto Redis::getLastError() */
PHP_METHOD(Redis, getLastError) {
zval *object;

View File

@@ -110,6 +110,10 @@ zend_function_entry redis_cluster_functions[] = {
PHP_ME(RedisCluster, _redir, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _compress, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _pack, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, acl, arginfo_acl_cl, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, append, arginfo_key_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, bgrewriteaof, arginfo_key_or_address, ZEND_ACC_PUBLIC)
@@ -1970,6 +1974,27 @@ PHP_METHOD(RedisCluster, _unserialize) {
}
/* }}} */
PHP_METHOD(RedisCluster, _compress) {
redisCluster *c = GET_CONTEXT();
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
PHP_METHOD(RedisCluster, _uncompress) {
redisCluster *c = GET_CONTEXT();
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags,
redis_cluster_exception_ce);
}
PHP_METHOD(RedisCluster, _pack) {
redisCluster *c = GET_CONTEXT();
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
PHP_METHOD(RedisCluster, _unpack) {
redisCluster *c = GET_CONTEXT();
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
/* {{{ proto array RedisCluster::_masters() */
PHP_METHOD(RedisCluster, _masters) {
redisCluster *c = GET_CONTEXT();

View File

@@ -13,7 +13,7 @@
redis_##name##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, &cmd, \
&cmd_len, &slot)
/* Append information required to handle MULTI commands to the tail of our MULTI
/* Append information required to handle MULTI commands to the tail of our MULTI
* linked list. */
#define CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx) \
clusterFoldItem *_item; \
@@ -69,8 +69,8 @@
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
/* More generic processing, where only the keyword differs */
#define CLUSTER_PROCESS_KW_CMD(kw, cmdfunc, resp_func, readcmd) \
redisCluster *c = GET_CONTEXT(); \
@@ -89,7 +89,7 @@
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
/* Create cluster context */
zend_object *create_cluster_context(zend_class_entry *class_type);
@@ -293,6 +293,10 @@ PHP_METHOD(RedisCluster, setoption);
PHP_METHOD(RedisCluster, _prefix);
PHP_METHOD(RedisCluster, _serialize);
PHP_METHOD(RedisCluster, _unserialize);
PHP_METHOD(RedisCluster, _compress);
PHP_METHOD(RedisCluster, _uncompress);
PHP_METHOD(RedisCluster, _pack);
PHP_METHOD(RedisCluster, _unpack);
PHP_METHOD(RedisCluster, _masters);
PHP_METHOD(RedisCluster, _redir);

View File

@@ -4510,4 +4510,67 @@ void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RETURN_ZVAL(&z_ret, 0, 0);
}
void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
zend_string *zstr;
size_t len;
char *buf;
int cmp_free;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
RETURN_FALSE;
}
cmp_free = redis_compress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
RETVAL_STRINGL(buf, len);
if (cmp_free) efree(buf);
}
void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zend_class_entry *ex)
{
zend_string *zstr;
size_t len;
char *buf;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
RETURN_FALSE;
} else if (ZSTR_LEN(zstr) == 0 || redis_sock->compression == REDIS_COMPRESSION_NONE) {
RETURN_STR_COPY(zstr);
}
if (!redis_uncompress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr))) {
zend_throw_exception(ex, "Invalid compressed data or uncompression error", 0);
RETURN_FALSE;
}
RETVAL_STRINGL(buf, len);
efree(buf);
}
void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
int valfree;
size_t len;
char *val;
zval *zv;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
RETURN_FALSE;
}
valfree = redis_pack(redis_sock, zv, &val, &len);
RETVAL_STRINGL(val, len);
if (valfree) efree(val);
}
void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
zend_string *str;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
RETURN_FALSE;
}
if (redis_unpack(redis_sock, ZSTR_VAL(str), ZSTR_LEN(str), return_value) == 0) {
RETURN_STR_COPY(str);
}
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */

View File

@@ -52,7 +52,7 @@ int redis_kv_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
@@ -96,11 +96,11 @@ typedef int (*zrange_cb)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *,char**,int*,int*,short*,void**);
int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
void **ctx);
int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
void **ctx);
int redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
@@ -143,7 +143,7 @@ int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
/* Commands which need a unique construction mechanism. This is either because
* they don't share a signature with any other command, or because there is
* they don't share a signature with any other command, or because there is
* specific processing we do (e.g. verifying subarguments) that make them
* unique */
@@ -174,7 +174,7 @@ int redis_hmset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_hstrlen_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
@@ -313,21 +313,28 @@ int redis_sentinel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_sentinel_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
/* Commands that don't communicate with Redis at all (such as getOption,
/* Commands that don't communicate with Redis at all (such as getOption,
* setOption, _prefix, _serialize, etc). These can be handled in one place
* with the method of grabbing our RedisSock* object in different ways
* with the method of grabbing our RedisSock* object in different ways
* depending if this is a Redis object or a RedisCluster object. */
void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS,
void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex);
void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex);
void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
#endif

View File

@@ -5089,6 +5089,71 @@ class Redis_Test extends TestSuite
}
}
public function testCompressHelpers() {
$compressors = self::getAvailableCompression();
$vals = ['foo', 12345, random_bytes(128), ''];
$oldcmp = $this->redis->getOption(Redis::OPT_COMPRESSION);
foreach ($compressors as $cmp) {
foreach ($vals as $val) {
$this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
$this->redis->set('cmpkey', $val);
/* Get the value raw */
$this->redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE);
$raw = $this->redis->get('cmpkey');
$this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
$this->assertEquals($raw, $this->redis->_compress($val));
$uncompressed = $this->redis->get('cmpkey');
$this->assertEquals($uncompressed, $this->redis->_uncompress($raw));
}
}
$this->redis->setOption(Redis::OPT_COMPRESSION, $oldcmp);
}
public function testPackHelpers() {
list ($oldser, $oldcmp) = [
$this->redis->getOption(Redis::OPT_SERIALIZER),
$this->redis->getOption(Redis::OPT_COMPRESSION)
];
foreach ($this->serializers as $ser) {
$compressors = self::getAvailableCompression();
foreach ($compressors as $cmp) {
$this->redis->setOption(Redis::OPT_SERIALIZER, $ser);
$this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
foreach (['foo', 12345, random_bytes(128), '', ['an', 'array']] as $v) {
/* Can only attempt the array if we're serializing */
if (is_array($v) && $ser == Redis::SERIALIZER_NONE)
continue;
$this->redis->set('packkey', $v);
/* Get the value raw */
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE);
$this->redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE);
$raw = $this->redis->get('packkey');
$this->redis->setOption(Redis::OPT_SERIALIZER, $ser);
$this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
$this->assertEquals($raw, $this->redis->_pack($v));
$unpacked = $this->redis->get('packkey');
$this->assertEquals($unpacked, $this->redis->_unpack($raw));
}
}
}
$this->redis->setOption(Redis::OPT_SERIALIZER, $oldser);
$this->redis->setOption(Redis::OPT_COMPRESSION, $oldcmp);
}
public function testPrefix() {
// no prefix
$this->redis->setOption(Redis::OPT_PREFIX, '');

View File

@@ -39,6 +39,18 @@ class TestSuite
public function getPort() { return $this->i_port; }
public function getAuth() { return $this->auth; }
public static function getAvailableCompression() {
$result[] = Redis::COMPRESSION_NONE;
if (defined('Redis::COMPRESSION_LZF'))
$result[] = Redis::COMPRESSION_LZF;
if (defined('Redis::COMPRESSION_LZ4'))
$result[] = Redis::COMPRESSION_LZ4;
if (defined('Redis::COMPRESSION_ZSTD'))
$result[] = Redis::COMPRESSION_ZSTD;
return $result;
}
/**
* Returns the fully qualified host path,
* which may be used directly for php.ini parameters like session.save_path