summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorViktor Söderqvist <viktor.soderqvist@est.tech>2021-02-28 13:11:18 +0100
committerGitHub <noreply@github.com>2021-02-28 14:11:18 +0200
commit6122f1c450846584eedf614551de0c97da305b45 (patch)
treec417866fb76551227649ea4be5eb02828d9c41fd /src
parent4a474843fbd018cd323971b57dec976d7ad0278d (diff)
downloadredis-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.c34
-rw-r--r--src/pubsub.c14
-rw-r--r--src/server.h1
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 */