Merge pull request #4994 from soloestoy/module-blocked-client
Modules: make unloading module more safe
This commit is contained in:
commit
24fdc87fe0
11
src/module.c
11
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;
|
||||
|
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user