Skip to content

Commit 4cb4cd0

Browse files
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 phpredis#1939
1 parent 2d72c55 commit 4cb4cd0

File tree

10 files changed

+330
-75
lines changed

10 files changed

+330
-75
lines changed

library.c

Lines changed: 78 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,19 +2820,7 @@ static uint8_t crc8(unsigned char *input, size_t len) {
28202820
#endif
28212821

28222822
PHP_REDIS_API int
2823-
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
2824-
{
2825-
char *buf;
2826-
int valfree;
2827-
size_t len;
2828-
2829-
valfree = redis_serialize(redis_sock, z, &buf, &len);
2830-
if (redis_sock->compression == REDIS_COMPRESSION_NONE) {
2831-
*val = buf;
2832-
*val_len = len;
2833-
return valfree;
2834-
}
2835-
2823+
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len) {
28362824
switch (redis_sock->compression) {
28372825
case REDIS_COMPRESSION_LZF:
28382826
#ifdef HAVE_REDIS_LZF
@@ -2845,9 +2833,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
28452833
size = len + MIN(UINT_MAX - len, MAX(LZF_MARGIN, len / 25));
28462834
data = emalloc(size);
28472835
if ((res = lzf_compress(buf, len, data, size)) > 0) {
2848-
if (valfree) efree(buf);
2849-
*val = data;
2850-
*val_len = res;
2836+
*dst = data;
2837+
*dstlen = res;
28512838
return 1;
28522839
}
28532840
efree(data);
@@ -2877,10 +2864,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
28772864
data = emalloc(size);
28782865
size = ZSTD_compress(data, size, buf, len, level);
28792866
if (!ZSTD_isError(size)) {
2880-
if (valfree) efree(buf);
2881-
data = erealloc(data, size);
2882-
*val = data;
2883-
*val_len = size;
2867+
*dst = erealloc(data, size);
2868+
*dstlen = size;
28842869
return 1;
28852870
}
28862871
efree(data);
@@ -2928,22 +2913,21 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
29282913
break;
29292914
}
29302915

2931-
if (valfree) efree(buf);
2932-
*val = lz4buf;
2933-
*val_len = lz4len + REDIS_LZ4_HDR_SIZE;
2916+
*dst = lz4buf;
2917+
*dstlen = lz4len + REDIS_LZ4_HDR_SIZE;
29342918
return 1;
29352919
}
29362920
#endif
29372921
break;
29382922
}
2939-
*val = buf;
2940-
*val_len = len;
2941-
return valfree;
2923+
2924+
*dst = buf;
2925+
*dstlen = len;
2926+
return 0;
29422927
}
29432928

29442929
PHP_REDIS_API int
2945-
redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
2946-
{
2930+
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len) {
29472931
switch (redis_sock->compression) {
29482932
case REDIS_COMPRESSION_LZF:
29492933
#ifdef HAVE_REDIS_LZF
@@ -2952,50 +2936,49 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
29522936
int i;
29532937
uint32_t res;
29542938

2955-
if (val_len == 0)
2939+
if (len == 0)
29562940
break;
29572941

29582942
/* start from two-times bigger buffer and
29592943
* increase it exponentially if needed */
29602944
errno = E2BIG;
29612945
for (i = 2; errno == E2BIG; i *= 2) {
2962-
data = emalloc(i * val_len);
2963-
if ((res = lzf_decompress(val, val_len, data, i * val_len)) == 0) {
2946+
data = emalloc(i * len);
2947+
if ((res = lzf_decompress(src, len, data, i * len)) == 0) {
29642948
/* errno != E2BIG will brake for loop */
29652949
efree(data);
29662950
continue;
2967-
} else if (redis_unserialize(redis_sock, data, res, z_ret) == 0) {
2968-
ZVAL_STRINGL(z_ret, data, res);
29692951
}
2970-
efree(data);
2952+
2953+
*dst = data;
2954+
*dstlen = res;
29712955
return 1;
29722956
}
2957+
2958+
efree(data);
2959+
break;
29732960
}
29742961
#endif
29752962
break;
29762963
case REDIS_COMPRESSION_ZSTD:
29772964
#ifdef HAVE_REDIS_ZSTD
29782965
{
29792966
char *data;
2980-
unsigned long long len;
2967+
unsigned long long zlen;
29812968

2982-
len = ZSTD_getFrameContentSize(val, val_len);
2983-
2984-
if (len != ZSTD_CONTENTSIZE_ERROR && len != ZSTD_CONTENTSIZE_UNKNOWN && len <= INT_MAX)
2985-
{
2986-
size_t zlen;
2969+
zlen = ZSTD_getFrameContentSize(src, len);
2970+
if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
2971+
break;
29872972

2988-
data = emalloc(len);
2989-
zlen = ZSTD_decompress(data, len, val, val_len);
2990-
if (ZSTD_isError(zlen) || zlen != len) {
2991-
efree(data);
2992-
break;
2993-
} else if (redis_unserialize(redis_sock, data, zlen, z_ret) == 0) {
2994-
ZVAL_STRINGL(z_ret, data, zlen);
2995-
}
2973+
data = emalloc(zlen);
2974+
*dstlen = ZSTD_decompress(data, zlen, src, len);
2975+
if (ZSTD_isError(*dstlen) || *dstlen != zlen) {
29962976
efree(data);
2997-
return 1;
2977+
break;
29982978
}
2979+
2980+
*dst = data;
2981+
return 1;
29992982
}
30002983
#endif
30012984
break;
@@ -3008,12 +2991,12 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
30082991

30092992
/* We must have at least enough bytes for our header, and can't have more than
30102993
* INT_MAX + our header size. */
3011-
if (val_len < REDIS_LZ4_HDR_SIZE || val_len > INT_MAX + REDIS_LZ4_HDR_SIZE)
2994+
if (len < REDIS_LZ4_HDR_SIZE || len > INT_MAX + REDIS_LZ4_HDR_SIZE)
30122995
break;
30132996

30142997
/* Operate on copies in case our CRC fails */
3015-
const char *copy = val;
3016-
size_t copylen = val_len;
2998+
const char *copy = src;
2999+
size_t copylen = len;
30173000

30183001
/* Read in our header bytes */
30193002
memcpy(&lz4crc, copy, sizeof(uint8_t));
@@ -3028,23 +3011,59 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
30283011
/* Finally attempt decompression */
30293012
data = emalloc(datalen);
30303013
if (LZ4_decompress_safe(copy, data, copylen, datalen) > 0) {
3031-
if (redis_unserialize(redis_sock, data, datalen, z_ret) == 0) {
3032-
ZVAL_STRINGL(z_ret, data, datalen);
3033-
}
3034-
efree(data);
3014+
*dst = data;
3015+
*dstlen = datalen;
30353016
return 1;
30363017
}
3018+
30373019
efree(data);
30383020
}
30393021
#endif
30403022
break;
30413023
}
3042-
return redis_unserialize(redis_sock, val, val_len, z_ret);
3024+
3025+
*dst = (char*)src;
3026+
*dstlen = len;
3027+
return 0;
3028+
}
3029+
3030+
PHP_REDIS_API int
3031+
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) {
3032+
size_t tmplen;
3033+
int tmpfree;
3034+
char *tmp;
3035+
3036+
/* First serialize */
3037+
tmpfree = redis_serialize(redis_sock, z, &tmp, &tmplen);
3038+
3039+
/* Now attempt compression */
3040+
if (redis_compress(redis_sock, val, val_len, tmp, tmplen)) {
3041+
if (tmpfree) efree(tmp);
3042+
return 1;
3043+
}
3044+
3045+
return tmpfree;
3046+
}
3047+
3048+
PHP_REDIS_API int
3049+
redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) {
3050+
size_t len;
3051+
char *buf;
3052+
3053+
/* Uncompress, then unserialize */
3054+
if (redis_uncompress(redis_sock, &buf, &len, src, srclen)) {
3055+
if (!redis_unserialize(redis_sock, buf, len, zdst)) {
3056+
ZVAL_STRINGL(zdst, buf, len);
3057+
}
3058+
efree(buf);
3059+
return 1;
3060+
}
3061+
3062+
return redis_unserialize(redis_sock, buf, len, zdst);
30433063
}
30443064

30453065
PHP_REDIS_API int
3046-
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len
3047-
)
3066+
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
30483067
{
30493068
php_serialize_data_t ht;
30503069

library.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len);
121121
PHP_REDIS_API int
122122
redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
123123

124+
PHP_REDIS_API int
125+
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len);
126+
PHP_REDIS_API int
127+
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len);
128+
124129
PHP_REDIS_API int redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len);
125130
PHP_REDIS_API int redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
126131

php_redis.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,15 @@ PHP_METHOD(Redis, role);
165165
PHP_METHOD(Redis, getLastError);
166166
PHP_METHOD(Redis, clearLastError);
167167
PHP_METHOD(Redis, _prefix);
168+
PHP_METHOD(Redis, _pack);
169+
PHP_METHOD(Redis, _unpack);
170+
168171
PHP_METHOD(Redis, _serialize);
169172
PHP_METHOD(Redis, _unserialize);
170173

174+
PHP_METHOD(Redis, _compress);
175+
PHP_METHOD(Redis, _uncompress);
176+
171177
PHP_METHOD(Redis, mset);
172178
PHP_METHOD(Redis, msetnx);
173179
PHP_METHOD(Redis, rpoplpush);

redis.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ static zend_function_entry redis_functions[] = {
286286
PHP_ME(Redis, _prefix, arginfo_key, ZEND_ACC_PUBLIC)
287287
PHP_ME(Redis, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
288288
PHP_ME(Redis, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
289+
PHP_ME(Redis, _pack, arginfo_value, ZEND_ACC_PUBLIC)
290+
PHP_ME(Redis, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
291+
PHP_ME(Redis, _compress, arginfo_value, ZEND_ACC_PUBLIC)
292+
PHP_ME(Redis, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
289293
PHP_ME(Redis, acl, arginfo_acl, ZEND_ACC_PUBLIC)
290294
PHP_ME(Redis, append, arginfo_key_value, ZEND_ACC_PUBLIC)
291295
PHP_ME(Redis, auth, arginfo_auth, ZEND_ACC_PUBLIC)
@@ -3294,6 +3298,51 @@ PHP_METHOD(Redis, _unserialize) {
32943298
redis_exception_ce);
32953299
}
32963300

3301+
PHP_METHOD(Redis, _compress) {
3302+
RedisSock *redis_sock;
3303+
3304+
// Grab socket
3305+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3306+
RETURN_FALSE;
3307+
}
3308+
3309+
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3310+
}
3311+
3312+
PHP_METHOD(Redis, _uncompress) {
3313+
RedisSock *redis_sock;
3314+
3315+
// Grab socket
3316+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3317+
RETURN_FALSE;
3318+
}
3319+
3320+
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
3321+
redis_exception_ce);
3322+
}
3323+
3324+
PHP_METHOD(Redis, _pack) {
3325+
RedisSock *redis_sock;
3326+
3327+
// Grab socket
3328+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3329+
RETURN_FALSE;
3330+
}
3331+
3332+
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3333+
}
3334+
3335+
PHP_METHOD(Redis, _unpack) {
3336+
RedisSock *redis_sock;
3337+
3338+
// Grab socket
3339+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3340+
RETURN_FALSE;
3341+
}
3342+
3343+
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3344+
}
3345+
32973346
/* {{{ proto Redis::getLastError() */
32983347
PHP_METHOD(Redis, getLastError) {
32993348
zval *object;

redis_cluster.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ zend_function_entry redis_cluster_functions[] = {
110110
PHP_ME(RedisCluster, _redir, arginfo_void, ZEND_ACC_PUBLIC)
111111
PHP_ME(RedisCluster, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
112112
PHP_ME(RedisCluster, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
113+
PHP_ME(RedisCluster, _compress, arginfo_value, ZEND_ACC_PUBLIC)
114+
PHP_ME(RedisCluster, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
115+
PHP_ME(RedisCluster, _pack, arginfo_value, ZEND_ACC_PUBLIC)
116+
PHP_ME(RedisCluster, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
113117
PHP_ME(RedisCluster, acl, arginfo_acl_cl, ZEND_ACC_PUBLIC)
114118
PHP_ME(RedisCluster, append, arginfo_key_value, ZEND_ACC_PUBLIC)
115119
PHP_ME(RedisCluster, bgrewriteaof, arginfo_key_or_address, ZEND_ACC_PUBLIC)
@@ -1970,6 +1974,27 @@ PHP_METHOD(RedisCluster, _unserialize) {
19701974
}
19711975
/* }}} */
19721976

1977+
PHP_METHOD(RedisCluster, _compress) {
1978+
redisCluster *c = GET_CONTEXT();
1979+
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
1980+
}
1981+
1982+
PHP_METHOD(RedisCluster, _uncompress) {
1983+
redisCluster *c = GET_CONTEXT();
1984+
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags,
1985+
redis_cluster_exception_ce);
1986+
}
1987+
1988+
PHP_METHOD(RedisCluster, _pack) {
1989+
redisCluster *c = GET_CONTEXT();
1990+
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
1991+
}
1992+
1993+
PHP_METHOD(RedisCluster, _unpack) {
1994+
redisCluster *c = GET_CONTEXT();
1995+
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
1996+
}
1997+
19731998
/* {{{ proto array RedisCluster::_masters() */
19741999
PHP_METHOD(RedisCluster, _masters) {
19752000
redisCluster *c = GET_CONTEXT();

redis_cluster.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
redis_##name##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, &cmd, \
1414
&cmd_len, &slot)
1515

16-
/* Append information required to handle MULTI commands to the tail of our MULTI
16+
/* Append information required to handle MULTI commands to the tail of our MULTI
1717
* linked list. */
1818
#define CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx) \
1919
clusterFoldItem *_item; \
@@ -69,8 +69,8 @@
6969
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
7070
RETURN_ZVAL(getThis(), 1, 0); \
7171
} \
72-
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
73-
72+
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
73+
7474
/* More generic processing, where only the keyword differs */
7575
#define CLUSTER_PROCESS_KW_CMD(kw, cmdfunc, resp_func, readcmd) \
7676
redisCluster *c = GET_CONTEXT(); \
@@ -89,7 +89,7 @@
8989
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
9090
RETURN_ZVAL(getThis(), 1, 0); \
9191
} \
92-
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
92+
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
9393

9494
/* Create cluster context */
9595
zend_object *create_cluster_context(zend_class_entry *class_type);
@@ -293,6 +293,10 @@ PHP_METHOD(RedisCluster, setoption);
293293
PHP_METHOD(RedisCluster, _prefix);
294294
PHP_METHOD(RedisCluster, _serialize);
295295
PHP_METHOD(RedisCluster, _unserialize);
296+
PHP_METHOD(RedisCluster, _compress);
297+
PHP_METHOD(RedisCluster, _uncompress);
298+
PHP_METHOD(RedisCluster, _pack);
299+
PHP_METHOD(RedisCluster, _unpack);
296300
PHP_METHOD(RedisCluster, _masters);
297301
PHP_METHOD(RedisCluster, _redir);
298302

0 commit comments

Comments
 (0)