Skip to content

Commit c3ab4a2

Browse files
Merge pull request phpredis#1971 from phpredis/refactor-compression
2 parents 2d72c55 + 4cb4cd0 commit c3ab4a2

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)