承接前一篇, 服務器採用C編寫, 邏輯層使用LUA, 搭配開源mongodb c driver開發異步查詢接口.
有了上一次的改造, 這次來說說是如何使用改造後的接口實現異步查詢.
首先, 再來理清一下思路, 現在的一次完整同步查詢被拆分成3個步驟:
1.創建併發送請求
2.接受返回結果消息頭
3.接受返回結果數據並做相應的回調處理
爲此我們需要2個結構來處理這個過程:
上圖的第一個結構爲網絡連接內部參數, 用於每次回調處理recv的時候取數據.
第二個結構爲hash表中的數據, 用每次異步請求ID作爲KEY.
下面會分別對這三個階段進行講解:
請求發送:
ok, 請求發送時, 首先我們需要爲該次異步請求生成一個query id, 該id可以採用例如UUID類的方法生成, 也可以簡單的使用自增ID.
其次, 填充本次請求內容, 並將數據庫操作對象保存至hashtbl(query id作key), 將請求發送給DB.
最後, 將query id返回給LUA邏輯層, 掛起當前coroutine.
C 接口如下:
LUA 層接口:
接收並處理響應:
這裏面共包含2個部分, 處理消息頭和處理消息數據並打包至邏輯層.
爲什麼這裏面要把解析頭部和處理數據部分分開, 是因爲頭部長度固定, 我們可以一次讀取完成, 但是後續的數據長度是從頭部信息中獲取
得到的, 我們沒辦法在一開始就確定一共要讀多長的數據, 故要分開處理.
解析頭部:
固定讀取定長消息頭, 得到後續數據長度和query id 並得到mongo_reply, 我們需要保存該mongo_reply以便後續處理.
這裏面我們再次用到了query id, 用其將mongo_reply保存至請求時的hash結構指定KEY中.
處理數據:
此時由於本次接受到的數據並非一定滿足後續數據長度, 故有可能中斷, 但是好在該次響應在網絡層面上數據是連貫的, 所以我們在讀取
完整響應期間, 可以利用網絡框架幫助我們保存一些臨時參數, 比如保存query id, 這樣即使在非連貫的讀取一次響應數據時也不會因爲
獲取query id而產生不必要的麻煩.
這樣當我們讀取完整數據後, 就可以封裝結果至邏輯層使用了 :)
接受邏輯:
在處理數據時, 再次從hashtbl中獲取了"ns", 寫到這裏, 大家應該明白了爲什麼使用一個hashtbl來保存這個ns, 而不是直接放在網絡框架中
做臨時參數處理, 因爲每次異步請求都會得到ns, 但我們又不能保證每次都是一樣, 請求和響應並非連貫導致了臨時保存的結果可能是錯誤的也
可能是剛剛被置空了...
封裝結果至LUA邏輯層, 這裏就不列舉代碼了, 簡單說下, 就是將結果保存爲一維線性, 二維hash的lua table中.
然後調用邏輯層喚醒指定query id的coroutine繼續執行.
總結:
至此, 一個完整的異步查詢請求就編寫完成, 由於時間關係, 代碼層面上還有很多可以精簡優化的餘地, 我在此僅僅作爲提供思路, 歡迎一同探討 :)
email : [email protected]