fallocate() と ftruncate() の違いについて

※2013年2月13日、ちょっと書き直し。



以前、MongoDBをext3で使ったら死んだというページとはてブを見て、fallocateってまだまだ知られてないんだなぁと思ったので、周知のために色々書いてみることにした。

fallocateって何?

ファイルにデータを書き込む前に、指定したサイズ分の領域を事前に確保(予約)する時に使う、LinuxシステムコールC言語用の関数)です。ext4やXFSなど、対応したファイルシステムでしか使えません。ちなみに、同名かつ(ほぼ)同機能のコマンドが存在します。

posix_fallocateってのもあったんだけど、fallocateと何が違う?

fallocateにちょっと機能を追加したモノ(というかラッパー)です。fallocateに対応していないファイルシステムでも使えますが、その場合はファイルに対してゼロフィルを行うため、注意が必要です。MongoDBのpreallocateの中身はたぶんコレ。

ftruncateは?

ファイルサイズを変更するためのC言語用の関数です。ファイルを切り詰めたり、Sparseファイル(穴あきファイル)を作るのに使います。こちらも、ほぼ同名かつ同機能のコマンドが存在します。

fallocateとftruncateって具体的にどう違うわけ?

実際に使ってみると違いが分かります。

まず、次のようにそれぞれのコマンドを実行して1GBのファイルを作成します。

fallocate -l 1000M test_fallocate
truncate -s 1000M test_truncate

そのファイルの情報を、filefragコマンドで確認します。

$ filefrag -v test_fallocate 
Filesystem type is: 58465342
File size of test_fallocate is 1048576000 (256000 blocks, blocksize 4096)
 ext logical physical expected length flags
   0       0 54729056          256000 unwritten,eof
test_fallocate: 1 extent found

$ filefrag -v test_truncate 
Filesystem type is: 58465342
File size of test_truncate is 1048576000 (256000 blocks, blocksize 4096)
test_truncate: 0 extents found

このように、truncateでは実ブロックが確保されていません。

fallocateって、実際にどう使うわけ?

creat()システムコールを実行して新規ファイルを作成 → そのファイルディスクリプタを引数にしてfallocate()システムコールを呼び出す、といった感じで使います。

fallocateを使う利点って何?

fallocateの戻り値やerrnoをチェックすることで、ドライブに空きがあるか分かります。

また、fallocateは可能な限り連続した領域を確保するため、断片化を抑えることができます。

ただし、ファイルシステムext4の場合、バグがあるらしく、128MBを超えるサイズに対しては断片化を抑える効果がありません(Ubuntu 12.04での話です。いずれ改善するかも?)

ファイルシステムがXFSの場合、空き領域が充分あれば断片化しません。1GBを超えるサイズも余裕です。

ext4でfallocateを使って大きなサイズを確保した場合、どれぐらい断片化するの?

1GB確保してみたら、こうなりました。

$ fallocate -l 1000M test_fallocate
$ filefrag -v test_fallocate 
Filesystem type is: ef53
File size of test_fallocate is 1048576000 (256000 blocks, blocksize 4096)
 ext logical physical expected length flags
   0       0   784384            2048 unwritten
   1    2048   815104   786432   4096 unwritten
   2    6144   835584   819200  26624 unwritten

中略

  28  223232  2174976  2164736   8192 unwritten
  29  231424  2217984  2183168  22528 unwritten
  30  253952  2250752  2240512   2048 unwritten,eof
test_fallocate: 31 extents found

断片化しまくりです。

関連