Skip to content

Commit e1a5145

Browse files
Changed the way we build the HMSET command such that we don't
continue to destroy and reallocate the command buffer Added a simply library routine to append to a command buffer using a smart_str Made the unit tests work even if you're not compiled with igbinary Addresses issue phpredis#287
1 parent 07369ed commit e1a5145

File tree

4 files changed

+56
-46
lines changed

4 files changed

+56
-46
lines changed

library.c

+14
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,20 @@ int redis_cmd_append_str(char **cmd, int cmd_len, char *append, int append_len)
447447
return buf.len;
448448
}
449449

450+
/*
451+
* Append a command sequence to a smart_str
452+
*/
453+
int redis_cmd_append_sstr(smart_str *str, char *append, int append_len) {
454+
smart_str_appendc(str, '$');
455+
smart_str_append_long(str, append_len);
456+
smart_str_appendl(str, _NL, sizeof(_NL) - 1);
457+
smart_str_appendl(str, append, append_len);
458+
smart_str_appendl(str, _NL, sizeof(_NL) - 1);
459+
460+
// Return our new length
461+
return str->len;
462+
}
463+
450464
/*
451465
* Append an integer command to a Redis command
452466
*/

library.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ int redis_cmd_format(char **ret, char *format, ...);
44
int redis_cmd_format_static(char **ret, char *keyword, char *format, ...);
55
int redis_cmd_format_header(char **ret, char *keyword, int arg_count);
66
int redis_cmd_append_str(char **cmd, int cmd_len, char *append, int append_len);
7+
int redis_cmd_append_sstr(smart_str *str, char *append, int append_len);
78
int redis_cmd_append_int(char **cmd, int cmd_len, int append);
89

910

redis.c

+37-45
Original file line numberDiff line numberDiff line change
@@ -4856,18 +4856,15 @@ PHP_METHOD(Redis, hMget) {
48564856
REDIS_PROCESS_RESPONSE_CLOSURE(redis_sock_read_multibulk_reply_assoc, z_keys);
48574857
}
48584858

4859-
48604859
PHP_METHOD(Redis, hMset)
48614860
{
48624861
zval *object;
48634862
RedisSock *redis_sock;
4864-
char *key = NULL, *cmd;
4865-
int key_len, cmd_len, key_free;
4863+
char *key = NULL, *cmd, *old_cmd = NULL;
4864+
int key_len, cmd_len, key_free, i, element_count = 2;
48664865
zval *z_hash;
48674866
HashTable *ht_hash;
4868-
int i;
4869-
int element_count = 2;
4870-
char *old_cmd = NULL;
4867+
smart_str set_cmds = {0};
48714868

48724869
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osa",
48734870
&object, redis_ce,
@@ -4885,68 +4882,63 @@ PHP_METHOD(Redis, hMset)
48854882
RETURN_FALSE;
48864883
}
48874884

4888-
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
4889-
cmd_len = redis_cmd_format(&cmd,
4885+
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
4886+
cmd_len = redis_cmd_format(&cmd,
48904887
"$5" _NL "HMSET" _NL
48914888
"$%d" _NL "%s" _NL
48924889
, key_len, key, key_len);
4893-
if(key_free) efree(key);
4890+
if(key_free) efree(key);
48944891

48954892
/* looping on each item of the array */
4896-
for(i =0, zend_hash_internal_pointer_reset(ht_hash);
4897-
zend_hash_has_more_elements(ht_hash) == SUCCESS;
4898-
i++, zend_hash_move_forward(ht_hash)) {
4899-
4900-
char *hkey;
4901-
unsigned int hkey_len;
4902-
unsigned long idx;
4903-
int type;
4904-
int hkey_free = 0;
4905-
zval **z_value_p;
4893+
for(i =0, zend_hash_internal_pointer_reset(ht_hash);
4894+
zend_hash_has_more_elements(ht_hash) == SUCCESS;
4895+
i++, zend_hash_move_forward(ht_hash)) {
4896+
4897+
char *hkey, hkey_str[40];
4898+
unsigned int hkey_len;
4899+
unsigned long idx;
4900+
int type;
4901+
zval **z_value_p;
49064902

4907-
char *hval;
4903+
char *hval;
49084904
int hval_len, hval_free;
49094905

4910-
type = zend_hash_get_current_key_ex(ht_hash, &hkey, &hkey_len, &idx, 0, NULL);
4906+
type = zend_hash_get_current_key_ex(ht_hash, &hkey, &hkey_len, &idx, 0, NULL);
49114907

4912-
if(zend_hash_get_current_data(ht_hash, (void**)&z_value_p) == FAILURE) {
4913-
continue; /* this should never happen */
4914-
}
4908+
if(zend_hash_get_current_data(ht_hash, (void**)&z_value_p) == FAILURE) {
4909+
continue; /* this should never happen */
4910+
}
49154911

4916-
if(type != HASH_KEY_IS_STRING) { /* convert to string */
4917-
hkey_free = 1;
4918-
hkey = emalloc(40);
4919-
hkey_len = 1 + sprintf(hkey, "%ld", idx);
4912+
if(type != HASH_KEY_IS_STRING) { /* convert to string */
4913+
hkey_len = 1 + sprintf(hkey_str, "%ld", idx);
4914+
hkey = (char*)hkey_str;
49204915
}
49214916
element_count += 2;
49224917

49234918
/* key is set. */
49244919
hval_free = redis_serialize(redis_sock, *z_value_p, &hval, &hval_len TSRMLS_CC);
49254920

4926-
old_cmd = cmd;
4927-
cmd_len = redis_cmd_format(&cmd, "%s"
4928-
"$%d" _NL "%s" _NL
4929-
"$%d" _NL "%s" _NL
4930-
, cmd, cmd_len
4931-
, hkey_len-1, hkey, hkey_len-1
4932-
, hval_len, hval, hval_len);
4933-
efree(old_cmd);
4921+
// Append our member and value in place
4922+
redis_cmd_append_sstr(&set_cmds, hkey, hkey_len - 1);
4923+
redis_cmd_append_sstr(&set_cmds, hval, hval_len);
4924+
49344925
if(hval_free) efree(hval);
4935-
if(hkey_free) efree(hkey);
49364926
}
49374927

4928+
// Now construct the entire command
49384929
old_cmd = cmd;
4939-
cmd_len = redis_cmd_format(&cmd, "*%d" _NL "%s"
4940-
, element_count, cmd, cmd_len);
4930+
cmd_len = redis_cmd_format(&cmd, "*%d" _NL "%s%s", element_count, cmd, cmd_len, set_cmds.c, set_cmds.len);
49414931
efree(old_cmd);
49424932

4943-
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
4944-
IF_ATOMIC() {
4945-
redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
4946-
}
4947-
REDIS_PROCESS_RESPONSE(redis_boolean_response);
4948-
}
4933+
// Free the HMSET bits
4934+
efree(set_cmds.c);
49494935

4936+
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
4937+
IF_ATOMIC() {
4938+
redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
4939+
}
4940+
REDIS_PROCESS_RESPONSE(redis_boolean_response);
4941+
}
49504942

49514943

49524944
PHPAPI int redis_response_enqueued(RedisSock *redis_sock TSRMLS_DC) {

tests/TestRedis.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -3263,7 +3263,10 @@ public function testUnserialize() {
32633263
1,1.5,'one',Array('this','is','an','array')
32643264
);
32653265

3266-
foreach(Array(Redis::SERIALIZER_PHP, Redis::SERIALIZER_IGBINARY) as $mode) {
3266+
$serializers = Array(Redis::SERIALIZER_PHP);
3267+
if(defined('Redis::SERIALIZER_IGBINARY')) $serializers[] = Redis::SERIALIZER_IGBINARY;
3268+
3269+
foreach($serializers as $mode) {
32673270
$vals_enc = Array();
32683271

32693272
// Pass them through redis so they're serialized

0 commit comments

Comments
 (0)