diff options
-rw-r--r-- | library.c | 137 | ||||
-rw-r--r-- | library.h | 5 | ||||
-rw-r--r-- | php_redis.h | 6 | ||||
-rw-r--r-- | redis.c | 49 | ||||
-rw-r--r-- | redis_cluster.c | 25 | ||||
-rw-r--r-- | redis_cluster.h | 12 | ||||
-rw-r--r-- | redis_commands.c | 63 | ||||
-rw-r--r-- | redis_commands.h | 31 | ||||
-rw-r--r-- | tests/RedisTest.php | 65 | ||||
-rw-r--r-- | tests/TestSuite.php | 12 |
10 files changed, 330 insertions, 75 deletions
@@ -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; @@ -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); @@ -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 |