summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSalvatore Sanfilippo <antirez@gmail.com>2019-10-28 09:55:11 +0100
committerGitHub <noreply@github.com>2019-10-28 09:55:11 +0100
commit24fdc87fe0fafe4f9ccb7acdeeac1748e27ed212 (patch)
treead037b663882b2bda83ea7ab7506bc4351c1e598
parent6e98214f740eb04c9761ccb983ba51988ee35bc2 (diff)
parentc74398e130af6983aa7d109a7b19bb9bb2668745 (diff)
downloadredis-24fdc87fe0fafe4f9ccb7acdeeac1748e27ed212.tar.gz
Merge pull request #4994 from soloestoy/module-blocked-client
Modules: make unloading module more safe
-rw-r--r--src/module.c11
-rw-r--r--src/server.c2
2 files changed, 12 insertions, 1 deletions
diff --git a/src/module.c b/src/module.c
index cabb37e08..eb994a8e5 100644
--- a/src/module.c
+++ b/src/module.c
@@ -63,6 +63,7 @@ struct RedisModule {
int in_call; /* RM_Call() nesting level */
int in_hook; /* Hooks callback nesting level for this module (0 or 1). */
int options; /* Module options and capabilities. */
+ int blocked_clients; /* Count of RedisModuleBlockedClient in this module. */
RedisModuleInfoFunc info_cb; /* Callback for module to add INFO fields. */
};
typedef struct RedisModule RedisModule;
@@ -3961,6 +3962,7 @@ RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc
c->bpop.module_blocked_handle = zmalloc(sizeof(RedisModuleBlockedClient));
RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle;
+ ctx->module->blocked_clients++;
/* We need to handle the invalid operation of calling modules blocking
* commands from Lua or MULTI. We actually create an already aborted
@@ -4119,6 +4121,7 @@ void moduleHandleBlockedClients(void) {
/* Free 'bc' only after unblocking the client, since it is
* referenced in the client blocking context, and must be valid
* when calling unblockClient(). */
+ bc->module->blocked_clients--;
zfree(bc);
/* Lock again before to iterate the loop. */
@@ -6089,6 +6092,7 @@ int moduleLoad(const char *path, void **module_argv, int module_argc) {
/* Redis module loaded! Register it. */
dictAdd(modules,ctx.module->name,ctx.module);
+ ctx.module->blocked_clients = 0;
ctx.module->handle = handle;
serverLog(LL_NOTICE,"Module '%s' loaded from %s",ctx.module->name,path);
moduleFreeContext(&ctx);
@@ -6114,6 +6118,9 @@ int moduleUnload(sds name) {
} else if (listLength(module->usedby)) {
errno = EPERM;
return REDISMODULE_ERR;
+ } else if (module->blocked_clients) {
+ errno = EAGAIN;
+ return REDISMODULE_ERR;
}
/* Give module a chance to clean up. */
@@ -6279,6 +6286,10 @@ NULL
errmsg = "the module exports APIs used by other modules. "
"Please unload them first and try again";
break;
+ case EAGAIN:
+ errmsg = "the module has blocked clients. "
+ "Please wait them unblocked and try again";
+ break;
default:
errmsg = "operation not possible.";
break;
diff --git a/src/server.c b/src/server.c
index d16ff0a8e..77db810b2 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2104,7 +2104,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
/* Check if there are clients unblocked by modules that implement
* blocking commands. */
- moduleHandleBlockedClients();
+ if (moduleCount()) moduleHandleBlockedClients();
/* Try to process pending commands for clients that were just unblocked. */
if (listLength(server.unblocked_clients))