Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Grunder <michael.grunder@gmail.com>2021-06-22 20:18:04 +0300
committerGitHub <noreply@github.com>2021-06-22 20:18:04 +0300
commitc3ab4a25bc186493b6cf73d94c469bab5f134da9 (patch)
tree16046fc52ef712839ae0a252d20e9a9dacb69c21
parent2d72c55d7d0402bfdf147ba71cead38d2573e203 (diff)
parent4cb4cd0ee26fdd1a07f468b976f990dbb9de7ed0 (diff)
Merge pull request #1971 from phpredis/refactor-compression
-rw-r--r--library.c137
-rw-r--r--library.h5
-rw-r--r--php_redis.h6
-rw-r--r--redis.c49
-rw-r--r--redis_cluster.c25
-rw-r--r--redis_cluster.h12
-rw-r--r--redis_commands.c63
-rw-r--r--redis_commands.h31
-rw-r--r--tests/RedisTest.php65
-rw-r--r--tests/TestSuite.php12
10 files changed, 330 insertions, 75 deletions
diff --git a/library.c b/library.c
index 87b6bfa8..d15dad1e 100644
--- a/library.c
+++ b/library.c
@@ -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);
-
- if (len != ZSTD_CONTENTSIZE_ERROR && len != ZSTD_CONTENTSIZE_UNKNOWN && len <= INT_MAX)
- {
- size_t zlen;
+ zlen = ZSTD_getFrameContentSize(src, len);
+ if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
+ break;
- 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_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
- )
+redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
{
php_serialize_data_t ht;
diff --git a/library.h b/library.h
index f78f38c5..2ae55992 100644
--- a/library.h
+++ b/library.h
@@ -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);
diff --git a/php_redis.h b/php_redis.h
index 6b7b3be4..a0c5de40 100644
--- a/php_redis.h
+++ b/php_redis.h
@@ -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);
diff --git a/redis.c b/redis.c
index 230859db..bbf5bd89 100644
--- a/redis.c
+++ b/redis.c
@@ -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;
diff --git a/redis_cluster.c b/redis_cluster.c
index 402c23b7..8c451994 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -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();
diff --git a/redis_cluster.h b/redis_cluster.h
index c6959fde..41f40c1a 100644
--- a/redis_cluster.h
+++ b/redis_cluster.h
@@ -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);
diff --git a/redis_commands.c b/redis_commands.c
index 22d23b82..4d463ba1 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -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: */
diff --git a/redis_commands.h b/redis_commands.h
index be30a310..6550d5c6 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -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,22 +313,29 @@ 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,
RedisSock *redis_sock);
-void redis_serialize_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_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
+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
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index b6b6934c..d2d8ce9d 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -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, '');
diff --git a/tests/TestSuite.php b/tests/TestSuite.php
index c879b330..d4f737f9 100644
--- a/tests/TestSuite.php
+++ b/tests/TestSuite.php
@@ -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