Reuse lookupCommand data on consecutive same command calls on main thread (#13764)
We can see that on fast commands and fast pipeline use-cases, lookupCommand() takes 1.9% to 3.4% of total cpu cyles (depending on pipeline). In cases in which consecutives commands are the same we can avoid the call to lookupCommand() completely without changing or adding new fields to the client struct (we simply reuse the info already avaiable in lastcmd). This change can represent an improvement of around 4.4% in QPS on the high pipeline use-cases. --------- Co-authored-by: debing.sun <debing.sun@redis.com>
This commit is contained in:
co-authored by
debing.sun
parent
ee933d9e2b
commit
3f06ddfb7b
+19
-2
@@ -80,12 +80,25 @@ struct redisServer server; /* Server global state */
|
||||
/*============================ Internal prototypes ========================== */
|
||||
|
||||
static inline int isShutdownInitiated(void);
|
||||
static inline int isCommandReusable(struct redisCommand *cmd, robj *commandArg);
|
||||
int isReadyToShutdown(void);
|
||||
int finishShutdown(void);
|
||||
const char *replstateToString(int replstate);
|
||||
|
||||
/*============================ Utility functions ============================ */
|
||||
|
||||
/* Check if a given command can be reused without performing a lookup.
|
||||
* A command is reusable if:
|
||||
* - It is not NULL.
|
||||
* - It does not have subcommands (subcommands_dict == NULL).
|
||||
* This preserves simplicity on the check and accounts for the majority of the use cases.
|
||||
* - Its full name matches the provided command argument. */
|
||||
static inline int isCommandReusable(struct redisCommand *cmd, robj *commandArg) {
|
||||
return cmd != NULL &&
|
||||
cmd->subcommands_dict == NULL &&
|
||||
strcasecmp(cmd->fullname, commandArg->ptr) == 0;
|
||||
}
|
||||
|
||||
/* This macro tells if we are in the context of loading an AOF. */
|
||||
#define isAOFLoadingContext() \
|
||||
((server.current_client && server.current_client->id == CLIENT_ID_AOF) ? 1 : 0)
|
||||
@@ -3979,8 +3992,12 @@ int processCommand(client *c) {
|
||||
* In case we are reprocessing a command after it was blocked,
|
||||
* we do not have to repeat the same checks */
|
||||
if (!client_reprocessing_command) {
|
||||
struct redisCommand *cmd = c->iolookedcmd ? c->iolookedcmd : lookupCommand(c->argv, c->argc);
|
||||
|
||||
/* check if we can reuse the last command instead of looking up if we already have that info */
|
||||
struct redisCommand *cmd = NULL;
|
||||
if (isCommandReusable(c->lastcmd, c->argv[0]))
|
||||
cmd = c->lastcmd;
|
||||
else
|
||||
cmd = c->iolookedcmd ? c->iolookedcmd : lookupCommand(c->argv, c->argc);
|
||||
if (!cmd) {
|
||||
/* Handle possible security attacks. */
|
||||
if (!strcasecmp(c->argv[0]->ptr,"host:") || !strcasecmp(c->argv[0]->ptr,"post")) {
|
||||
|
||||
Reference in New Issue
Block a user