Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
c3e18719
Commit
c3e18719
authored
Feb 23, 2018
by
Yossi Gottlieb
Browse files
Initial command filter experiment.
parent
8ea906a3
Changes
6
Show whitespace changes
Inline
Side-by-side
src/module.c
View file @
c3e18719
...
...
@@ -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);
}
src/modules/Makefile
View file @
c3e18719
...
...
@@ -13,7 +13,7 @@ endif
.SUFFIXES
:
.c .so .xo .o
all
:
helloworld.so hellotype.so helloblock.so testmodule.so hellocluster.so hellotimer.so hellodict.so
all
:
helloworld.so hellotype.so helloblock.so testmodule.so hellocluster.so hellotimer.so hellodict.so
hellofilter.so
.c.xo
:
$(CC)
-I
.
$(CFLAGS)
$(SHOBJ_CFLAGS)
-fPIC
-c
$<
-o
$@
...
...
@@ -46,6 +46,10 @@ hellotimer.so: hellotimer.xo
hellodict.xo
:
../redismodule.h
hellodict.so
:
hellodict.xo
hellofilter.xo
:
../redismodule.h
hellofilter.so
:
hellofilter.xo
$(LD)
-o
$@
$<
$(SHOBJ_LDFLAGS)
$(LIBS)
-lc
testmodule.xo
:
../redismodule.h
...
...
src/modules/hellofilter.c
0 → 100644
View file @
c3e18719
#define REDISMODULE_EXPERIMENTAL_API
#include "../redismodule.h"
static
RedisModuleString
*
log_key_name
;
static
const
char
log_command_name
[]
=
"hellofilter.log"
;
int
HelloFilter_LogCommand
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
RedisModuleString
*
s
=
RedisModule_CreateStringFromString
(
ctx
,
argv
[
0
]);
int
i
;
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
size_t
arglen
;
const
char
*
arg
=
RedisModule_StringPtrLen
(
argv
[
i
],
&
arglen
);
RedisModule_StringAppendBuffer
(
ctx
,
s
,
" "
,
1
);
RedisModule_StringAppendBuffer
(
ctx
,
s
,
arg
,
arglen
);
}
RedisModuleKey
*
log
=
RedisModule_OpenKey
(
ctx
,
log_key_name
,
REDISMODULE_WRITE
|
REDISMODULE_READ
);
RedisModule_ListPush
(
log
,
REDISMODULE_LIST_HEAD
,
s
);
RedisModule_CloseKey
(
log
);
RedisModule_FreeString
(
ctx
,
s
);
size_t
cmdlen
;
const
char
*
cmdname
=
RedisModule_StringPtrLen
(
argv
[
1
],
&
cmdlen
);
RedisModuleCallReply
*
reply
=
RedisModule_Call
(
ctx
,
cmdname
,
"v"
,
&
argv
[
2
],
argc
-
2
);
if
(
reply
)
{
RedisModule_ReplyWithCallReply
(
ctx
,
reply
);
RedisModule_FreeCallReply
(
reply
);
}
else
{
RedisModule_ReplyWithSimpleString
(
ctx
,
"Unknown command or invalid arguments"
);
}
return
REDISMODULE_OK
;
}
void
HelloFilter_CommandFilter
(
RedisModuleCtx
*
ctx
,
RedisModuleFilteredCommand
*
cmd
)
{
cmd
->
argv
=
RedisModule_Realloc
(
cmd
->
argv
,
(
cmd
->
argc
+
1
)
*
sizeof
(
RedisModuleString
*
));
int
i
;
for
(
i
=
cmd
->
argc
;
i
>
0
;
i
--
)
{
cmd
->
argv
[
i
]
=
cmd
->
argv
[
i
-
1
];
}
cmd
->
argv
[
0
]
=
RedisModule_CreateString
(
ctx
,
log_command_name
,
sizeof
(
log_command_name
)
-
1
);
cmd
->
argc
++
;
}
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
if
(
RedisModule_Init
(
ctx
,
"hellofilter"
,
1
,
REDISMODULE_APIVER_1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
argc
!=
1
)
{
RedisModule_Log
(
ctx
,
"warning"
,
"Log key name not specified"
);
return
REDISMODULE_ERR
;
}
log_key_name
=
RedisModule_CreateStringFromString
(
ctx
,
argv
[
0
]);
if
(
RedisModule_CreateCommand
(
ctx
,
log_command_name
,
HelloFilter_LogCommand
,
"write deny-oom"
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_RegisterCommandFilter
(
ctx
,
HelloFilter_CommandFilter
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
}
src/redismodule.h
View file @
c3e18719
...
...
@@ -163,6 +163,12 @@ typedef void (*RedisModuleTypeFreeFunc)(void *value);
typedef
void
(
*
RedisModuleClusterMessageReceiver
)(
RedisModuleCtx
*
ctx
,
const
char
*
sender_id
,
uint8_t
type
,
const
unsigned
char
*
payload
,
uint32_t
len
);
typedef
void
(
*
RedisModuleTimerProc
)(
RedisModuleCtx
*
ctx
,
void
*
data
);
typedef
struct
RedisModuleFilteredCommand
{
RedisModuleString
**
argv
;
int
argc
;
}
RedisModuleFilteredCommand
;
typedef
void
(
*
RedisModuleCommandFilterFunc
)
(
RedisModuleCtx
*
ctx
,
RedisModuleFilteredCommand
*
cmd
);
#define REDISMODULE_TYPE_METHOD_VERSION 1
typedef
struct
RedisModuleTypeMethods
{
uint64_t
version
;
...
...
@@ -337,6 +343,7 @@ void REDISMODULE_API_FUNC(RedisModule_SetDisconnectCallback)(RedisModuleBlockedC
void
REDISMODULE_API_FUNC
(
RedisModule_SetClusterFlags
)(
RedisModuleCtx
*
ctx
,
uint64_t
flags
);
int
REDISMODULE_API_FUNC
(
RedisModule_ExportSharedAPI
)(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
,
void
*
func
);
void
*
REDISMODULE_API_FUNC
(
RedisModule_GetSharedAPI
)(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
);
int
REDISMODULE_API_FUNC
(
RedisModule_RegisterCommandFilter
)(
RedisModuleCtx
*
ctx
,
RedisModuleCommandFilterFunc
cb
);
#endif
/* This is included inline inside each Redis module. */
...
...
@@ -499,6 +506,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
SetClusterFlags
);
REDISMODULE_GET_API
(
ExportSharedAPI
);
REDISMODULE_GET_API
(
GetSharedAPI
);
REDISMODULE_GET_API
(
RegisterCommandFilter
);
#endif
if
(
RedisModule_IsModuleNameBusy
&&
RedisModule_IsModuleNameBusy
(
name
))
return
REDISMODULE_ERR
;
...
...
src/server.c
View file @
c3e18719
...
...
@@ -3268,6 +3268,8 @@ void call(client *c, int flags) {
* other operations can be performed by the caller. Otherwise
* if C_ERR is returned the client was destroyed (i.e. after QUIT). */
int processCommand(client *c) {
moduleCallCommandFilters(c);
/* The QUIT command is handled separately. Normal command procs will
* go through checking for replication and QUIT will cause trouble
* when FORCE_REPLICATION is enabled and would be implemented in
...
...
src/server.h
View file @
c3e18719
...
...
@@ -1489,7 +1489,7 @@ size_t moduleCount(void);
void
moduleAcquireGIL
(
void
);
void
moduleReleaseGIL
(
void
);
void
moduleNotifyKeyspaceEvent
(
int
type
,
const
char
*
event
,
robj
*
key
,
int
dbid
);
void
moduleCallCommandFilters
(
client
*
c
);
/* Utils */
long
long
ustime
(
void
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment