diff options
author | yoav-steinberg <yoav@monfort.co.il> | 2021-10-06 11:39:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-06 11:39:09 +0300 |
commit | 5725088ff22065d6d6ce39ed79ed7ad63ff43f92 (patch) | |
tree | d099686acce7ed36a50d4239c4567808d4ed8040 | |
parent | 4fb39b6700c2a08b7de595fbff8102b84c79e562 (diff) | |
download | redis-5725088ff22065d6d6ce39ed79ed7ad63ff43f92.tar.gz |
Avoid argv memcpy when queuing a multi command. (#9602)
When queuing a multi command we duplicated the argv (meaning an alloc
and a memcpy). This isn't needed since we can use the previously allocated
argv and just reset the client objects argv to NULL. This should saves some
memory and is a minor optimization in heavy MULTI/EXEC traffic, especially
if there are lots of arguments.
-rw-r--r-- | src/multi.c | 18 | ||||
-rw-r--r-- | src/server.h | 1 |
2 files changed, 13 insertions, 6 deletions
diff --git a/src/multi.c b/src/multi.c index 4171131b7..5cc846637 100644 --- a/src/multi.c +++ b/src/multi.c @@ -58,7 +58,6 @@ void freeClientMultiState(client *c) { /* Add a new command into the MULTI commands queue */ void queueMultiCommand(client *c) { multiCmd *mc; - int j; /* No sense to waste memory if the transaction is already aborted. * this is useful in case client sends these in a pipeline, or doesn't @@ -72,14 +71,20 @@ void queueMultiCommand(client *c) { mc = c->mstate.commands+c->mstate.count; mc->cmd = c->cmd; mc->argc = c->argc; - mc->argv = zmalloc(sizeof(robj*)*c->argc); - memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc); - for (j = 0; j < c->argc; j++) - incrRefCount(mc->argv[j]); + mc->argv = c->argv; + mc->argv_len = c->argv_len; + c->mstate.count++; c->mstate.cmd_flags |= c->cmd->flags; c->mstate.cmd_inv_flags |= ~c->cmd->flags; c->mstate.argv_len_sums += c->argv_len_sum + sizeof(robj*)*c->argc; + + /* Reset the client's args since we copied them into the mstate and shouldn't + * reference them from c anymore. */ + c->argv = NULL; + c->argc = 0; + c->argv_len_sum = 0; + c->argv_len = 0; } void discardTransaction(client *c) { @@ -206,8 +211,9 @@ void execCommand(client *c) { orig_cmd = c->cmd; addReplyArrayLen(c,c->mstate.count); for (j = 0; j < c->mstate.count; j++) { - c->argv_len = c->argc = c->mstate.commands[j].argc; + c->argc = c->mstate.commands[j].argc; c->argv = c->mstate.commands[j].argv; + c->argv_len = c->mstate.commands[j].argv_len; c->cmd = c->mstate.commands[j].cmd; /* ACL permissions are also checked at the time of execution in case diff --git a/src/server.h b/src/server.h index dbf5512ce..d57e8e16f 100644 --- a/src/server.h +++ b/src/server.h @@ -790,6 +790,7 @@ typedef struct dbBackup dbBackup; /* Client MULTI/EXEC state */ typedef struct multiCmd { robj **argv; + int argv_len; int argc; struct redisCommand *cmd; } multiCmd; |