diff options
author | Viktor Söderqvist <viktor.soderqvist@est.tech> | 2021-02-28 13:11:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-28 14:11:18 +0200 |
commit | 6122f1c450846584eedf614551de0c97da305b45 (patch) | |
tree | c417866fb76551227649ea4be5eb02828d9c41fd /src | |
parent | 4a474843fbd018cd323971b57dec976d7ad0278d (diff) | |
download | redis-6122f1c450846584eedf614551de0c97da305b45.tar.gz |
Shared reusable client for RM_Call() (#8516)
A single client pointer is added in the server struct. This is
initialized by the first RM_Call() and reused for every subsequent
RM_Call() except if it's already in use, which means that it's not
used for (recursive) module calls to modules. For these, a new
"fake" client is created each time.
Other changes:
* Avoid allocating a dict iterator in pubsubUnsubscribeAllChannels
when not needed
Diffstat (limited to 'src')
-rw-r--r-- | src/module.c | 34 | ||||
-rw-r--r-- | src/pubsub.c | 14 | ||||
-rw-r--r-- | src/server.h | 1 |
3 files changed, 38 insertions, 11 deletions
diff --git a/src/module.c b/src/module.c index fe0cd8345..9a37826fb 100644 --- a/src/module.c +++ b/src/module.c @@ -3969,16 +3969,26 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch RedisModuleCallReply *reply = NULL; int replicate = 0; /* Replicate this command? */ - /* Create the client and dispatch the command. */ + /* Handle arguments. */ va_start(ap, fmt); - c = createClient(NULL); - c->user = NULL; /* Root user. */ argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,&flags,ap); replicate = flags & REDISMODULE_ARGV_REPLICATE; va_end(ap); /* Setup our fake client for command execution. */ - c->flags |= CLIENT_MODULE; + if (server.module_client == NULL) { + /* This is the first RM_Call() ever. Create reusable client. */ + c = server.module_client = createClient(NULL); + } else if (server.module_client->argv == NULL) { + /* The reusable module client is not busy with a command. Use it. */ + c = server.module_client; + } else { + /* The reusable module client is busy. (It is probably used in a + * recursive call to this module.) */ + c = createClient(NULL); + } + c->user = NULL; /* Root user. */ + c->flags = CLIENT_MODULE; /* We do not want to allow block, the module do not expect it */ c->flags |= CLIENT_DENY_BLOCKING; @@ -4066,7 +4076,18 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch cleanup: if (ctx->module) ctx->module->in_call--; - freeClient(c); + if (c == server.module_client) { + /* reset shared client so it can be reused */ + discardTransaction(c); + pubsubUnsubscribeAllChannels(c,0); + pubsubUnsubscribeAllPatterns(c,0); + resetClient(c); /* frees the contents of argv */ + zfree(c->argv); + c->argv = NULL; + c->resp = 2; + } else { + freeClient(c); /* temporary client */ + } return reply; } @@ -8269,6 +8290,9 @@ void moduleInitModulesSystem(void) { /* Set up filter list */ moduleCommandFilters = listCreate(); + /* Reusable client for RM_Call() is created on first use */ + server.module_client = NULL; + moduleRegisterCoreAPI(); if (pipe(server.module_blocked_pipe) == -1) { serverLog(LL_WARNING, diff --git a/src/pubsub.c b/src/pubsub.c index a7b370d5d..5f7335bbe 100644 --- a/src/pubsub.c +++ b/src/pubsub.c @@ -250,18 +250,20 @@ int pubsubUnsubscribePattern(client *c, robj *pattern, int notify) { /* Unsubscribe from all the channels. Return the number of channels the * client was subscribed to. */ int pubsubUnsubscribeAllChannels(client *c, int notify) { - dictIterator *di = dictGetSafeIterator(c->pubsub_channels); - dictEntry *de; int count = 0; + if (dictSize(c->pubsub_channels) > 0) { + dictIterator *di = dictGetSafeIterator(c->pubsub_channels); + dictEntry *de; - while((de = dictNext(di)) != NULL) { - robj *channel = dictGetKey(de); + while((de = dictNext(di)) != NULL) { + robj *channel = dictGetKey(de); - count += pubsubUnsubscribeChannel(c,channel,notify); + count += pubsubUnsubscribeChannel(c,channel,notify); + } + dictReleaseIterator(di); } /* We were subscribed to nothing? Still reply to the client. */ if (notify && count == 0) addReplyPubsubUnsubscribed(c,NULL); - dictReleaseIterator(di); return count; } diff --git a/src/server.h b/src/server.h index 5bdcaae64..f52c2ee06 100644 --- a/src/server.h +++ b/src/server.h @@ -1195,6 +1195,7 @@ struct redisServer { to be processed. */ pid_t child_pid; /* PID of current child */ int child_type; /* Type of current child */ + client *module_client; /* "Fake" client to call Redis from modules */ /* Networking */ int port; /* TCP listening port */ int tls_port; /* TLS listening port */ |