Initial command filter experiment.

This commit is contained in:
Yossi Gottlieb
2018-02-23 16:19:37 +02:00
parent 8ea906a3e8
commit c3e187190b
6 changed files with 161 additions and 2 deletions

View File

@ -270,6 +270,28 @@ typedef struct RedisModuleDictIter {
raxIterator ri;
} RedisModuleDictIter;
/* Information about the command to be executed, as passed to and from a
* filter. */
typedef struct RedisModuleFilteredCommand {
RedisModuleString **argv;
int argc;
} RedisModuleFilteredCommand;
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCtx *ctx, RedisModuleFilteredCommand *cmd);
typedef struct RedisModuleCommandFilter {
/* The module that registered the filter */
RedisModule *module;
/* Filter callback function */
RedisModuleCommandFilterFunc callback;
/* Indicates a filter is active, avoid reentrancy */
int active;
} RedisModuleCommandFilter;
/* Registered filters */
static list *moduleCommandFilters;
/* --------------------------------------------------------------------------
* Prototypes
* -------------------------------------------------------------------------- */
@ -4770,6 +4792,56 @@ int moduleUnregisterUsedAPI(RedisModule *module) {
return count;
}
/* --------------------------------------------------------------------------
* Module Command Filter API
* -------------------------------------------------------------------------- */
/* Register a new command filter function. Filters get executed by Redis
* before processing an inbound command and can be used to manipulate the
* behavior of standard Redis commands. Filters must not attempt to
* perform Redis commands or operate on the dataset, and must restrict
* themselves to manipulation of the arguments.
*/
int RM_RegisterCommandFilter(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc callback) {
RedisModuleCommandFilter *filter = zmalloc(sizeof(*filter));
filter->module = ctx->module;
filter->callback = callback;
filter->active = 0;
listAddNodeTail(moduleCommandFilters, filter);
return REDISMODULE_OK;
}
void moduleCallCommandFilters(client *c) {
if (listLength(moduleCommandFilters) == 0) return;
listIter li;
listNode *ln;
listRewind(moduleCommandFilters,&li);
RedisModuleFilteredCommand cmd = {
.argv = c->argv,
.argc = c->argc
};
while((ln = listNext(&li))) {
RedisModuleCommandFilter *filter = ln->value;
if (filter->active) continue;
RedisModuleCtx ctx = REDISMODULE_CTX_INIT;
ctx.module = filter->module;
filter->active = 1;
filter->callback(&ctx, &cmd);
filter->active = 0;
moduleFreeContext(&ctx);
}
c->argv = cmd.argv;
c->argc = cmd.argc;
}
/* --------------------------------------------------------------------------
* Modules API internals
* -------------------------------------------------------------------------- */
@ -4816,6 +4888,9 @@ void moduleInitModulesSystem(void) {
moduleFreeContextReusedClient->flags |= CLIENT_MODULE;
moduleFreeContextReusedClient->user = NULL; /* root user. */
/* Set up filter list */
moduleCommandFilters = listCreate();
moduleRegisterCoreAPI();
if (pipe(server.module_blocked_pipe) == -1) {
serverLog(LL_WARNING,
@ -5219,4 +5294,5 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(DictCompare);
REGISTER_API(ExportSharedAPI);
REGISTER_API(GetSharedAPI);
REGISTER_API(RegisterCommandFilter);
}