Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
6fd4af1f
Commit
6fd4af1f
authored
Mar 14, 2019
by
antirez
Browse files
Merge branch 'sharedapi' into unstable
parents
2537b214
8a87de13
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
6fd4af1f
...
@@ -47,9 +47,21 @@ struct RedisModule {
...
@@ -47,9 +47,21 @@ 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 using APIs from this one. */
list
*
using
;
/* List of modules we use some APIs of. */
};
};
typedef
struct
RedisModule
RedisModule
;
typedef
struct
RedisModule
RedisModule
;
/* This represents a shared API. Shared APIs will be used to populate
* the server.sharedapi dictionary, mapping names of APIs exported by
* modules for other modules to use, to their structure specifying the
* function pointer that can be called. */
struct
RedisModuleSharedAPI
{
void
*
func
;
RedisModule
*
module
;
};
typedef
struct
RedisModuleSharedAPI
RedisModuleSharedAPI
;
static
dict
*
modules
;
/* Hash table of modules. SDS -> RedisModule ptr.*/
static
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
...
@@ -701,6 +713,8 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
...
@@ -701,6 +713,8 @@ 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
();
ctx
->
module
=
module
;
ctx
->
module
=
module
;
}
}
...
@@ -4623,6 +4637,121 @@ void RM_GetRandomHexChars(char *dst, size_t len) {
...
@@ -4623,6 +4637,121 @@ void RM_GetRandomHexChars(char *dst, size_t len) {
getRandomHexChars
(
dst
,
len
);
getRandomHexChars
(
dst
,
len
);
}
}
/* --------------------------------------------------------------------------
* Modules API exporting / importing
* -------------------------------------------------------------------------- */
/* This function is called by a module in order to export some API with a
* given name. Other modules will be able to use this API by calling the
* symmetrical function RM_GetSharedAPI() and casting the return value to
* the right function pointer.
*
* The function will return REDISMODULE_OK if the name is not already taken,
* otherwise REDISMODULE_ERR will be returned and no operation will be
* performed.
*
* IMPORTANT: the apiname argument should be a string literal with static
* lifetime. The API relies on the fact that it will always be valid in
* the future. */
int
RM_ExportSharedAPI
(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
,
void
*
func
)
{
RedisModuleSharedAPI
*
sapi
=
zmalloc
(
sizeof
(
*
sapi
));
sapi
->
module
=
ctx
->
module
;
sapi
->
func
=
func
;
if
(
dictAdd
(
server
.
sharedapi
,
(
char
*
)
apiname
,
sapi
)
!=
DICT_OK
)
{
zfree
(
sapi
);
return
REDISMODULE_ERR
;
}
return
REDISMODULE_OK
;
}
/* Request an exported API pointer. The return value is just a void pointer
* that the caller of this function will be required to cast to the right
* function pointer, so this is a private contract between modules.
*
* If the requested API is not available then NULL is returned. Because
* modules can be loaded at different times with different order, this
* function calls should be put inside some module generic API registering
* step, that is called every time a module attempts to execute a
* command that requires external APIs: if some API cannot be resolved, the
* command should return an error.
*
* Here is an exmaple:
*
* int ... myCommandImplementation() {
* if (getExternalAPIs() == 0) {
* reply with an error here if we cannot have the APIs
* }
* // Use the API:
* myFunctionPointer(foo);
* }
*
* And the function registerAPI() is:
*
* int getExternalAPIs(void) {
* static int api_loaded = 0;
* if (api_loaded != 0) return 1; // APIs already resolved.
*
* myFunctionPointer = RedisModule_GetOtherModuleAPI("...");
* if (myFunctionPointer == NULL) return 0;
*
* return 1;
* }
*/
void
*
RM_GetSharedAPI
(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
)
{
dictEntry
*
de
=
dictFind
(
server
.
sharedapi
,
apiname
);
if
(
de
==
NULL
)
return
NULL
;
RedisModuleSharedAPI
*
sapi
=
dictGetVal
(
de
);
if
(
listSearchKey
(
sapi
->
module
->
usedby
,
ctx
->
module
)
==
NULL
)
{
listAddNodeTail
(
sapi
->
module
->
usedby
,
ctx
->
module
);
listAddNodeTail
(
ctx
->
module
->
using
,
sapi
->
module
);
}
return
sapi
->
func
;
}
/* Remove all the APIs registered by the specified module. Usually you
* want this when the module is going to be unloaded. This function
* assumes that's caller responsibility to make sure the APIs are not
* used by other modules.
*
* The number of unregistered APIs is returned. */
int
moduleUnregisterSharedAPI
(
RedisModule
*
module
)
{
int
count
=
0
;
dictIterator
*
di
=
dictGetSafeIterator
(
server
.
sharedapi
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
const
char
*
apiname
=
dictGetKey
(
de
);
RedisModuleSharedAPI
*
sapi
=
dictGetVal
(
de
);
if
(
sapi
->
module
==
module
)
{
dictDelete
(
server
.
sharedapi
,
apiname
);
zfree
(
sapi
);
count
++
;
}
}
dictReleaseIterator
(
di
);
return
count
;
}
/* Remove the specified module as an user of APIs of ever other module.
* This is usually called when a module is unloaded.
*
* Returns the number of modules this module was using APIs from. */
int
moduleUnregisterUsedAPI
(
RedisModule
*
module
)
{
listIter
li
;
listNode
*
ln
;
int
count
=
0
;
listRewind
(
module
->
using
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
RedisModule
*
used
=
ln
->
value
;
listNode
*
ln
=
listSearchKey
(
used
->
usedby
,
module
);
if
(
ln
)
{
listDelNode
(
module
->
using
,
ln
);
count
++
;
}
}
return
count
;
}
/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
* Modules API internals
* Modules API internals
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
...
@@ -4767,6 +4896,8 @@ int moduleLoad(const char *path, void **module_argv, int module_argc) {
...
@@ -4767,6 +4896,8 @@ int moduleLoad(const char *path, void **module_argv, int module_argc) {
if
(
onload
((
void
*
)
&
ctx
,
module_argv
,
module_argc
)
==
REDISMODULE_ERR
)
{
if
(
onload
((
void
*
)
&
ctx
,
module_argv
,
module_argc
)
==
REDISMODULE_ERR
)
{
if
(
ctx
.
module
)
{
if
(
ctx
.
module
)
{
moduleUnregisterCommands
(
ctx
.
module
);
moduleUnregisterCommands
(
ctx
.
module
);
moduleUnregisterSharedAPI
(
ctx
.
module
);
moduleUnregisterUsedAPI
(
ctx
.
module
);
moduleFreeModuleStructure
(
ctx
.
module
);
moduleFreeModuleStructure
(
ctx
.
module
);
}
}
dlclose
(
handle
);
dlclose
(
handle
);
...
@@ -4796,14 +4927,17 @@ int moduleUnload(sds name) {
...
@@ -4796,14 +4927,17 @@ int moduleUnload(sds name) {
if
(
module
==
NULL
)
{
if
(
module
==
NULL
)
{
errno
=
ENOENT
;
errno
=
ENOENT
;
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
}
}
else
if
(
listLength
(
module
->
types
))
{
if
(
listLength
(
module
->
types
))
{
errno
=
EBUSY
;
errno
=
EBUSY
;
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
}
else
if
(
listLength
(
module
->
usedby
))
{
errno
=
EPERM
;
return
REDISMODULE_ERR
;
}
}
moduleUnregisterCommands
(
module
);
moduleUnregisterCommands
(
module
);
moduleUnregisterSharedAPI
(
module
);
moduleUnregisterUsedAPI
(
module
);
/* Remove any notification subscribers this module might have */
/* Remove any notification subscribers this module might have */
moduleUnsubscribeNotifications
(
module
);
moduleUnsubscribeNotifications
(
module
);
...
@@ -4884,7 +5018,12 @@ NULL
...
@@ -4884,7 +5018,12 @@ NULL
errmsg
=
"no such module with that name"
;
errmsg
=
"no such module with that name"
;
break
;
break
;
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
;
case
EPERM
:
errmsg
=
"the module exports APIs used by other modules. "
"Please unload them first and try again"
;
break
;
break
;
default:
default:
errmsg
=
"operation not possible."
;
errmsg
=
"operation not possible."
;
...
@@ -4909,6 +5048,7 @@ size_t moduleCount(void) {
...
@@ -4909,6 +5048,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
.
sharedapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Realloc
);
REGISTER_API
(
Realloc
);
...
@@ -5059,4 +5199,6 @@ void moduleRegisterCoreAPI(void) {
...
@@ -5059,4 +5199,6 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
DictPrev
);
REGISTER_API
(
DictPrev
);
REGISTER_API
(
DictCompareC
);
REGISTER_API
(
DictCompareC
);
REGISTER_API
(
DictCompare
);
REGISTER_API
(
DictCompare
);
REGISTER_API
(
ExportSharedAPI
);
REGISTER_API
(
GetSharedAPI
);
}
}
src/redismodule.h
View file @
6fd4af1f
...
@@ -335,6 +335,8 @@ void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t
...
@@ -335,6 +335,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_ExportSharedAPI
)(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
,
void
*
func
);
void
*
REDISMODULE_API_FUNC
(
RedisModule_GetSharedAPI
)(
RedisModuleCtx
*
ctx
,
const
char
*
apiname
);
#endif
#endif
/* This is included inline inside each Redis module. */
/* This is included inline inside each Redis module. */
...
@@ -495,6 +497,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
...
@@ -495,6 +497,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
(
ExportSharedAPI
);
REDISMODULE_GET_API
(
GetSharedAPI
);
#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 @
6fd4af1f
...
@@ -1026,7 +1026,9 @@ struct redisServer {
...
@@ -1026,7 +1026,9 @@ struct redisServer {
size_t
initial_memory_usage
;
/* Bytes used after initialization. */
size_t
initial_memory_usage
;
/* Bytes used after initialization. */
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 core APIs dictionary for modules. */
dict
*
sharedapi
;
/* Like moduleapi but containing the APIs that
modules share with each other. */
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