creat()などで作成したファイルに、大きなデータを書き込むとファイルの断片化が起こるが、データを書き込む前に領域を確保しておけば、断片化が起こる可能性を減らすことが出来る。
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/falloc.h>
int main(void)
{
int fd = creat("sample.dat", S_IRUSR | S_IWUSR);
/* 領域を128MB確保する */
fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, 1024 * 1024 * 128);
/* ここにデータを書き込む処理を書く */
return 0;
}
上記のコードを実行して作成したsample.datに対して、filefragコマンドを実行すると以下のように表示される。
$filefrag -v sample.dat
Filesystem type is: ef53
File size of sample.dat is 0 (0 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 4435968 30720 unwritten,eof
1 30720 4466688 2048 unwritten,eof
sample.dat: 1 extent found
ファイルサイズは0のままだが、連続した実領域が確保されているのが確認できる。
上記の通り、fallocate()はファイルサイズ(の値)を変更しないので、そこが気になる場合は代わりにposix_fallocate()を使用する。
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/falloc.h>
int main(void)
{
int fd = creat("sample2.dat", S_IRUSR | S_IWUSR);
/* 領域を256MB確保する */
posix_fallocate(fd, 0, 1024 * 1024 * 256);
/* ここにデータを書き込む処理を書く */
return 0;
}
上記のコードを実行して作成したファイルに対して、filefragコマンドを実行すると以下のようになる。
$filefrag -v sample2.dat
Filesystem type is: ef53
File size of sample2.dat is 268435456 (65536 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 4548608 30720 unwritten
1 30720 4579328 30720 unwritten
2 61440 4610048 4096 unwritten,eof
sample2.dat: 1 extent found
File sizeが268435456になっている。
ちなみに、fallocate()は本来、ディスクスペースを確実に確保するための関数、つまり、
データをファイルに書き出そうとしたけど、空きが無くて失敗したよ\(^o^)/
という状況を事前に防ぐ為の関数であって、断片化を防ぐためのものでは無い。連続領域が確保されるのはオマケみたいなもん。
他にも、fallocate()実行にかかるコストはほとんど無いとか、確保した領域は0で埋められている事が期待できるので、作成したファイルに対してゼロフィルする必要が無いとか、そういう利点もあったりする。
欠点は、使えるファイルシステムが限られる点。ext4やXFS、btrfsは対応しているが、今でもよく使われていると思われるext3は未対応。
あと、ext4は連続領域を確保する性能が低いので、fallocate()で128MBを超える領域を確保すると断片化しやすい。XFSはその辺は優秀で、1GBを超えても余裕で連続領域を確保できる。
WindowsではSetFilePointer()とSetEndOfFile()を使えば連続領域を確保出来るらしいので、誰かサンプルソース下さい。