時間事件保存在aeEventLoop->timeEventHead 以鏈表的方式進行存儲
/* Time event structure */
typedef struct aeTimeEvent {
long long id; /* time event identifier. */
long when_sec; /* seconds */
long when_ms; /* milliseconds */
aeTimeProc *timeProc; //時間事件處理函數
aeEventFinalizerProc *finalizerProc;
void *clientData;
struct aeTimeEvent *next;
} aeTimeEvent;
時間事件API
添加時間事件
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
aeTimeProc *proc, void *clientData,
aeEventFinalizerProc *finalizerProc)
{
long long id = eventLoop->timeEventNextId++;
aeTimeEvent *te;
te = zmalloc(sizeof(*te));
if (te == NULL) return AE_ERR;
te->id = id;
//微妙轉換成時間戳
aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
te->timeProc = proc; //時間處理函數
te->finalizerProc = finalizerProc;
te->clientData = clientData;
te->next = eventLoop->timeEventHead; //insert 鏈表
eventLoop->timeEventHead = te;
return id;
}
刪除時間事件(by id)
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
{
aeTimeEvent *te, *prev = NULL;
te = eventLoop->timeEventHead;
while(te) {
if (te->id == id) {
if (prev == NULL)
eventLoop->timeEventHead = te->next;
else
prev->next = te->next;
//刪除時候,執行的finalizerProc回調
if (te->finalizerProc)
te->finalizerProc(eventLoop, te->clientData);
zfree(te);
return AE_OK;
}
prev = te;
te = te->next;
}
return AE_ERR; /* NO event with the specified ID found */
}
//搜索最近時間事件,遍歷鏈表
static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
{
aeTimeEvent *te = eventLoop->timeEventHead;
aeTimeEvent *nearest = NULL;
while(te) {
if (!nearest || te->when_sec < nearest->when_sec ||
(te->when_sec == nearest->when_sec &&
te->when_ms < nearest->when_ms))
nearest = te;
te = te->next;
}
return nearest;
}
//時間事件處理函數
static int processTimeEvents(aeEventLoop *eventLoop) {
int processed = 0;
aeTimeEvent *te;
long long maxId;
time_t now = time(NULL);
/* 如果時鐘被往回調整,定時jobs強制執行一遍 */
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;
while(te) {
long now_sec, now_ms;
long long id;
if (te->id > maxId) {
te = te->next;
continue;
}
aeGetTime(&now_sec, &now_ms);
//超時了
if (now_sec > te->when_sec ||
(now_sec == te->when_sec && now_ms >= te->when_ms))
{
int retval;
id = te->id;
/*回調定時任務函數,比如serverCron*/
retval = te->timeProc(eventLoop, id, te->clientData);
processed++;
/*重置或者刪除*/
if (retval != AE_NOMORE) {
aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
} else {
aeDeleteTimeEvent(eventLoop, id);
}
te = eventLoop->timeEventHead;
} else {
te = te->next;
}
}
return processed;
}
serverCron
持續運行的redis需要定期對自身資源和狀態進行檢查和調整,serverCron就是做這件事的。
主要工作:
1 更新服務器各類統計,比如時間、內存佔用、數據庫佔用等情況
2 清理數據庫中過期的鍵值對
3 關閉和清理連接失效的客戶端
4 嘗試進行aof或rdb持久化操作
5 如果服務器是主服務器,那麼對從服務器進行定期同步
添加:
initServer -> aeCreateTimeEvent
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
redisPanic("Can't create the serverCron time event.");
exit(1);
}
執行:
1 watch_dog機制,是爲了檢測系統超時調用。相應的配置watchdog_period,如果爲非0,那麼就是執行一遍網絡事件耗時超過給定值,那麼setitimer 就會釋放sigalarm信號, 生成coredump,可以看當前耗時堆棧。
源碼:
if (server.watchdog_period) watchdogScheduleSignal(server.watchdog_period);
void watchdogScheduleSignal(int period) {
struct itimerval it;
/* Will stop the timer if period is 0. */
it.it_value.tv_sec = period/1000;
it.it_value.tv_usec = (period%1000)*1000;
/* Don't automatically restart. */
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &it, NULL);
}
2 更新系統cache時間
updateCachedTime()
3 統計,採用循環數組方式,idx指向當前最新方式。
//平均命令數
trackInstantaneousMetric(REDIS_METRIC_COMMAND,server.stat_numcommands);
//平均網絡input
trackInstantaneousMetric(REDIS_METRIC_NET_INPUT,server.stat_net_input_bytes);
//平均網絡output
trackInstantaneousMetric(REDIS_METRIC_NET_OUTPUT,server.stat_net_output_bytes);
4 更新redis idle 時間
server.lruclock = getLRUClock();
5 記錄最大使用內存
if (zmalloc_used_memory() > server.stat_peak_memory)
server.stat_peak_memory = zmalloc_used_memory();
6 客戶端管理clientsCron
①處理超時客戶端 ② 客戶端緩衝區大小調整
7databasesCron 數據庫管理