8000 Switch from linked list to growing array for reply callbacks · phpredis/phpredis@a551fdc · GitHub
[go: up one dir, main page]

Skip to content

Commit a551fdc

Browse files
JakubOnderkamichael-grunder
authored andcommitted
Switch from linked list to growing array for reply callbacks
Reduce allocation and deallocation count and also memory usage when using pipelining
1 parent be38856 commit a551fdc

File tree

4 files changed

+43
-39
lines changed

4 files changed

+43
-39
lines changed

common.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,9 @@ typedef enum {
181181
} while (0)
182182

183183
#define REDIS_SAVE_CALLBACK(callback, closure_context) do { \
184-
fold_item *fi = malloc(sizeof(fold_item)); \
184+
fold_item *fi = redis_add_reply_callback(redis_sock); \
185185
fi->fun = callback; \
186186
fi->ctx = closure_context; \
187-
fi->next = NULL; \
188-
if (redis_sock->current) { \
189-
redis_sock->current->next = fi; \
190-
} \
191-
redis_sock->current = fi; \
192-
if (NULL == redis_sock->head) { \
193-
redis_sock->head = redis_sock->current; \
194-
} \
195187
} while (0)
196188

197189
#define REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len) \
@@ -315,9 +307,9 @@ typedef struct {
315307
zend_string *prefix;
316308

317309
short mode;
318-
struct fold_item *head;
319-
struct fold_item *current;
320-
310+
struct fold_item *reply_callback;
311+
size_t reply_callback_count;
312+
size_t reply_callback_capacity;
321313
smart_string pipeline_cmd;
322314

323315
zend_string *err;
@@ -341,7 +333,6 @@ typedef int (*FailableResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock*,
341333
typedef struct fold_item {
342334
FailableResultCallback fun;
343335
void *ctx;
344-
struct fold_item *next;
345336
} fold_item;
346337

347338
typedef struct {

library.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numbe 10000 rDiff line change
@@ -3176,7 +3176,7 @@ redis_sock_disconnect(RedisSock *redis_sock, int force, int is_reset_mode)
31763176
}
31773177
if (force || !IS_ATOMIC(redis_sock)) {
31783178
php_stream_pclose(redis_sock->stream);
3179-
free_reply_callbacks(redis_sock);
3179+
redis_free_reply_callbacks(redis_sock);
31803180
if (p) p->nb_active--;
31813181
} else if (p) {
31823182
zend_llist_prepend_element(&p->list, &redis_sock->stream);
@@ -3536,17 +3536,31 @@ redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz)
35363536
return -1;
35373537
}
35383538

3539+
fold_item*
3540+
redis_add_reply_callback(RedisSock *redis_sock) {
3541+
/* Grow array to double size if we need more space */
3542+
if (UNEXPECTED(redis_sock->reply_callback_count == redis_sock->reply_callback_capacity)) {
3543+
if (redis_sock->reply_callback_capacity == 0) {
3544+
redis_sock->reply_callback_capacity = 8; /* initial capacity */
3545+
} else if (redis_sock->reply_callback_capacity < 1024) {
3546+
redis_sock->reply_callback_capacity *= 2;
3547+
} else {
3548+
redis_sock->reply_callback_capacity += 4 * 4096 / sizeof(fold_item);
3549+
}
3550+
redis_sock->reply_callback = erealloc(redis_sock->reply_callback, redis_sock->reply_callback_capacity * sizeof(fold_item));
3551+
}
3552+
return &redis_sock->reply_callback[redis_sock->reply_callback_count++];
3553+
}
3554+
35393555
void
3540-
free_reply_callbacks(RedisSock *redis_sock)
3556+
redis_free_reply_callbacks(RedisSock *redis_sock)
35413557
{
3542-
fold_item *fi;
3543-
3544-
while (redis_sock->head != NULL) {
3545-
fi = redis_sock->head->next;
3546-
free(redis_sock->head);
3547-
redis_sock->head = fi;
3558+
if (redis_sock->reply_callback != NULL) {
3559+
efree(redis_sock->reply_callback);
3560+
redis_sock->reply_callback = NULL;
3561+
redis_sock->reply_callback_count = 0;
3562+
redis_sock->reply_callback_capacity = 0;
35483563
}
3549-
redis_sock->current = NULL;
35503564
}
35513565

35523566
/**
@@ -3577,7 +3591,7 @@ PHP_REDIS_API void redis_free_socket(RedisSock *redis_sock)
35773591
}
35783592
}
35793593
redis_sock_free_auth(redis_sock);
3580-
free_reply_callbacks(redis_sock);
3594+
redis_free_reply_callbacks(redis_sock);
35813595
efree(redis_sock);
35823596
}
35833597

library.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040

4141

4242
void redis_register_persistent_resource(zend_string *id, void *ptr, int le_id);
43-
void free_reply_callbacks(RedisSock *redis_sock);
43+
fold_item* redis_add_reply_callback(RedisSock *redis_sock);
44+
void redis_free_reply_callbacks(RedisSock *redis_sock);
4445

4546
PHP_REDIS_API int redis_extract_auth_info(zval *ztest, zend_string **user, zend_string **pass);
4647

redis.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ PHP_METHOD(Redis,__destruct) {
491491
// queued
492492
redis_send_discard(redis_sock);
493493
}
494-
free_reply_callbacks(redis_sock);
494+
redis_free_reply_callbacks(redis_sock);
495495
}
496496
}
497497

< D7AE code class="diff-text-cell hunk">
@@ -750,7 +750,7 @@ PHP_METHOD(Redis, reset)
750750
RETURN_ZVAL(getThis(), 1, 0);
751751
}
752752

753-
free_reply_callbacks(redis_sock);
753+
redis_free_reply_callbacks(redis_sock);
754754
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
755755
redis_sock->mode = ATOMIC;
756756
redis_sock->dbNumber = 0;
@@ -1953,7 +1953,7 @@ PHP_METHOD(Redis, discard)
19531953
ret = redis_send_discard(redis_sock);
19541954
}
19551955
if (ret == SUCCESS) {
1956-
free_reply_callbacks(redis_sock);
1956+
redis_free_reply_callbacks(redis_sock);
19571957
redis_sock->mode = ATOMIC;
19581958
RETURN_TRUE;
19591959
}
@@ -1975,7 +1975,7 @@ redis_sock_read_multibulk_multi_reply(INTERNAL_FUNCTION_PARAMETERS,
19751975
}
19761976

19771977
// No command issued, return empty immutable array
1978-
if (redis_sock->head == NULL) {
1978+
if (redis_sock->reply_callback == NULL) {
19791979
ZVAL_EMPTY_ARRAY(z_tab);
19801980
return SUCCESS;
19811981
}
@@ -2015,7 +2015,7 @@ PHP_METHOD(Redis, exec)
20152015
}
20162016
ret = redis_sock_read_multibulk_multi_reply(
20172017
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_ret);
2018-
free_reply_callbacks(redis_sock);
2018+
redis_free_reply_callbacks(redis_sock);
20192019
REDIS_DISABLE_MODE(redis_sock, MULTI);
20202020
redis_sock->watching = 0;
20212021
if (ret < 0) {
@@ -2042,7 +2042,7 @@ PHP_METHOD(Redis, exec)
20422042
}
20432043
smart_string_free(&redis_sock->pipeline_cmd);
20442044
}
2045-
free_reply_callbacks(redis_sock);
2045+
redis_free_reply_callbacks(redis_sock);
20462046
REDIS_DISABLE_MODE(redis_sock, PIPELINE);
20472047
}
20482048
RETURN_ZVAL(&z_ret, 0, 1);
@@ -2067,12 +2067,13 @@ PHP_REDIS_API int
20672067
redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS,
20682068
RedisSock *redis_sock, zval 108B2 *z_tab)
20692069
{
2070-
fold_item *fi;
2070+
fold_item fi;
2071+
size_t i;
20712072

2072-
for (fi = redis_sock->head; fi; /* void */) {
2073-
if (fi->fun) {
2074-
fi->fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, fi->ctx);
2075-
fi = fi->next;
2073+
for (i = 0; i < redis_sock->reply_callback_count; i++) {
2074+
fi = redis_sock->reply_callback[i];
2075+
if (fi.fun) {
2076+
fi.fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, fi.ctx);
20762077
continue;
20772078
}
20782079
size_t len;
@@ -2084,7 +2085,7 @@ redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS,
20842085
return FAILURE;
20852086
}
20862087

2087-
while ((fi = fi->next) && fi->fun) {
2088+
while (redis_sock->reply_callback[++i].fun) {
20882089
if (redis_response_enqueued(redis_sock) != SUCCESS) {
20892090
return FAILURE;
20902091
}
@@ -2103,10 +2104,7 @@ redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS,
21032104
if (num > 0 && redis_read_multibulk_recursive(redis_sock, num, 0, &z_ret) < 0) {
21042105
return FAILURE;
21052106
}
2106-
2107-
if (fi) fi = fi->next;
21082107
}
2109-
redis_sock->current = fi;
21102108
return SUCCESS;
21112109
}
21122110

0 commit comments

Comments
 (0)
0