本文爲做者原創,轉載請註明出處:http://my.oschina.net/fuckphp/blog/505956php
Redis 的 ae模塊的代碼主要分佈在 ae.c ae.h 還有 ae_*.c 中,分別實現了epoll、evport、kqueue、select幾種網絡模型,本文將以epoll爲例,對Redis的ae模塊進行學習。redis
aeEveltLoop 主要定義描述了redis ae模塊的主循環信息,在整個事件的循環週期內(aeEveltLoop.stop!=0),保存了io事件和時間事件的事件列表等信息。
api
typedef struct aeEventLoop { int maxfd; /* 當前註冊的最大描述符 */ int setsize; /* 最大文件描述符個數 */ long long timeEventNextId; //自增id 用於給每一個事件分配id time_t lastTime; /* 用於校準系統時間,每次事件事件執行前更新該時間 */ aeFileEvent *events; /* 存放註冊的事件 */ aeFiredEvent *fired; /* 已經觸發的事件保存在這裏 */ aeTimeEvent *timeEventHead; /* 時間事件單向鏈表 包含了將來將會事件的事件 */ int stop; void *apidata; /* 用戶的自定義數據用於傳遞給回調函數 */ aeBeforeSleepProc *beforesleep; /* 每個事件循環都會執行一次 */ } aeEventLoop;
aeFileEvent 描述了redis ae模塊關於io類事件的主要信息,包含當前事件的讀寫模式回調函數等,註冊一個io事件後aeFileEvent結構被記錄在aeEventLoop的events屬性中,根據文件描述來決定結構在events屬性中的位置
網絡
/* File event structure */ typedef struct aeFileEvent { int mask; /* one of AE_(READABLE|WRITABLE) 讀寫模式的定義*/ aeFileProc *rfileProc; /* 讀操做回調函數的定義 */ aeFileProc *wfileProc; /* 寫操做回調函數的定義 */ void *clientData; /* 用戶自定義數據用於傳遞給回調函數 */ } aeFileEvent;
aeTimeEvent 描述了redis時間事件的主要信息,Redis的事件事件結構就是一個鏈表節點,多個時間事件組成鏈表,Redis每一個循環週期會遍歷該鏈表(保存在aeEventLoop.timeEventHead中),進行時間校準後,執行觸發的時間事件。
函數
/* Time event structure */ typedef struct aeTimeEvent { long long id; /* 時間事件的id,根據aeEventLoop.timeEventNextId屬性自增來生成 */ long when_sec; /* 執行當前事件的時間 單位 秒 */ long when_ms; /* 執行當前事件的時間 單位 毫秒 */ aeTimeProc *timeProc; /* 事件觸發時候執行 */ aeEventFinalizerProc *finalizerProc; /* 事件執行完成而且從時間事件鏈表中刪除的時候執行 */ void *clientData; /* 用戶自定義數據用於傳遞給回調函數 */ struct aeTimeEvent *next; /* 指向鏈表的下一個節點 */ } aeTimeEvent;
aeFiredEvent 保存了每次被觸發io事件的文件描述符和讀寫模式信息
oop
/* A fired event */ typedef struct aeFiredEvent { int fd; /* 觸發io事件的文件描述符 */ int mask; /* 描述當前觸發的讀寫模式 */ } aeFiredEvent;
該部分使用一張簡單的圖片來表示,具體內容能夠結合上文註釋來理解(圖片偷自 @C_Z 的文章 :) )學習
建立 aeEventLoop同時初始化 io事件列表和事件事件鏈表和相關的狀態信息,同時建立epoll對象spa
建立 時間事件 設置時間事件觸發的回調函數,執行時間並加入到主循環的timeEventHead鏈表中.net
建立 io事件 根據 設置 epoll監聽的文件表述符描述符讀寫狀態同時更新到aeEventLoop的events事件列表相應位置中(根據文件描述符來定位指針的偏移量)指針
偷懶。。稍候補圖。。。。
執行 aeBeforeSleepProc 回調函數
讀取最近一個時間事件的距離事件
執行epoll_wait 監聽文件描述符,監聽超時時間截止到下一個時間事件觸發以前或者有io事件觸發
將觸發的io事件放入aeEventLoop.FiredEvent中
讀取觸發的io事件列表並執行對應的讀寫事件
校準系統時間,若是系統時間與lastTime不符合實際狀況,則將時間事件鏈表中全部事件都標記爲當即執行
執行每一一個時間事件的回調函數
根據回調函數返回值決定,當前事件該從時間事件鏈表刪除仍是從新設置下次執行時間
若是時間事件從倆表刪除則執行 aeEventFinalizerProc 回調函數
進入下一個循環週期 知道 aeEventLoop.stop == 0
Redis2.8.9源碼 src/ae.h src/ae.c src/ae_epoll.c