Skip to content

Commit da2790a

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 6a77ef5 commit da2790a

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
@@ -2748,19 +2748,7 @@ static uint8_t crc8(unsigned char *input, size_t len) {
27482748
#endif
27492749

27502750
PHP_REDIS_API int
2751-
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
2752-
{
2753-
char *buf;
2754-
int valfree;
2755-
size_t len;
2756-
2757-
valfree = redis_serialize(redis_sock, z, &buf, &len);
2758-
if (redis_sock->compression == REDIS_COMPRESSION_NONE) {
2759-
*val = buf;
2760-
*val_len = len;
2761-
return valfree;
2762-
}
2763-
2751+
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len) {
27642752
switch (redis_sock->compression) {
27652753
case REDIS_COMPRESSION_LZF:
27662754
#ifdef HAVE_REDIS_LZF
@@ -2773,9 +2761,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
27732761
size = len + MIN(UINT_MAX - len, MAX(LZF_MARGIN, len / 25));
27742762
data = emalloc(size);
27752763
if ((res = lzf_compress(buf, len, data, size)) > 0) {
2776-
if (valfree) efree(buf);
2777-
*val = data;
2778-
*val_len = res;
2764+
*dst = data;
2765+
*dstlen = res;
27792766
return 1;
27802767
}
27812768
efree(data);
@@ -2805,10 +2792,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
28052792
data = emalloc(size);
28062793
size = ZSTD_compress(data, size, buf, len, level);
28072794
if (!ZSTD_isError(size)) {
2808-
if (valfree) efree(buf);
2809-
data = erealloc(data, size);
2810-
*val = data;
2811-
*val_len = size;
2795+
*dst = erealloc(data, size);
2796+
*dstlen = size;
28122797
return 1;
28132798
}
28142799
efree(data);
@@ -2856,22 +2841,21 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
28562841
break;
28572842
}
28582843

2859-
if (valfree) efree(buf);
2860-
*val = lz4buf;
2861-
*val_len = lz4len + REDIS_LZ4_HDR_SIZE;
2844+
*dst = lz4buf;
2845+
*dstlen = lz4len + REDIS_LZ4_HDR_SIZE;
28622846
return 1;
28632847
}
28642848
#endif
28652849
break;
28662850
}
2867-
*val = buf;
2868-
*val_len = len;
2869-
return valfree;
2851+
2852+
*dst = buf;
2853+
*dstlen = len;
2854+
return 0;
28702855
}
28712856

28722857
PHP_REDIS_API int
2873-
redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
2874-
{
2858+
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len) {
28752859
switch (redis_sock->compression) {
28762860
case REDIS_COMPRESSION_LZF:
28772861
#ifdef HAVE_REDIS_LZF
@@ -2880,50 +2864,49 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
28802864
int i;
28812865
uint32_t res;
28822866

2883-
if (val_len == 0)
2867+
if (len == 0)
28842868
break;
28852869

28862870
/* start from two-times bigger buffer and
28872871
* increase it exponentially if needed */
28882872
errno = E2BIG;
28892873
for (i = 2; errno == E2BIG; i *= 2) {
2890-
data = emalloc(i * val_len);
2891-
if ((res = lzf_decompress(val, val_len, data, i * val_len)) == 0) {
2874+
data = emalloc(i * len);
2875+
if ((res = lzf_decompress(src, len, data, i * len)) == 0) {
28922876
/* errno != E2BIG will brake for loop */
28932877
efree(data);
28942878
continue;
2895-
} else if (redis_unserialize(redis_sock, data, res, z_ret) == 0) {
2896-
ZVAL_STRINGL(z_ret, data, res);
28972879
}
2898-
efree(data);
2880+
2881+
*dst = data;
2882+
*dstlen = res;
28992883
return 1;
29002884
}
2885+
2886+
efree(data);
2887+
break;
29012888
}
29022889
#endif
29032890
break;
29042891
case REDIS_COMPRESSION_ZSTD:
29052892
#ifdef HAVE_REDIS_ZSTD
29062893
{
29072894
char *data;
2908-
unsigned long long len;
2895+
unsigned long long zlen;
29092896

2910-
len = ZSTD_getFrameContentSize(val, val_len);
2911-
2912-
if (len != ZSTD_CONTENTSIZE_ERROR && len != ZSTD_CONTENTSIZE_UNKNOWN && len <= INT_MAX)
2913-
{
2914-
size_t zlen;
2897+
zlen = ZSTD_getFrameContentSize(src, len);
2898+
if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
2899+
break;
29152900

2916-
data = emalloc(len);
2917-
zlen = ZSTD_decompress(data, len, val, val_len);
2918-
if (ZSTD_isError(zlen) || zlen != len) {
2919-
efree(data);
2920-
break;
2921-
} else if (redis_unserialize(redis_sock, data, zlen, z_ret) == 0) {
2922-
ZVAL_STRINGL(z_ret, data, zlen);
2923-
}
2901+
data = emalloc(zlen);
2902+
*dstlen = ZSTD_decompress(data, zlen, src, len);
2903+
if (ZSTD_isError(*dstlen) || *dstlen != zlen) {
29242904
efree(data);
2925-
return 1;
2905+
break;
29262906
}
2907+
2908+
*dst = data;
2909+
return 1;
29272910
}
29282911
#endif
29292912
break;
@@ -2936,12 +2919,12 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
29362919

29372920
/* We must have at least enough bytes for our header, and can't have more than
29382921
* INT_MAX + our header size. */
2939-
if (val_len < REDIS_LZ4_HDR_SIZE || val_len > INT_MAX + REDIS_LZ4_HDR_SIZE)
2922+
if (len < REDIS_LZ4_HDR_SIZE || len > INT_MAX + REDIS_LZ4_HDR_SIZE)
29402923
break;
29412924

29422925
/* Operate on copies in case our CRC fails */
2943-
const char *copy = val;
2944-
size_t copylen = val_len;
2926+
const char *copy = src;
2927+
size_t copylen = len;
29452928

29462929
/* Read in our header bytes */
29472930
memcpy(&lz4crc, copy, sizeof(uint8_t));
@@ -2956,23 +2939,59 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
29562939
/* Finally attempt decompression */
29572940
data = emalloc(datalen);
29582941
if (LZ4_decompress_safe(copy, data, copylen, datalen) > 0) {
2959-
if (redis_unserialize(redis_sock, data, datalen, z_ret) == 0) {
2960-
ZVAL_STRINGL(z_ret, data, datalen);
2961-
}
2962-
efree(data);
2942+
*dst = data;
2943+
*dstlen = datalen;
29632944
return 1;
29642945
}
2946+
29652947
efree(data);
29662948
}
29672949
#endif
29682950
break;
29692951
}
2970-
return redis_unserialize(redis_sock, val, val_len, z_ret);
2952+
2953+
*dst = (char*)src;
2954+
*dstlen = len;
2955+
return 0;
2956+
}
2957+
2958+
PHP_REDIS_API int
2959+
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) {
2960+
size_t tmplen;
2961+
int tmpfree;
2962+
char *tmp;
2963+
2964+
/* First serialize */
2965+
tmpfree = redis_serialize(redis_sock, z, &tmp, &tmplen);
2966+
2967+
/* Now attempt compression */
2968+
if (redis_compress(redis_sock, val, val_len, tmp, tmplen)) {
2969+
if (tmpfree) efree(tmp);
2970+
return 1;
2971+
}
2972+
2973+
return tmpfree;
2974+
}
2975+
2976+
PHP_REDIS_API int
2977+
redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) {
2978+
size_t len;
2979+
char *buf;
2980+
2981+
/* Uncompress, then unserialize */
2982+
if (redis_uncompress(redis_sock, &buf, &len, src, srclen)) {
2983+
if (!redis_unserialize(redis_sock, buf, len, zdst)) {
2984+
ZVAL_STRINGL(zdst, buf, len);
2985+
}
2986+
efree(buf);
2987+
return 1;
2988+
}
2989+
2990+
return redis_unserialize(redis_sock, buf, len, zdst);
29712991
}
29722992

29732993
PHP_REDIS_API int
2974-
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len
2975-
)
2994+
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
29762995
{
29772996
php_serialize_data_t ht;
29782997

library.h

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

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

php_redis.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,15 @@ PHP_METHOD(Redis, role);
158158
PHP_METHOD(Redis, getLastError);
159159
PHP_METHOD(Redis, clearLastError);
160160
PHP_METHOD(Redis, _prefix);
161+
PHP_METHOD(Redis, _pack);
162+
PHP_METHOD(Redis, _unpack);
163+
161164
PHP_METHOD(Redis, _serialize);
162165
PHP_METHOD(Redis, _unserialize);
163166

167+
PHP_METHOD(Redis, _compress);
168+
PHP_METHOD(Redis, _uncompress);
169+
164170
PHP_METHOD(Redis, mset);
165171
PHP_METHOD(Redis, msetnx);
166172
PHP_METHOD(Redis, rpoplpush);

redis.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ static zend_function_entry redis_functions[] = {
257257
PHP_ME(Redis, _prefix, arginfo_key, ZEND_ACC_PUBLIC)
258258
PHP_ME(Redis, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
259259
PHP_ME(Redis, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
260+
PHP_ME(Redis, _pack, arginfo_value, ZEND_ACC_PUBLIC)
261+
PHP_ME(Redis, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
262+
PHP_ME(Redis, _compress, arginfo_value, ZEND_ACC_PUBLIC)
263+
PHP_ME(Redis, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
260264
PHP_ME(Redis, acl, arginfo_acl, ZEND_ACC_PUBLIC)
261265
PHP_ME(Redis, append, arginfo_key_value, ZEND_ACC_PUBLIC)
262266
PHP_ME(Redis, auth, arginfo_auth, ZEND_ACC_PUBLIC)
@@ -3252,6 +3256,51 @@ PHP_METHOD(Redis, _unserialize) {
32523256
redis_exception_ce);
32533257
}
32543258

3259+
PHP_METHOD(Redis, _compress) {
3260+
RedisSock *redis_sock;
3261+
3262+
// Grab socket
3263+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3264+
RETURN_FALSE;
3265+
}
3266+
3267+
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3268+
}
3269+
3270+
PHP_METHOD(Redis, _uncompress) {
3271+
RedisSock *redis_sock;
3272+
3273+
// Grab socket
3274+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3275+
RETURN_FALSE;
3276+
}
3277+
3278+
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
3279+
redis_exception_ce);
3280+
}
3281+
3282+
PHP_METHOD(Redis, _pack) {
3283+
RedisSock *redis_sock;
3284+
3285+
// Grab socket
3286+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3287+
RETURN_FALSE;
3288+
}
3289+
3290+
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3291+
}
3292+
3293+
PHP_METHOD(Redis, _unpack) {
3294+
RedisSock *redis_sock;
3295+
3296+
// Grab socket
3297+
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
3298+
RETURN_FALSE;
3299+
}
3300+
3301+
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
3302+
}
3303+
32553304
/* {{{ proto Redis::getLastError() */
32563305
PHP_METHOD(Redis, getLastError) {
32573306
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)
@@ -1971,6 +1975,27 @@ PHP_METHOD(RedisCluster, _unserialize) {
19711975
}
19721976
/* }}} */
19731977

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