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
561039c1
Commit
561039c1
authored
Mar 30, 2018
by
antirez
Browse files
Modules Timer API: initial implementation.
parent
192361b5
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
561039c1
...
@@ -4017,6 +4017,96 @@ int RM_GetClusterNodeInfo(RedisModuleCtx *ctx, const char *id, char *ip, char *m
...
@@ -4017,6 +4017,96 @@ int RM_GetClusterNodeInfo(RedisModuleCtx *ctx, const char *id, char *ip, char *m
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
/* --------------------------------------------------------------------------
* Modules Timers API
*
* Module timers are an high precision "green timers" abstraction where
* every module can register even millions of timers without problems, even if
* the actual event loop will just have a single timer that is used to awake the
* module timers subsystem in order to process the next event.
*
* All the timers are stored into a radix tree, ordered by expire time, when
* the main Redis event loop timer callback is called, we try to process all
* the timers already expired one after the other. Then we re-enter the event
* loop registering a timer that will expire when the next to process module
* timer will expire.
*
* Every time the list of active timers drops to zero, we unregister the
* main event loop timer, so that there is no overhead when such feature is
* not used.
* -------------------------------------------------------------------------- */
static
rax
*
Timers
;
/* The radix tree of all the timers sorted by expire. */
long
long
aeTimer
=
-
1
;
/* Main event loop (ae.c) timer identifier. */
typedef
int64_t
(
*
RedisModuleTimerProc
)(
RedisModuleCtx
*
ctx
,
void
*
data
);
/* The timer descriptor, stored as value in the radix tree. */
typedef
struct
RedisModuleTimer
{
RedisModule
*
module
;
/* Module reference. */
RedisModuleTimerProc
callback
;
/* The callback to invoke on expire. */
void
*
data
;
/* Private data for the callback. */
}
RedisModuleTimer
;
/* Create a new timer that will fire after `period` milliseconds, and will call
* the specified function using `data` as argument. The returned timer ID can be
* used to get information from the timer or to stop it before it fires. */
RedisModuleTimerID
RM_CreateTimer
(
RedisModuleCtx
*
ctx
,
mstime_t
period
,
RedisModuleTimerProc
callback
,
void
*
data
)
{
RedisModuleTimer
*
timer
=
zmalloc
(
sizeof
(
*
timer
));
timer
->
module
=
ctx
->
module
;
timer
->
callback
=
callback
;
timer
->
data
=
data
;
uint64_t
expiretime
=
ustime
()
+
period
*
1000
;
uint64_t
key
;
while
(
1
)
{
key
=
htonu64
(
expiretime
);
int
retval
=
raxInsert
(
Timers
,(
unsigned
char
*
)
&
key
,
sizeof
(
key
),
timer
,
NULL
);
if
(
retval
)
expiretime
=
key
;
else
expiretime
++
;
}
/* We need to install the main event loop timer if it's not already
* installed, or we may need to refresh its period if we just installed
* a timer that will expire sooner than any other else. */
return
key
;
}
/* Stop a timer, returns REDISMODULE_OK if the timer was found, belonged to the
* calling module, and was stoped, otherwise REDISMODULE_ERR is returned.
* If not NULL, the data pointer is set to the value of the data argument when
* the timer was created. */
int
RM_StopTimer
(
RedisModuleCtx
*
ctx
,
RedisModuleTimerID
id
,
void
**
data
)
{
RedisModuleTimer
*
timer
=
raxFind
(
Timers
,(
unsigned
char
*
)
&
id
,
sizeof
(
id
));
if
(
timer
==
raxNotFound
||
timer
->
module
!=
ctx
->
module
)
return
REDISMODULE_ERR
;
if
(
data
)
*
data
=
timer
->
data
;
raxRemove
(
Timers
,(
unsigned
char
*
)
&
id
,
sizeof
(
id
),
NULL
);
zfree
(
timer
);
return
REDISMODULE_OK
;
}
/* Obtain information about a timer: its remaining time before firing
* (in milliseconds), and the private data pointer associated with the timer.
* If the timer specified does not exist or belongs to a different module
* no information is returned and the function returns REDISMODULE_ERR, otherwise
* REDISMODULE_OK is returned. The argumnets remaining or data can be NULL if
* the caller does not need certain information. */
int
RM_GetTimerInfo
(
RedisModuleCtx
*
ctx
,
RedisModuleTimerID
id
,
uint64_t
*
remaining
,
void
**
data
)
{
RedisModuleTimer
*
timer
=
raxFind
(
Timers
,(
unsigned
char
*
)
&
id
,
sizeof
(
id
));
if
(
timer
==
raxNotFound
||
timer
->
module
!=
ctx
->
module
)
return
REDISMODULE_ERR
;
if
(
remaining
)
{
int64_t
rem
=
ntohu64
(
id
)
-
ustime
();
if
(
rem
<
0
)
rem
=
0
;
*
remaining
=
rem
;
}
if
(
data
)
*
data
=
timer
->
data
;
return
REDISMODULE_OK
;
}
/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
* Modules API internals
* Modules API internals
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
...
@@ -4074,6 +4164,9 @@ void moduleInitModulesSystem(void) {
...
@@ -4074,6 +4164,9 @@ void moduleInitModulesSystem(void) {
anetNonBlock
(
NULL
,
server
.
module_blocked_pipe
[
0
]);
anetNonBlock
(
NULL
,
server
.
module_blocked_pipe
[
0
]);
anetNonBlock
(
NULL
,
server
.
module_blocked_pipe
[
1
]);
anetNonBlock
(
NULL
,
server
.
module_blocked_pipe
[
1
]);
/* Create the timers radix tree. */
Timers
=
raxNew
();
/* Our thread-safe contexts GIL must start with already locked:
/* Our thread-safe contexts GIL must start with already locked:
* it is just unlocked when it's safe. */
* it is just unlocked when it's safe. */
pthread_mutex_lock
(
&
moduleGIL
);
pthread_mutex_lock
(
&
moduleGIL
);
...
...
src/redismodule.h
View file @
561039c1
...
@@ -115,6 +115,12 @@
...
@@ -115,6 +115,12 @@
#define REDISMODULE_NOT_USED(V) ((void) V)
#define REDISMODULE_NOT_USED(V) ((void) V)
/* This type represents a timer handle, and is returned when a timer is
* registered and used in order to invalidate a timer. It's just a 64 bit
* number, because this is how each timer is represented inside the radix tree
* of timers that are going to expire, sorted by expire time. */
typedef
uint64_t
RedisModuleTimerID
;
/* ------------------------- End of common defines ------------------------ */
/* ------------------------- End of common defines ------------------------ */
#ifndef REDISMODULE_CORE
#ifndef REDISMODULE_CORE
...
...
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