在數量眾多的文件讀寫時,例如一個目錄下有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);
}