kfs代碼研究(磁盤異步IO)

磁盤IO在[qcdio/qcdiskqueue.h]和[qcdio/qcdiskqueue.cc]中實現,基於線程池和消費者/生產者模型。在這兩個源文件中實現了基於成塊讀寫的異步磁盤IO。

[qcdio/qcdiskqueue.cpp] class QCDiskQueue::Queue,實現了磁盤文件的異步IO。文件讀寫的單位是塊(支持direct-io)。它會啓動給定數量(inThreadCount)的線程處理io請求,支持管理給定數量(mFileCount)的磁盤文件,並且只支持給定數量(inMaxQueueDepth)的請求隊列長度。每次讀寫請求都表示爲一個Request,並插入Queue本身的請求隊列中,執行線程從請求隊列中取下Request並請求,請求執行完成以後,調用請求的回調函數。Queue本身並不保證磁盤請求的執行順序,也就是說,對於同一個文件發出的請求可能被並行執行,上層用戶必須保證發起的請求是可並行的。對於一個由Queue管理的文件,它會爲每個工作線程打開一個文件描述符,這樣就可以充分發揮讀的並行性,同時也意味着每個文件會打開inThreadCount個文件描述符。Queue用數組組織所有的打開的文件,當上層調用Open接口,Queue會返回一個int表示該文件在文件數組中的下標,類似於系統層的文件描述符,後續的讀寫請求都在該”文件描述符”上進行。Queue使用數組和鏈表組織所有的讀寫請求,當上層發起一個請求,首先在數組中分配一個未使用的Request,然後將該request放入請求隊列中,並把request的id(request在數組中的下標)返回給調用者,後續該request的操作以requestid爲標示。文件的讀寫由工作線程使用writev完成。每個請求都有一個與之關聯的回調函數,該請求失敗或者成功會調用該回調函數。由於單個Request的buffer數量是有限的,最多爲writev支持的最大數組長度,因此一個請求可能有多個Request組成,由鏈表鏈接起來。第一個Request包含了整個請求讀寫的塊數量,工作線程每次會取一個完整的請求的所有Request,因此每個請求都是有一個線程完成的。看代碼發現可能的一個bug,Cancel一個請求的時候,代碼只是把請求的第一個Request從請求鏈表中移除,而沒有移除所有的Request。在0.4的版本中,Sync接口沒有實現,僅僅是一個空讀。

[qcdio/qcdiskqueue.cpp] class QCDiskQueue 該類是對QCDiskQueue::Queue進行了簡單的封裝,同時使用條件變量提供了文件讀寫的磁盤接口。就是請求發起線程阻塞在那裏,等待工作線程完成io操作。

以上就是磁盤異步IO的主要實現


發佈了4 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章