summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJokea <tfengjun@gmail.com>2012-08-30 15:08:19 +0800
committerantirez <antirez@gmail.com>2012-10-04 19:30:48 +0200
commite480c279bc28832ca78a33f7f52c0b57ae5a16f1 (patch)
treef0f1e5953c98dfca6dca7d3b8dc82b45a64cf9db
parent0c19880ce61bb4516346288a33797ec650e13842 (diff)
downloadredis-e480c279bc28832ca78a33f7f52c0b57ae5a16f1.tar.gz
Force expire all timer events when system clock skew is detected.
When system time changes back, the timer will not worker properly hence some core functionality of redis will stop working(e.g. replication, bgsave, etc). See issue #633 for details. The patch saves the previous time and when a system clock skew is detected, it will force expire all timers. Modiifed by @antirez: the previous time was moved into the eventLoop structure to make sure the library is still thread safe as long as you use different event loops into different threads (otherwise you need some synchronization). More comments added about the reasoning at the base of the patch, that's worth reporting here: /* If the system clock is moved to the future, and then set back to the * right value, time events may be delayed in a random way. Often this * means that scheduled operations will not be performed soon enough. * * Here we try to detect system clock skews, and force all the time * events to be processed ASAP when this happens: the idea is that * processing events earlier is less dangerous than delaying them * indefinitely, and practice suggests it is. */
-rw-r--r--src/ae.c19
-rw-r--r--src/ae.h1
2 files changed, 20 insertions, 0 deletions
diff --git a/src/ae.c b/src/ae.c
index ba53b4568..ee483802c 100644
--- a/src/ae.c
+++ b/src/ae.c
@@ -67,6 +67,7 @@ aeEventLoop *aeCreateEventLoop(int setsize) {
eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
eventLoop->setsize = setsize;
+ eventLoop->lastTime = time(NULL);
eventLoop->timeEventHead = NULL;
eventLoop->timeEventNextId = 0;
eventLoop->stop = 0;
@@ -236,6 +237,24 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
int processed = 0;
aeTimeEvent *te;
long long maxId;
+ time_t now = time(NULL);
+
+ /* If the system clock is moved to the future, and then set back to the
+ * right value, time events may be delayed in a random way. Often this
+ * means that scheduled operations will not be performed soon enough.
+ *
+ * Here we try to detect system clock skews, and force all the time
+ * events to be processed ASAP when this happens: the idea is that
+ * processing events earlier is less dangerous than delaying them
+ * indefinitely, and practice suggests it is. */
+ if (now < eventLoop->lastTime) {
+ te = eventLoop->timeEventHead;
+ while(te) {
+ te->when_sec = 0;
+ te = te->next;
+ }
+ }
+ eventLoop->lastTime = now;
te = eventLoop->timeEventHead;
maxId = eventLoop->timeEventNextId-1;
diff --git a/src/ae.h b/src/ae.h
index e1dccfc76..f52a075e5 100644
--- a/src/ae.h
+++ b/src/ae.h
@@ -88,6 +88,7 @@ typedef struct aeEventLoop {
int maxfd; /* highest file descriptor currently registered */
int setsize; /* max number of file descriptors tracked */
long long timeEventNextId;
+ time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* Registered events */
aeFiredEvent *fired; /* Fired events */
aeTimeEvent *timeEventHead;