Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitce5b0fa

Browse files
ImplementHGETEX,HSETEX,HGETDEL, and refactorHMGET (#2667)
* Rework HMGET and implement HGETEXInstead of using a bespoke NULL terminated `zval**` array for thecontext array we can use a `HashTable`. This might be a tiny bit moreexpensive but Zend hashtables are quite efficient and this should alsobe less error prone.* Rework our `HashTable` context array to store keysInstead of sending an array of values we can instead add the fields askeys to our context array. That way when we combine the keys with theRedis provided values we can do it in-place and then just give theHashTable to the user to then do with what they want.* Implement HGETDEL command.* Fix edge cases to abide by legacy behavior.Previously we coerced integer strings into integer keys when zipping`HMGET` responses. This commit adds logic so we continue to do this anddo not change semantics.* Implement `HGETDEL` and `HGETEX` for `RedisCluster`.This commit implements the new commands and reworks the `HMGET` replyhandler to use the new context `HashTable`.* Fix an edge case where we get zero multiblk elements* Tests for `HGETEX` and `HGETDEL`* Minor logic improvementWe don't need to check if `c->reply_len > 0` in the last else blocksince we have already determined it must be.* Implement `HSETEX` for `Redis` and `RedisCluster`* Use `zval_get_tmp_string` ro populating non-long keys
1 parent8dada17 commitce5b0fa

14 files changed

+700
-137
lines changed

‎cluster_library.c‎

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@ static void dump_reply(clusterReply *reply, int indent) {
8787
}
8888
*/
8989

90+
/* MULTI BULK processing callbacks */
91+
staticintmbulk_resp_loop(RedisSock*redis_sock,zval*z_result,
92+
long longcount,void*ctx);
93+
staticintmbulk_resp_loop_raw(RedisSock*redis_sock,zval*z_result,
94+
long longcount,void*ctx);
95+
staticintmbulk_resp_loop_zipstr(RedisSock*redis_sock,zval*z_result,
96+
long longcount,void*ctx);
97+
staticintmbulk_resp_loop_dbl(RedisSock*redis_sock,zval*z_result,
98+
long longcount,void*ctx);
99+
staticintmbulk_resp_loop_zipdbl(RedisSock*redis_sock,zval*z_result,
100+
long longcount,void*ctx);
101+
staticintmbulk_resp_loop_assoc(RedisSock*redis_sock,zval*z_result,
102+
long longcount,void*ctx);
103+
104+
105+
90106

91107
/* Recursively free our reply object. If free_data is non-zero we'll also free
92108
* the payload data (strings) themselves. If not, we just free the structs */
@@ -2267,8 +2283,9 @@ PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS, re
22672283
}
22682284

22692285
/* Generic MULTI BULK response processor */
2270-
PHP_REDIS_APIvoidcluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
2271-
redisCluster*c,mbulk_cbcb,void*ctx)
2286+
staticvoid
2287+
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,
2288+
zend_boolinit_array,mbulk_cbcb,void*ctx)
22722289
{
22732290
zvalz_result;
22742291

@@ -2279,19 +2296,20 @@ PHP_REDIS_API void cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
22792296

22802297
if (c->reply_len==-1&&c->flags->null_mbulk_as_null) {
22812298
ZVAL_NULL(&z_result);
2282-
}else {
2299+
}elseif (c->reply_len <=0){
22832300
array_init(&z_result);
2301+
}else {
2302+
if (init_array)
2303+
array_init(&z_result);
22842304

2285-
if (c->reply_len>0) {
2286-
/* Push serialization settings from the cluster into our socket */
2287-
c->cmd_sock->serializer=c->flags->serializer;
2288-
c->cmd_sock->compression=c->flags->compression;
2305+
/* Push serialization settings from the cluster into our socket */
2306+
c->cmd_sock->serializer=c->flags->serializer;
2307+
c->cmd_sock->compression=c->flags->compression;
22892308

2290-
/* Call our specified callback */
2291-
if (cb(c->cmd_sock,&z_result,c->reply_len,ctx)==FAILURE) {
2292-
zval_dtor(&z_result);
2293-
CLUSTER_RETURN_FALSE(c);
2294-
}
2309+
/* Call our specified callback */
2310+
if (cb(c->cmd_sock,&z_result,c->reply_len,ctx)==FAILURE) {
2311+
zval_dtor(&z_result);
2312+
CLUSTER_RETURN_FALSE(c);
22952313
}
22962314
}
22972315

@@ -2745,15 +2763,15 @@ PHP_REDIS_API void
27452763
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,void*ctx)
27462764
{
27472765
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2748-
mbulk_resp_loop_raw,NULL);
2766+
1,mbulk_resp_loop_raw,NULL);
27492767
}
27502768

27512769
/* Unserialize all the things */
27522770
PHP_REDIS_APIvoid
27532771
cluster_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,void*ctx)
27542772
{
27552773
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2756-
mbulk_resp_loop,NULL);
2774+
1,mbulk_resp_loop,NULL);
27572775
}
27582776

27592777
/* For handling responses where we get key, value, key, value that
@@ -2763,7 +2781,7 @@ cluster_mbulk_zipstr_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
27632781
void*ctx)
27642782
{
27652783
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2766-
mbulk_resp_loop_zipstr,NULL);
2784+
1,mbulk_resp_loop_zipstr,NULL);
27672785
}
27682786

27692787
/* Handling key,value to key=>value where the values are doubles */
@@ -2772,15 +2790,15 @@ cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
27722790
void*ctx)
27732791
{
27742792
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2775-
mbulk_resp_loop_zipdbl,NULL);
2793+
1,mbulk_resp_loop_zipdbl,NULL);
27762794
}
27772795

27782796
PHP_REDIS_APIvoid
27792797
cluster_mbulk_dbl_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,
27802798
void*ctx)
27812799
{
27822800
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2783-
mbulk_resp_loop_dbl,ctx);
2801+
1,mbulk_resp_loop_dbl,ctx);
27842802
}
27852803

27862804
/* Associate multi bulk response (for HMGET really) */
@@ -2789,15 +2807,15 @@ cluster_mbulk_assoc_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
27892807
void*ctx)
27902808
{
27912809
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,
2792-
mbulk_resp_loop_assoc,ctx);
2810+
0,mbulk_resp_loop_assoc,ctx);
27932811
}
27942812

27952813
/*
27962814
* Various MULTI BULK reply callback functions
27972815
*/
27982816

2799-
intmbulk_resp_loop_dbl(RedisSock*redis_sock,zval*z_result,
2800-
long longcount,void*ctx)
2817+
staticintmbulk_resp_loop_dbl(RedisSock*redis_sock,zval*z_result,
2818+
long longcount,void*ctx)
28012819
{
28022820
char*line;
28032821
intline_len;
@@ -2816,8 +2834,8 @@ int mbulk_resp_loop_dbl(RedisSock *redis_sock, zval *z_result,
28162834
}
28172835

28182836
/* MULTI BULK response where we don't touch the values (e.g. KEYS) */
2819-
intmbulk_resp_loop_raw(RedisSock*redis_sock,zval*z_result,
2820-
long longcount,void*ctx)
2837+
staticintmbulk_resp_loop_raw(RedisSock*redis_sock,zval*z_result,
2838+
long longcount,void*ctx)
28212839
{
28222840
char*line;
28232841
intline_len;
@@ -2838,8 +2856,8 @@ int mbulk_resp_loop_raw(RedisSock *redis_sock, zval *z_result,
28382856
}
28392857

28402858
/* MULTI BULK response where we unserialize everything */
2841-
intmbulk_resp_loop(RedisSock*redis_sock,zval*z_result,
2842-
long longcount,void*ctx)
2859+
staticintmbulk_resp_loop(RedisSock*redis_sock,zval*z_result,
2860+
long longcount,void*ctx)
28432861
{
28442862
char*line;
28452863
intline_len;
@@ -2863,8 +2881,8 @@ int mbulk_resp_loop(RedisSock *redis_sock, zval *z_result,
28632881
}
28642882

28652883
/* MULTI BULK response where we turn key1,value1 into key1=>value1 */
2866-
intmbulk_resp_loop_zipstr(RedisSock*redis_sock,zval*z_result,
2867-
long longcount,void*ctx)
2884+
staticintmbulk_resp_loop_zipstr(RedisSock*redis_sock,zval*z_result,
2885+
long longcount,void*ctx)
28682886
{
28692887
char*line,*key=NULL;
28702888
long longidx=0;
@@ -2899,8 +2917,8 @@ int mbulk_resp_loop_zipstr(RedisSock *redis_sock, zval *z_result,
28992917
}
29002918

29012919
/* MULTI BULK loop processor where we expect key,score key, score */
2902-
intmbulk_resp_loop_zipdbl(RedisSock*redis_sock,zval*z_result,
2903-
long longcount,void*ctx)
2920+
staticintmbulk_resp_loop_zipdbl(RedisSock*redis_sock,zval*z_result,
2921+
long longcount,void*ctx)
29042922
{
29052923
char*line,*key=NULL;
29062924
intline_len,key_len=0;
@@ -2937,36 +2955,28 @@ int mbulk_resp_loop_zipdbl(RedisSock *redis_sock, zval *z_result,
29372955
}
29382956

29392957
/* MULTI BULK where we're passed the keys, and we attach vals */
2940-
intmbulk_resp_loop_assoc(RedisSock*redis_sock,zval*z_result,
2941-
long longcount,void*ctx)
2958+
staticintmbulk_resp_loop_assoc(RedisSock*redis_sock,zval*z_result,
2959+
long longcount,void*ctx)
29422960
{
2961+
zval*zfield,z_unpacked;
2962+
HashTable*htctx=ctx;
2963+
intline_len;
29432964
char*line;
2944-
intline_len,i;
2945-
zval*z_keys=ctx;
29462965

2947-
// Loop while we've got replies
2948-
for (i=0;i<count;++i) {
2949-
zend_string*zstr=zval_get_string(&z_keys[i]);
2966+
ZEND_HASH_FOREACH_VAL(htctx,zfield) {
29502967
line=redis_sock_read(redis_sock,&line_len);
2951-
29522968
if (line!=NULL) {
2953-
zvalz_unpacked;
29542969
redis_unpack(redis_sock,line,line_len,&z_unpacked);
2955-
add_assoc_zval_ex(z_result,ZSTR_VAL(zstr),ZSTR_LEN(zstr),&z_unpacked);
29562970
efree(line);
29572971
}else {
2958-
add_assoc_bool_ex(z_result,ZSTR_VAL(zstr),ZSTR_LEN(zstr),0);
2972+
ZVAL_FALSE(&z_unpacked);
29592973
}
29602974

2961-
// Clean up key context
2962-
zend_string_release(zstr);
2963-
zval_dtor(&z_keys[i]);
2964-
}
2975+
ZVAL_COPY_VALUE(zfield,&z_unpacked);
2976+
}ZEND_HASH_FOREACH_END();
29652977

2966-
// Clean up our keys overall
2967-
efree(z_keys);
2978+
ZVAL_ARR(z_result,htctx);
29682979

2969-
// Success!
29702980
returnSUCCESS;
29712981
}
29722982

‎cluster_library.h‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,6 @@ PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS,
462462
redisCluster*c,void*ctx);
463463

464464
/* MULTI BULK response functions */
465-
PHP_REDIS_APIvoidcluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
466-
redisCluster*c,mbulk_cbfunc,void*ctx);
467465
PHP_REDIS_APIvoidcluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
468466
redisCluster*c,void*ctx);
469467
PHP_REDIS_APIvoidcluster_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
@@ -520,20 +518,6 @@ PHP_REDIS_API void cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS,
520518
PHP_REDIS_APIvoidcluster_acl_getuser_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,void*ctx);
521519
PHP_REDIS_APIvoidcluster_acl_log_resp(INTERNAL_FUNCTION_PARAMETERS,redisCluster*c,void*ctx);
522520

523-
/* MULTI BULK processing callbacks */
524-
intmbulk_resp_loop(RedisSock*redis_sock,zval*z_result,
525-
long longcount,void*ctx);
526-
intmbulk_resp_loop_raw(RedisSock*redis_sock,zval*z_result,
527-
long longcount,void*ctx);
528-
intmbulk_resp_loop_zipstr(RedisSock*redis_sock,zval*z_result,
529-
long longcount,void*ctx);
530-
intmbulk_resp_loop_dbl(RedisSock*redis_sock,zval*z_result,
531-
long longcount,void*ctx);
532-
intmbulk_resp_loop_zipdbl(RedisSock*redis_sock,zval*z_result,
533-
long longcount,void*ctx);
534-
intmbulk_resp_loop_assoc(RedisSock*redis_sock,zval*z_result,
535-
long longcount,void*ctx);
536-
537521
#endif
538522

539523
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */

‎library.c‎

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3476,50 +3476,46 @@ redis_mbulk_reply_zipped_raw_variant(RedisSock *redis_sock, zval *zret, int coun
34763476

34773477
/* Specialized multibulk processing for HMGET where we need to pair requested
34783478
* keys with their returned values */
3479-
PHP_REDIS_APIintredis_mbulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS,RedisSock*redis_sock,zval*z_tab,void*ctx)
3479+
PHP_REDIS_APIint
3480+
redis_mbulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS,RedisSock*redis_sock,
3481+
zval*z_tab,void*ctx)
34803482
{
3481-
char*response;
3482-
intresponse_len,retval;
3483-
inti,numElems;
3483+
HashTable*htctx;
3484+
intnumElems;
3485+
zval*zfield;
3486+
char*rresp;
3487+
intlen;
34843488

3485-
zval*z_keys=ctx;
3489+
htctx=ctx;
34863490

3487-
if (read_mbulk_header(redis_sock,&numElems)<0) {
3491+
if (read_mbulk_header(redis_sock,&numElems)<0||
3492+
zend_hash_num_elements(htctx)!=numElems)
3493+
{
3494+
zend_hash_destroy(htctx);
3495+
FREE_HASHTABLE(htctx);
34883496
REDIS_RESPONSE_ERROR(redis_sock,z_tab);
3489-
retval=FAILURE;
3490-
gotoend;
3497+
returnFAILURE;
34913498
}
34923499

3493-
zvalz_multi_result;
3494-
array_init_size(&z_multi_result,numElems);/* pre-allocate array for multi's results. */
3495-
3496-
for(i=0;i<numElems;++i) {
3497-
zend_string*tmp_str;
3498-
zend_string*zstr=zval_get_tmp_string(&z_keys[i],&tmp_str);
3499-
response=redis_sock_read(redis_sock,&response_len);
3500-
zvalz_unpacked;
3501-
if (response!=NULL) {
3502-
redis_unpack(redis_sock,response,response_len,&z_unpacked);
3503-
efree(response);
3500+
zvalz_multi_result,zunpacked;
3501+
3502+
ZEND_HASH_FOREACH_VAL(htctx,zfield) {
3503+
rresp=redis_sock_read(redis_sock,&len);
3504+
3505+
if (rresp!=NULL) {
3506+
redis_unpack(redis_sock,rresp,len,&zunpacked);
3507+
efree(rresp);
35043508
}else {
3505-
ZVAL_FALSE(&z_unpacked);
3509+
ZVAL_FALSE(&zunpacked);
35063510
}
3507-
zend_symtable_update(Z_ARRVAL(z_multi_result),zstr,&z_unpacked);
3508-
zend_tmp_string_release(tmp_str);
3509-
}
35103511

3511-
REDIS_RETURN_ZVAL(redis_sock,z_tab,z_multi_result);
3512-
3513-
retval=SUCCESS;
3512+
ZVAL_COPY_VALUE(zfield,&zunpacked);
3513+
}ZEND_HASH_FOREACH_END();
35143514

3515-
end:
3516-
// Cleanup z_keys
3517-
for (i=0;Z_TYPE(z_keys[i])!=IS_NULL;++i) {
3518-
zval_dtor(&z_keys[i]);
3519-
}
3520-
efree(z_keys);
3515+
ZVAL_ARR(&z_multi_result,htctx);
3516+
REDIS_RETURN_ZVAL(redis_sock,z_tab,z_multi_result);
35213517

3522-
returnretval;
3518+
returnSUCCESS;
35233519
}
35243520

35253521
/**

‎redis.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,18 @@ PHP_METHOD(Redis, hMget) {
18721872
}
18731873
/* }}} */
18741874

1875+
PHP_METHOD(Redis,hgetex) {
1876+
REDIS_PROCESS_CMD(hgetex,redis_mbulk_reply_assoc);
1877+
}
1878+
1879+
PHP_METHOD(Redis,hsetex) {
1880+
REDIS_PROCESS_CMD(hsetex,redis_long_response);
1881+
}
1882+
1883+
PHP_METHOD(Redis,hgetdel) {
1884+
REDIS_PROCESS_CMD(hgetdel,redis_mbulk_reply_assoc);
1885+
}
1886+
18751887
/* {{{ proto bool Redis::hmset(string key, array keyvals) */
18761888
PHP_METHOD(Redis,hMset)
18771889
{

‎redis.stub.php‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,39 @@ public function hLen(string $key): Redis|int|false;
18141814
*/
18151815
publicfunctionhMget(string$key,array$fields):Redis|array|false;
18161816

1817+
/**
1818+
* Get one or more fields of a hash while optionally setting expiration
1819+
* information
1820+
*
1821+
* @param string $key The hash to query.
1822+
* @param array $fields One or more fields to query in the hash.
1823+
* @param string|array $expiry Info about the expiration
1824+
*
1825+
* @return Redis|array|false The fields and values or false if the key didn't exist.
1826+
*/
1827+
publicfunctionhgetex(string$key,array$fields,string|array|null$expiry =null):Redis|array|false;
1828+
1829+
/**
1830+
* Set one or more fields in a hash with optional expiration information.
1831+
*
1832+
* @param string $key The hash to create/update.
1833+
* @param array $fields An array with fields values.
1834+
* @param array|null $expiry Info about the expiration
1835+
*
1836+
* @return Redis|int|false One if fields were set zero if not.
1837+
*/
1838+
publicfunctionhsetex(string$key,array$fields, ?array$expiry =null):Redis|int|false;
1839+
1840+
/**
1841+
* Get one or more fields and delete them
1842+
*
1843+
* @param string $key The hash in question
1844+
* @param array $fields One or more fields
1845+
*
1846+
* @return Redis|array|false The field and values or false on failure
1847+
*/
1848+
publicfunctionhgetdel(string$key,array$fields):Redis|array|false;
1849+
18171850
/**
18181851
* Add or update one or more hash fields and values
18191852
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp