Commit babe3c7b authored by zhaozhao.zz's avatar zhaozhao.zz Committed by Oran Agra
Browse files

Modules: rewrite config loadmodule option

parent 09e435c8
...@@ -315,7 +315,7 @@ void queueLoadModule(sds path, sds *argv, int argc) { ...@@ -315,7 +315,7 @@ void queueLoadModule(sds path, sds *argv, int argc) {
struct moduleLoadQueueEntry *loadmod; struct moduleLoadQueueEntry *loadmod;
loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry)); loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry));
loadmod->argv = zmalloc(sizeof(robj*)*argc); loadmod->argv = argc ? zmalloc(sizeof(robj*)*argc) : NULL;
loadmod->path = sdsnew(path); loadmod->path = sdsnew(path);
loadmod->argc = argc; loadmod->argc = argc;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
...@@ -1542,6 +1542,27 @@ void rewriteConfigBindOption(struct rewriteConfigState *state) { ...@@ -1542,6 +1542,27 @@ void rewriteConfigBindOption(struct rewriteConfigState *state) {
rewriteConfigRewriteLine(state,option,line,force); rewriteConfigRewriteLine(state,option,line,force);
} }
/* Rewrite the loadmodule option. */
void rewriteConfigLoadmoduleOption(struct rewriteConfigState *state) {
sds line;
dictIterator *di = dictGetIterator(modules);
dictEntry *de;
while ((de = dictNext(di)) != NULL) {
struct RedisModule *module = dictGetVal(de);
line = sdsnew("loadmodule ");
line = sdscatsds(line, module->loadmod->path);
for (int i = 0; i < module->loadmod->argc; i++) {
line = sdscatlen(line, " ", 1);
line = sdscatsds(line, module->loadmod->argv[i]->ptr);
}
rewriteConfigRewriteLine(state,"loadmodule",line,1);
}
dictReleaseIterator(di);
/* Mark "loadmodule" as processed in case modules is empty. */
rewriteConfigMarkAsProcessed(state,"loadmodule");
}
/* Glue together the configuration lines in the current configuration /* Glue together the configuration lines in the current configuration
* rewrite state into a single string, stripping multiple empty lines. */ * rewrite state into a single string, stripping multiple empty lines. */
sds rewriteConfigGetContentFromState(struct rewriteConfigState *state) { sds rewriteConfigGetContentFromState(struct rewriteConfigState *state) {
...@@ -1702,6 +1723,7 @@ int rewriteConfig(char *path, int force_all) { ...@@ -1702,6 +1723,7 @@ int rewriteConfig(char *path, int force_all) {
rewriteConfigNotifykeyspaceeventsOption(state); rewriteConfigNotifykeyspaceeventsOption(state);
rewriteConfigClientoutputbufferlimitOption(state); rewriteConfigClientoutputbufferlimitOption(state);
rewriteConfigOOMScoreAdjValuesOption(state); rewriteConfigOOMScoreAdjValuesOption(state);
rewriteConfigLoadmoduleOption(state);
/* Rewrite Sentinel config if in Sentinel mode. */ /* Rewrite Sentinel config if in Sentinel mode. */
if (server.sentinel_mode) rewriteConfigSentinelOption(state); if (server.sentinel_mode) rewriteConfigSentinelOption(state);
......
...@@ -75,28 +75,6 @@ typedef struct RedisModuleInfoCtx { ...@@ -75,28 +75,6 @@ typedef struct RedisModuleInfoCtx {
int in_dict_field; /* indication that we're currently appending to a dict */ int in_dict_field; /* indication that we're currently appending to a dict */
} RedisModuleInfoCtx; } RedisModuleInfoCtx;
typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleDefragFunc)(struct RedisModuleDefragCtx *ctx);
/* This structure represents a module inside the system. */
struct RedisModule {
void *handle; /* Module dlopen() handle. */
char *name; /* Module name. */
int ver; /* Module version. We use just progressive integers. */
int apiver; /* Module API version as requested during initialization.*/
list *types; /* Module data types. */
list *usedby; /* List of modules using APIs from this one. */
list *using; /* List of modules we use some APIs of. */
list *filters; /* List of filters the module has registered. */
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. */
RedisModuleDefragFunc defrag_cb; /* Callback for global data defrag. */
};
typedef struct RedisModule RedisModule;
/* This represents a shared API. Shared APIs will be used to populate /* This represents a shared API. Shared APIs will be used to populate
* the server.sharedapi dictionary, mapping names of APIs exported by * the server.sharedapi dictionary, mapping names of APIs exported by
* modules for other modules to use, to their structure specifying the * modules for other modules to use, to their structure specifying the
...@@ -107,7 +85,7 @@ struct RedisModuleSharedAPI { ...@@ -107,7 +85,7 @@ struct RedisModuleSharedAPI {
}; };
typedef struct RedisModuleSharedAPI RedisModuleSharedAPI; typedef struct RedisModuleSharedAPI RedisModuleSharedAPI;
static dict *modules; /* Hash table of modules. SDS -> RedisModule ptr.*/ dict *modules; /* Hash table of modules. SDS -> RedisModule ptr.*/
/* Entries in the context->amqueue array, representing objects to free /* Entries in the context->amqueue array, representing objects to free
* when the callback returns. */ * when the callback returns. */
...@@ -950,7 +928,7 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api ...@@ -950,7 +928,7 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
if (ctx->module != NULL) return; if (ctx->module != NULL) return;
module = zmalloc(sizeof(*module)); module = zmalloc(sizeof(*module));
module->name = sdsnew((char*)name); module->name = sdsnew(name);
module->ver = ver; module->ver = ver;
module->apiver = apiver; module->apiver = apiver;
module->types = listCreate(); module->types = listCreate();
...@@ -962,6 +940,7 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api ...@@ -962,6 +940,7 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
module->options = 0; module->options = 0;
module->info_cb = 0; module->info_cb = 0;
module->defrag_cb = 0; module->defrag_cb = 0;
module->loadmod = NULL;
ctx->module = module; ctx->module = module;
} }
...@@ -8467,6 +8446,16 @@ void moduleInitModulesSystem(void) { ...@@ -8467,6 +8446,16 @@ void moduleInitModulesSystem(void) {
pthread_mutex_lock(&moduleGIL); pthread_mutex_lock(&moduleGIL);
} }
void moduleLoadQueueEntryFree(struct moduleLoadQueueEntry *loadmod) {
if (!loadmod) return;
sdsfree(loadmod->path);
for (int i = 0; i < loadmod->argc; i++) {
decrRefCount(loadmod->argv[i]);
}
zfree(loadmod->argv);
zfree(loadmod);
}
/* Load all the modules in the server.loadmodule_queue list, which is /* Load all the modules in the server.loadmodule_queue list, which is
* populated by `loadmodule` directives in the configuration file. * populated by `loadmodule` directives in the configuration file.
* We can't load modules directly when processing the configuration file * We can't load modules directly when processing the configuration file
...@@ -8491,12 +8480,7 @@ void moduleLoadFromQueue(void) { ...@@ -8491,12 +8480,7 @@ void moduleLoadFromQueue(void) {
loadmod->path); loadmod->path);
exit(1); exit(1);
} }
sdsfree(loadmod->path); moduleLoadQueueEntryFree(loadmod);
for (int i = 0; i < loadmod->argc; i++) {
decrRefCount(loadmod->argv[i]);
}
zfree(loadmod->argv);
zfree(loadmod);
listDelNode(server.loadmodule_queue, ln); listDelNode(server.loadmodule_queue, ln);
} }
} }
...@@ -8507,6 +8491,7 @@ void moduleFreeModuleStructure(struct RedisModule *module) { ...@@ -8507,6 +8491,7 @@ void moduleFreeModuleStructure(struct RedisModule *module) {
listRelease(module->usedby); listRelease(module->usedby);
listRelease(module->using); listRelease(module->using);
sdsfree(module->name); sdsfree(module->name);
moduleLoadQueueEntryFree(module->loadmod);
zfree(module); zfree(module);
} }
...@@ -8580,6 +8565,15 @@ int moduleLoad(const char *path, void **module_argv, int module_argc) { ...@@ -8580,6 +8565,15 @@ int moduleLoad(const char *path, void **module_argv, int module_argc) {
dictAdd(modules,ctx.module->name,ctx.module); dictAdd(modules,ctx.module->name,ctx.module);
ctx.module->blocked_clients = 0; ctx.module->blocked_clients = 0;
ctx.module->handle = handle; ctx.module->handle = handle;
ctx.module->loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry));
ctx.module->loadmod->path = sdsnew(path);
ctx.module->loadmod->argv = module_argc ? zmalloc(sizeof(robj*)*module_argc) : NULL;
ctx.module->loadmod->argc = module_argc;
for (int i = 0; i < module_argc; i++) {
ctx.module->loadmod->argv[i] = module_argv[i];
incrRefCount(ctx.module->loadmod->argv[i]);
}
serverLog(LL_NOTICE,"Module '%s' loaded from %s",ctx.module->name,path); serverLog(LL_NOTICE,"Module '%s' loaded from %s",ctx.module->name,path);
/* Fire the loaded modules event. */ /* Fire the loaded modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_MODULE_CHANGE, moduleFireServerEvent(REDISMODULE_EVENT_MODULE_CHANGE,
......
...@@ -538,8 +538,10 @@ struct RedisModule; ...@@ -538,8 +538,10 @@ struct RedisModule;
struct RedisModuleIO; struct RedisModuleIO;
struct RedisModuleDigest; struct RedisModuleDigest;
struct RedisModuleCtx; struct RedisModuleCtx;
struct moduleLoadQueueEntry;
struct redisObject; struct redisObject;
struct RedisModuleDefragCtx; struct RedisModuleDefragCtx;
struct RedisModuleInfoCtx;
/* Each module type implementation should export a set of methods in order /* Each module type implementation should export a set of methods in order
* to serialize and deserialize the value in the RDB file, rewrite the AOF * to serialize and deserialize the value in the RDB file, rewrite the AOF
...@@ -557,6 +559,8 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void * ...@@ -557,6 +559,8 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void *
typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value); typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value);
typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value); typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value);
typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value); typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value);
typedef void (*RedisModuleInfoFunc)(struct RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleDefragFunc)(struct RedisModuleDefragCtx *ctx);
/* This callback type is called by moduleNotifyUserChanged() every time /* This callback type is called by moduleNotifyUserChanged() every time
* a user authenticated via the module API is associated with a different * a user authenticated via the module API is associated with a different
...@@ -606,6 +610,26 @@ typedef struct moduleValue { ...@@ -606,6 +610,26 @@ typedef struct moduleValue {
void *value; void *value;
} moduleValue; } moduleValue;
/* This structure represents a module inside the system. */
struct RedisModule {
void *handle; /* Module dlopen() handle. */
char *name; /* Module name. */
int ver; /* Module version. We use just progressive integers. */
int apiver; /* Module API version as requested during initialization.*/
list *types; /* Module data types. */
list *usedby; /* List of modules using APIs from this one. */
list *using; /* List of modules we use some APIs of. */
list *filters; /* List of filters the module has registered. */
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. */
RedisModuleDefragFunc defrag_cb; /* Callback for global data defrag. */
struct moduleLoadQueueEntry *loadmod; /* Module load arguments for config rewrite. */
};
typedef struct RedisModule RedisModule;
/* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that /* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that
* the user does not have to take the total count of the written bytes nor * the user does not have to take the total count of the written bytes nor
* to care about error conditions. */ * to care about error conditions. */
...@@ -1746,6 +1770,7 @@ extern dictType replScriptCacheDictType; ...@@ -1746,6 +1770,7 @@ extern dictType replScriptCacheDictType;
extern dictType dbExpiresDictType; extern dictType dbExpiresDictType;
extern dictType modulesDictType; extern dictType modulesDictType;
extern dictType sdsReplyDictType; extern dictType sdsReplyDictType;
extern dict *modules;
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* Functions prototypes * Functions prototypes
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment