Module: Ability to get context from IO context.

It was noted by @dvirsky that it is not possible to use string functions
when writing the AOF file. This sometimes is critical since the command
rewriting may need to be built in the context of the AOF callback, and
without access to the context, and the limited types that the AOF
production functions will accept, this can be an issue.

Moreover there are other needs that we can't anticipate regarding the
ability to use Redis Modules APIs using the context in order to build
representations to emit AOF / RDB.

Because of this a new API was added that allows the user to get a
temporary context from the IO context. The context is auto released
if obtained when the RDB / AOF callback returns.

Calling multiple time the function to get the context, always returns
the same one, since it is invalid to have more than a single context.
This commit is contained in:
antirez 2016-10-06 17:05:38 +02:00
parent 72279e3ea4
commit 152c1b6802
5 changed files with 30 additions and 0 deletions

View File

@ -1023,6 +1023,10 @@ int rewriteModuleObject(rio *r, robj *key, robj *o) {
moduleType *mt = mv->type; moduleType *mt = mv->type;
moduleInitIOContext(io,mt,r); moduleInitIOContext(io,mt,r);
mt->aof_rewrite(&io,key,mv->value); mt->aof_rewrite(&io,key,mv->value);
if (io.ctx) {
moduleFreeContext(io.ctx);
zfree(io.ctx);
}
return io.error ? 0 : 1; return io.error ? 0 : 1;
} }

View File

@ -2958,6 +2958,20 @@ void RM_EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...) {
return; return;
} }
/* --------------------------------------------------------------------------
* IO context handling
* -------------------------------------------------------------------------- */
RedisModuleCtx *RM_GetContextFromIO(RedisModuleIO *io) {
if (io->ctx) return io->ctx; /* Can't have more than one... */
RedisModuleCtx ctxtemplate = REDISMODULE_CTX_INIT;
io->ctx = zmalloc(sizeof(*io));
*(io->ctx) = ctxtemplate;
io->ctx->module = io->type->module;
io->ctx->client = NULL;
return io->ctx;
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* Logging * Logging
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
@ -3342,4 +3356,5 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(StringAppendBuffer); REGISTER_API(StringAppendBuffer);
REGISTER_API(RetainString); REGISTER_API(RetainString);
REGISTER_API(StringCompare); REGISTER_API(StringCompare);
REGISTER_API(GetContextFromIO);
} }

View File

@ -770,6 +770,10 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
/* Then write the module-specific representation. */ /* Then write the module-specific representation. */
mt->rdb_save(&io,mv->value); mt->rdb_save(&io,mv->value);
if (io.ctx) {
moduleFreeContext(io.ctx);
zfree(io.ctx);
}
return io.error ? -1 : (ssize_t)io.bytes; return io.error ? -1 : (ssize_t)io.bytes;
} else { } else {
serverPanic("Unknown object type"); serverPanic("Unknown object type");

View File

@ -191,6 +191,7 @@ void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char
int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str); void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b); int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
RedisModuleCtx *REDISMODULE_API_FUNC(RM_GetContextFromIO)(RedisModuleIO *io);
/* This is included inline inside each Redis module. */ /* This is included inline inside each Redis module. */
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused)); static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
@ -291,6 +292,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(StringAppendBuffer); REDISMODULE_GET_API(StringAppendBuffer);
REDISMODULE_GET_API(RetainString); REDISMODULE_GET_API(RetainString);
REDISMODULE_GET_API(StringCompare); REDISMODULE_GET_API(StringCompare);
REDISMODULE_GET_API(GetIOContext);
REDISMODULE_GET_API(FreeIOContext);
RedisModule_SetModuleAttribs(ctx,name,ver,apiver); RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
return REDISMODULE_OK; return REDISMODULE_OK;

View File

@ -463,6 +463,7 @@ typedef long long mstime_t; /* millisecond time type. */
struct RedisModule; struct RedisModule;
struct RedisModuleIO; struct RedisModuleIO;
struct RedisModuleDigest; struct RedisModuleDigest;
struct RedisModuleCtx;
struct redisObject; struct redisObject;
/* Each module type implementation should export a set of methods in order /* Each module type implementation should export a set of methods in order
@ -516,6 +517,7 @@ typedef struct RedisModuleIO {
rio *rio; /* Rio stream. */ rio *rio; /* Rio stream. */
moduleType *type; /* Module type doing the operation. */ moduleType *type; /* Module type doing the operation. */
int error; /* True if error condition happened. */ int error; /* True if error condition happened. */
struct RedisModuleCtx *ctx; /* Optional context, via GetIOContext() call. */
} RedisModuleIO; } RedisModuleIO;
#define moduleInitIOContext(iovar,mtype,rioptr) do { \ #define moduleInitIOContext(iovar,mtype,rioptr) do { \
@ -523,6 +525,7 @@ typedef struct RedisModuleIO {
iovar.type = mtype; \ iovar.type = mtype; \
iovar.bytes = 0; \ iovar.bytes = 0; \
iovar.error = 0; \ iovar.error = 0; \
iovar.ctx = NULL; \
} while(0); } while(0);
/* Objects encoding. Some kind of objects like Strings and Hashes can be /* Objects encoding. Some kind of objects like Strings and Hashes can be
@ -1222,6 +1225,7 @@ void moduleLoadFromQueue(void);
int *moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); int *moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
moduleType *moduleTypeLookupModuleByID(uint64_t id); moduleType *moduleTypeLookupModuleByID(uint64_t id);
void moduleTypeNameByID(char *name, uint64_t moduleid); void moduleTypeNameByID(char *name, uint64_t moduleid);
void moduleFreeContext(struct RedisModuleCtx *ctx);
/* Utils */ /* Utils */
long long ustime(void); long long ustime(void);