Minor improvements to module blocked on keys (#7903)

- Clarify some documentation comments
- Make sure blocked-on-keys client privdata is accessible
  from withing the timeout callback
- Handle blocked clients in beforeSleep - In case a key
  becomes "ready" outside of processCommand

See #7879 #7880
This commit is contained in:
guybe7 2020-10-12 16:13:38 +02:00 committed by GitHub
parent 8b497881f2
commit addf47dcac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 15 additions and 9 deletions

View File

@ -507,7 +507,7 @@ void handleClientsBlockedOnKeys(void) {
server.fixed_time_expire++; server.fixed_time_expire++;
updateCachedTime(0); updateCachedTime(0);
/* Serve clients blocked on list key. */ /* Serve clients blocked on the key. */
robj *o = lookupKeyWrite(rl->db,rl->key); robj *o = lookupKeyWrite(rl->db,rl->key);
if (o != NULL) { if (o != NULL) {

View File

@ -4638,8 +4638,9 @@ RedisModuleBlockedClient *RM_BlockClientOnKeys(RedisModuleCtx *ctx, RedisModuleC
/* This function is used in order to potentially unblock a client blocked /* This function is used in order to potentially unblock a client blocked
* on keys with RedisModule_BlockClientOnKeys(). When this function is called, * on keys with RedisModule_BlockClientOnKeys(). When this function is called,
* all the clients blocked for this key will get their reply callback called, * all the clients blocked for this key will get their reply_callback called.
* and if the callback returns REDISMODULE_OK the client will be unblocked. */ *
* Note: The function has no effect if the signaled key doesn't exist. */
void RM_SignalKeyAsReady(RedisModuleCtx *ctx, RedisModuleString *key) { void RM_SignalKeyAsReady(RedisModuleCtx *ctx, RedisModuleString *key) {
signalKeyAsReady(ctx->client->db, key, OBJ_MODULE); signalKeyAsReady(ctx->client->db, key, OBJ_MODULE);
} }
@ -4683,14 +4684,13 @@ int moduleClientIsBlockedOnKeys(client *c) {
* *
* Note 1: this function can be called from threads spawned by the module. * Note 1: this function can be called from threads spawned by the module.
* *
* Note 2: when we unblock a client that is blocked for keys using * Note 2: when we unblock a client that is blocked for keys using the API
* the API RedisModule_BlockClientOnKeys(), the privdata argument here is * RedisModule_BlockClientOnKeys(), the privdata argument here is not used.
* not used, and the reply callback is called with the privdata pointer that
* was passed when blocking the client.
*
* Unblocking a client that was blocked for keys using this API will still * Unblocking a client that was blocked for keys using this API will still
* require the client to get some reply, so the function will use the * require the client to get some reply, so the function will use the
* "timeout" handler in order to do so. */ * "timeout" handler in order to do so (The privdata provided in
* RedisModule_BlockClientOnKeys() is accessible from the timeout
* callback via RM_GetBlockedClientPrivateData). */
int RM_UnblockClient(RedisModuleBlockedClient *bc, void *privdata) { int RM_UnblockClient(RedisModuleBlockedClient *bc, void *privdata) {
if (bc->blocked_on_keys) { if (bc->blocked_on_keys) {
/* In theory the user should always pass the timeout handler as an /* In theory the user should always pass the timeout handler as an
@ -4834,6 +4834,7 @@ void moduleBlockedClientTimedOut(client *c) {
ctx.module = bc->module; ctx.module = bc->module;
ctx.client = bc->client; ctx.client = bc->client;
ctx.blocked_client = bc; ctx.blocked_client = bc;
ctx.blocked_privdata = bc->privdata;
bc->timeout_callback(&ctx,(void**)c->argv,c->argc); bc->timeout_callback(&ctx,(void**)c->argv,c->argc);
moduleFreeContext(&ctx); moduleFreeContext(&ctx);
/* For timeout events, we do not want to call the disconnect callback, /* For timeout events, we do not want to call the disconnect callback,

View File

@ -2286,6 +2286,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
* releasing the GIL. Redis main thread will not touch anything at this * releasing the GIL. Redis main thread will not touch anything at this
* time. */ * time. */
if (moduleCount()) moduleReleaseGIL(); if (moduleCount()) moduleReleaseGIL();
/* Try to process blocked clients every once in while. Example: A module
* calls RM_SignalKeyAsReady from within a timer callback (So we don't
* visit processCommand() at all). */
handleClientsBlockedOnKeys();
} }
/* This function is called immediately after the event loop multiplexing /* This function is called immediately after the event loop multiplexing