From ffb00fbcbeeb2b0f17e70fbce81928e1f7fd4b46 Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 7 Oct 2016 13:48:05 +0200 Subject: Modules: blocking commands WIP: API exported, a first example. --- src/module.c | 23 +++++++++++++++++++++-- src/modules/Makefile | 7 ++++++- src/redismodule.h | 11 +++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/module.c b/src/module.c index 9a939d2fc..0cba99872 100644 --- a/src/module.c +++ b/src/module.c @@ -3085,7 +3085,21 @@ void unblockClientFromModule(client *c) { bc->client = NULL; } -int RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms) { +/* Block a client in the context of a blocking command, returning an handle + * which will be used, later, in order to block the client with a call to + * RedisModule_UnblockClient(). The arguments specify callback functions + * and a timeout after which the client is unblocked. + * + * The callbacks are called in the following contexts: + * + * reply_callback: called after a successful RedisModule_UnblockClient() call + * in order to reply to the client and unblock it. + * reply_timeout: called when the timeout is reached in order to send an + * error to the client. + * free_privdata: called in order to free the privata data that is passed + * by RedisModule_UnblockClient() call. + */ +RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms) { client *c = ctx->client; c->bpop.module_blocked_handle = zmalloc(sizeof(RedisModuleBlockedClient)); RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; @@ -3099,7 +3113,7 @@ int RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, Redis c->bpop.timeout = timeout_ms; blockClient(c,BLOCKED_MODULE); - return REDISMODULE_OK; + return bc; } /* Unblock a client blocked by `RedisModule_BlockedClient`. This will trigger @@ -3513,4 +3527,9 @@ void moduleRegisterCoreAPI(void) { REGISTER_API(RetainString); REGISTER_API(StringCompare); REGISTER_API(GetContextFromIO); + REGISTER_API(BlockClient); + REGISTER_API(UnblockClient); + REGISTER_API(IsBlockedReplyRequest); + REGISTER_API(IsBlockedTimeoutRequest); + REGISTER_API(GetBlockedClientPrivateData); } diff --git a/src/modules/Makefile b/src/modules/Makefile index 1027b2e0e..066e65e9b 100644 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -13,7 +13,7 @@ endif .SUFFIXES: .c .so .xo .o -all: helloworld.so hellotype.so testmodule.so +all: helloworld.so hellotype.so helloblock.so testmodule.so .c.xo: $(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@ @@ -28,6 +28,11 @@ hellotype.xo: ../redismodule.h hellotype.so: hellotype.xo $(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LIBS) -lc +helloblock.xo: ../redismodule.h + +helloblock.so: helloblock.xo + $(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LIBS) -lpthread -lc + testmodule.xo: ../redismodule.h testmodule.so: testmodule.xo diff --git a/src/redismodule.h b/src/redismodule.h index 4743fa98c..e931ecd07 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -84,6 +84,7 @@ typedef struct RedisModuleCallReply RedisModuleCallReply; typedef struct RedisModuleIO RedisModuleIO; typedef struct RedisModuleType RedisModuleType; typedef struct RedisModuleDigest RedisModuleDigest; +typedef struct RedisModuleBlockedClient RedisModuleBlockedClient; typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc); @@ -194,6 +195,11 @@ int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, Re void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str); int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b); RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io); +RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); +int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata); +int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx); +int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx); +void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx); /* This is included inline inside each Redis module. */ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused)); @@ -295,6 +301,11 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(RetainString); REDISMODULE_GET_API(StringCompare); REDISMODULE_GET_API(GetContextFromIO); + REDISMODULE_GET_API(BlockClient); + REDISMODULE_GET_API(UnblockClient); + REDISMODULE_GET_API(IsBlockedReplyRequest); + REDISMODULE_GET_API(IsBlockedTimeoutRequest); + REDISMODULE_GET_API(GetBlockedClientPrivateData); RedisModule_SetModuleAttribs(ctx,name,ver,apiver); return REDISMODULE_OK; -- cgit v1.2.1