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
ab37289f
Commit
ab37289f
authored
Dec 09, 2018
by
MeirShpilraien
Committed by
antirez
Dec 20, 2018
Browse files
added module ability to register api to be used by other modules
parent
009a9292
Changes
3
Show whitespace changes
Inline
Side-by-side
src/module.c
View file @
ab37289f
...
@@ -47,7 +47,16 @@ struct RedisModule {
...
@@ -47,7 +47,16 @@ struct RedisModule {
int
ver
;
/* Module version. We use just progressive integers. */
int
ver
;
/* Module version. We use just progressive integers. */
int
apiver
;
/* Module API version as requested during initialization.*/
int
apiver
;
/* Module API version as requested during initialization.*/
list
*
types
;
/* Module data types. */
list
*
types
;
/* Module data types. */
list
*
usedBy
;
/* list of modules names using this module api. */
list
*
using
;
/* list of modules names that this module is using thier api . */
list
*
exportedFunctions
;
/* list of function names exported by this module. */
};
};
struct
ModuleExportedApi
{
void
*
funcPointer
;
struct
RedisModule
*
module
;
};
typedef
struct
RedisModule
RedisModule
;
typedef
struct
RedisModule
RedisModule
;
static
dict
*
modules
;
/* Hash table of modules. SDS -> RedisModule ptr.*/
static
dict
*
modules
;
/* Hash table of modules. SDS -> RedisModule ptr.*/
...
@@ -700,6 +709,9 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
...
@@ -700,6 +709,9 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
module
->
ver
=
ver
;
module
->
ver
=
ver
;
module
->
apiver
=
apiver
;
module
->
apiver
=
apiver
;
module
->
types
=
listCreate
();
module
->
types
=
listCreate
();
module
->
usedBy
=
listCreate
();
module
->
using
=
listCreate
();
module
->
exportedFunctions
=
listCreate
();
ctx
->
module
=
module
;
ctx
->
module
=
module
;
}
}
...
@@ -4615,6 +4627,59 @@ void RM_GetRandomHexChars(char *dst, size_t len) {
...
@@ -4615,6 +4627,59 @@ void RM_GetRandomHexChars(char *dst, size_t len) {
getRandomHexChars
(
dst
,
len
);
getRandomHexChars
(
dst
,
len
);
}
}
/* Used to register an api to be used by other modules. */
int
RM_RegisterApi
(
RedisModuleCtx
*
ctx
,
const
char
*
funcname
,
void
*
funcptr
)
{
struct
ModuleExportedApi
*
eapi
=
zmalloc
(
sizeof
(
*
eapi
));
eapi
->
module
=
ctx
->
module
;
eapi
->
funcPointer
=
funcptr
;
if
(
dictAdd
(
server
.
exportedapi
,
(
char
*
)
funcname
,
eapi
)
!=
DICT_OK
){
zfree
(
eapi
);
return
REDISMODULE_ERR
;
}
listAddNodeHead
(
ctx
->
module
->
exportedFunctions
,
(
char
*
)
funcname
);
return
REDISMODULE_OK
;
}
static
inline
int
IsModuleInList
(
list
*
l
,
const
char
*
moduleName
){
listIter
*
iter
=
listGetIterator
(
l
,
AL_START_HEAD
);
listNode
*
node
=
NULL
;
while
((
node
=
listNext
(
iter
))){
char
*
name
=
listNodeValue
(
node
);
if
(
strcmp
(
name
,
moduleName
)
==
0
){
listReleaseIterator
(
iter
);
return
1
;
}
}
listReleaseIterator
(
iter
);
return
0
;
}
static
inline
void
RemoveFromList
(
list
*
l
,
const
char
*
moduleName
){
listIter
*
iter
=
listGetIterator
(
l
,
AL_START_HEAD
);
listNode
*
node
=
NULL
;
while
((
node
=
listNext
(
iter
))){
char
*
name
=
listNodeValue
(
node
);
if
(
strcmp
(
name
,
moduleName
)
==
0
){
listDelNode
(
l
,
node
);
return
;
}
}
listReleaseIterator
(
iter
);
}
void
*
RM_GetExportedApi
(
RedisModuleCtx
*
ctx
,
const
char
*
funcname
)
{
dictEntry
*
entry
=
dictFind
(
server
.
exportedapi
,
funcname
);
if
(
!
entry
){
return
NULL
;
}
struct
ModuleExportedApi
*
eapi
=
dictGetVal
(
entry
);
if
(
!
IsModuleInList
(
eapi
->
module
->
usedBy
,
ctx
->
module
->
name
)){
listAddNodeHead
(
eapi
->
module
->
usedBy
,
ctx
->
module
->
name
);
listAddNodeHead
(
ctx
->
module
->
using
,
eapi
->
module
->
name
);
}
return
eapi
->
funcPointer
;
}
/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
* Modules API internals
* Modules API internals
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
...
@@ -4735,6 +4800,28 @@ void moduleUnregisterCommands(struct RedisModule *module) {
...
@@ -4735,6 +4800,28 @@ void moduleUnregisterCommands(struct RedisModule *module) {
dictReleaseIterator
(
di
);
dictReleaseIterator
(
di
);
}
}
void
moduleUnregisterApi
(
struct
RedisModule
*
module
)
{
listIter
*
iter
=
listGetIterator
(
module
->
exportedFunctions
,
AL_START_HEAD
);
listNode
*
node
=
NULL
;
while
((
node
=
listNext
(
iter
))){
char
*
functionName
=
listNodeValue
(
node
);
struct
ModuleExportedApi
*
eapi
=
dictFetchValue
(
server
.
exportedapi
,
functionName
);
serverAssert
(
eapi
);
zfree
(
eapi
);
dictDelete
(
server
.
exportedapi
,
functionName
);
}
listReleaseIterator
(
iter
);
iter
=
listGetIterator
(
module
->
using
,
AL_START_HEAD
);
node
=
NULL
;
while
((
node
=
listNext
(
iter
))){
char
*
moduleName
=
listNodeValue
(
node
);
struct
RedisModule
*
usingModule
=
dictFetchValue
(
modules
,
moduleName
);
serverAssert
(
usingModule
);
RemoveFromList
(
usingModule
->
usedBy
,
module
->
name
);
}
listReleaseIterator
(
iter
);
}
/* Load a module and initialize it. On success C_OK is returned, otherwise
/* Load a module and initialize it. On success C_OK is returned, otherwise
* C_ERR is returned. */
* C_ERR is returned. */
int
moduleLoad
(
const
char
*
path
,
void
**
module_argv
,
int
module_argc
)
{
int
moduleLoad
(
const
char
*
path
,
void
**
module_argv
,
int
module_argc
)
{
...
@@ -4794,6 +4881,12 @@ int moduleUnload(sds name) {
...
@@ -4794,6 +4881,12 @@ int moduleUnload(sds name) {
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
}
}
if
(
listLength
(
module
->
usedBy
))
{
errno
=
EPERM
;
return
REDISMODULE_ERR
;
}
moduleUnregisterApi
(
module
);
moduleUnregisterCommands
(
module
);
moduleUnregisterCommands
(
module
);
/* Remove any notification subscribers this module might have */
/* Remove any notification subscribers this module might have */
...
@@ -4826,6 +4919,7 @@ void moduleCommand(client *c) {
...
@@ -4826,6 +4919,7 @@ void moduleCommand(client *c) {
if
(
c
->
argc
==
2
&&
!
strcasecmp
(
subcmd
,
"help"
))
{
if
(
c
->
argc
==
2
&&
!
strcasecmp
(
subcmd
,
"help"
))
{
const
char
*
help
[]
=
{
const
char
*
help
[]
=
{
"LIST -- Return a list of loaded modules."
,
"LIST -- Return a list of loaded modules."
,
"LISTAPI <module-name> -- Return a list of exported api."
,
"LOAD <path> [arg ...] -- Load a module library from <path>."
,
"LOAD <path> [arg ...] -- Load a module library from <path>."
,
"UNLOAD <name> -- Unload a module."
,
"UNLOAD <name> -- Unload a module."
,
NULL
NULL
...
@@ -4858,6 +4952,9 @@ NULL
...
@@ -4858,6 +4952,9 @@ NULL
case
EBUSY
:
case
EBUSY
:
errmsg
=
"the module exports one or more module-side data types, can't unload"
;
errmsg
=
"the module exports one or more module-side data types, can't unload"
;
break
;
break
;
case
EPERM
:
errmsg
=
"the module api is used by other modules, please unload them first and try again."
;
break
;
default:
default:
errmsg
=
"operation not possible."
;
errmsg
=
"operation not possible."
;
break
;
break
;
...
@@ -4879,6 +4976,21 @@ NULL
...
@@ -4879,6 +4976,21 @@ NULL
addReplyLongLong
(
c
,
module
->
ver
);
addReplyLongLong
(
c
,
module
->
ver
);
}
}
dictReleaseIterator
(
di
);
dictReleaseIterator
(
di
);
}
else
if
(
!
strcasecmp
(
subcmd
,
"listapi"
)
&&
c
->
argc
==
3
)
{
char
*
moduleName
=
c
->
argv
[
2
]
->
ptr
;
struct
RedisModule
*
module
=
dictFetchValue
(
modules
,
moduleName
);
if
(
!
module
){
addReplyErrorFormat
(
c
,
"Error listing module api: no such module %s"
,
moduleName
);
return
;
}
addReplyMultiBulkLen
(
c
,
listLength
(
module
->
exportedFunctions
));
listIter
*
iter
=
listGetIterator
(
module
->
exportedFunctions
,
AL_START_HEAD
);
listNode
*
node
=
NULL
;
while
((
node
=
listNext
(
iter
))){
char
*
functionName
=
listNodeValue
(
node
);
addReplyBulkCString
(
c
,
functionName
);
}
listReleaseIterator
(
iter
);
}
else
{
}
else
{
addReplySubcommandSyntaxError
(
c
);
addReplySubcommandSyntaxError
(
c
);
return
;
return
;
...
@@ -4894,6 +5006,7 @@ size_t moduleCount(void) {
...
@@ -4894,6 +5006,7 @@ size_t moduleCount(void) {
* file so that's easy to seek it to add new entries. */
* file so that's easy to seek it to add new entries. */
void
moduleRegisterCoreAPI
(
void
)
{
void
moduleRegisterCoreAPI
(
void
)
{
server
.
moduleapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
server
.
moduleapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
server
.
exportedapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Realloc
);
REGISTER_API
(
Realloc
);
...
@@ -5044,4 +5157,6 @@ void moduleRegisterCoreAPI(void) {
...
@@ -5044,4 +5157,6 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
DictPrev
);
REGISTER_API
(
DictPrev
);
REGISTER_API
(
DictCompareC
);
REGISTER_API
(
DictCompareC
);
REGISTER_API
(
DictCompare
);
REGISTER_API
(
DictCompare
);
REGISTER_API
(
RegisterApi
);
REGISTER_API
(
GetExportedApi
);
}
}
src/redismodule.h
View file @
ab37289f
...
@@ -332,6 +332,8 @@ void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t
...
@@ -332,6 +332,8 @@ void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t
void
REDISMODULE_API_FUNC
(
RedisModule_GetRandomHexChars
)(
char
*
dst
,
size_t
len
);
void
REDISMODULE_API_FUNC
(
RedisModule_GetRandomHexChars
)(
char
*
dst
,
size_t
len
);
void
REDISMODULE_API_FUNC
(
RedisModule_SetDisconnectCallback
)(
RedisModuleBlockedClient
*
bc
,
RedisModuleDisconnectFunc
callback
);
void
REDISMODULE_API_FUNC
(
RedisModule_SetDisconnectCallback
)(
RedisModuleBlockedClient
*
bc
,
RedisModuleDisconnectFunc
callback
);
void
REDISMODULE_API_FUNC
(
RedisModule_SetClusterFlags
)(
RedisModuleCtx
*
ctx
,
uint64_t
flags
);
void
REDISMODULE_API_FUNC
(
RedisModule_SetClusterFlags
)(
RedisModuleCtx
*
ctx
,
uint64_t
flags
);
int
REDISMODULE_API_FUNC
(
RedisModule_RegisterApi
)(
RedisModuleCtx
*
ctx
,
const
char
*
funcname
,
void
*
funcptr
);
void
*
REDISMODULE_API_FUNC
(
RedisModule_GetExportedApi
)(
RedisModuleCtx
*
ctx
,
const
char
*
funcname
);
#endif
#endif
/* This is included inline inside each Redis module. */
/* This is included inline inside each Redis module. */
...
@@ -492,6 +494,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
...
@@ -492,6 +494,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
GetRandomBytes
);
REDISMODULE_GET_API
(
GetRandomBytes
);
REDISMODULE_GET_API
(
GetRandomHexChars
);
REDISMODULE_GET_API
(
GetRandomHexChars
);
REDISMODULE_GET_API
(
SetClusterFlags
);
REDISMODULE_GET_API
(
SetClusterFlags
);
REDISMODULE_GET_API
(
RegisterApi
);
REDISMODULE_GET_API
(
GetExportedApi
);
#endif
#endif
if
(
RedisModule_IsModuleNameBusy
&&
RedisModule_IsModuleNameBusy
(
name
))
return
REDISMODULE_ERR
;
if
(
RedisModule_IsModuleNameBusy
&&
RedisModule_IsModuleNameBusy
(
name
))
return
REDISMODULE_ERR
;
...
...
src/server.h
View file @
ab37289f
...
@@ -955,6 +955,7 @@ struct redisServer {
...
@@ -955,6 +955,7 @@ struct redisServer {
int
always_show_logo
;
/* Show logo even for non-stdout logging. */
int
always_show_logo
;
/* Show logo even for non-stdout logging. */
/* Modules */
/* Modules */
dict
*
moduleapi
;
/* Exported APIs dictionary for modules. */
dict
*
moduleapi
;
/* Exported APIs dictionary for modules. */
dict
*
exportedapi
;
/* Api exported by other modules. */
list
*
loadmodule_queue
;
/* List of modules to load at startup. */
list
*
loadmodule_queue
;
/* List of modules to load at startup. */
int
module_blocked_pipe
[
2
];
/* Pipe used to awake the event loop if a
int
module_blocked_pipe
[
2
];
/* Pipe used to awake the event loop if a
client blocked on a module command needs
client blocked on a module command needs
...
...
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