在數量眾多的檔案讀寫時,例如一個目錄下有400萬個圖片檔案,需要將這400萬個圖片檔案打包,如果這400萬個檔案讀寫順序不對,將會到這磁頭來回seek,即便單檔案順序,但由於每個檔案較小,因此順序的機會有限,大部分呈現隨機讀的狀態。
linux核心的IO scheduling 是針對單個檔案的,有四種調度方式,但缺乏對大量檔案的調度,因此有必要在使用者空間進行IO調度。
簡單來說我們有一個目錄D,目錄下有file1,....file400million(檔案名稱),這樣400萬個檔案
首先第一步,獲得每個file的首個邏輯塊對應的PBI(physical block id),產生(PBI,filename)的pair
第二步,對FBI進行排序
第三步,按照排序結果進行IO
舉例,假定有三個檔案FILEA,FILEB,FILEC
第一步,FILEA的FBI為4094,FILEB的FBI為2310,FILEC的FBI為8910
則得到如下的列表
4094 FILEA
2310 FILEB
8910 FILEC
第二步,對FBI按升序排列,得到
2310 FILEB
4094 FILEA
8910 FILEC
第三步,讀入檔案的順序確定為FILEB,FILEA,FILEC,依次入讀
補充兩個基本要點:
1)每個檔案的邏輯塊從0開始編號
2)每個檔案的物理塊可以認為是連續(或者接近連續,這個由作業系統保證)
以下代碼為獲得任意一個檔案的全部物理塊號
#include "stdio.h"#include "stdlib.h"#include "fcntl.h"#include "sys/types.h"#include "sys/stat.h"#include "sys/ioctl.h"#include "linux/fs.h"int main(void){ int fd = open("/data/gram_test",O_RDONLY); if(fd<0) { return 1; } struct stat buf; int ret = fstat(fd,&buf); int nr_blocks = buf.st_blocks; //擷取邏輯塊數 for(int i = 0;i<nr_blocks;++i) { int physic_block_id = i; int ret = ioctl(fd,FIBMAP,&physic_block_id); //從指定邏輯塊獲得物理塊號,需要有root許可權。 if(!physic_block_id)continue; printf("%d\t%d\n",i,physic_block_id); }
close(fd);}
參考:
http://simula.no/research/nd/publications/Simula.ND.399/simula_pdf_file
http://home.ifi.uio.no/paalh/students/CarlHenrikLunde.pdf