回答編集履歴

2

補足説明

2023/08/18 02:03

投稿

otn
otn

スコア86295

test CHANGED
@@ -6,7 +6,7 @@
6
6
  Unix/Linux系の全てのファイルシステムを知っているわけではないですが、一般にディレクトリーの構造は、可変長のディレクトリーエントリー(可変長のファイル名と管理情報)が並んだ形式になっていて、データベースのような索引は無いので、ファイルを探すには先頭から見つかるまでディレクトリーファイルを読む必要があります。例えば、手元の`/usr/bin`は36KBなので、`/usr/bin/ls`の管理情報を知るために、平均すると18KBのファイルを読むことになります。
7
7
 
8
8
  質問の例だと、ファイル名が40バイトくらい(ちゃんと数えてませんが)のようなので、管理情報込みで1つのディレクトリーエントリーが60バイトだと仮定します。で、ファイルが1万6000個あったとすると、1つのディレクトリーに入れた場合、ディレクトリーサイズは、960,000 で、ファイルオープンや削除などをするために1ファイルの管理情報を得るために、平均480,000バイト読むことになります。
9
- これを1000個ずつ16分割すると、親ディレクトリーサイズは960で平均480バイト読む。子ディレクトリーサイズは60,000で平均30,000バイト読むので、親子合計で30,480バイトと、1ディレクトリーの場合の1/10以下です(16分割なのでおおよそ16分の1)。つまりメモリーのキャッシュやバッファの効果を無視すると十倍以上速い。
9
+ これを1000個ずつ16分割すると、親ディレクトリーサイズは960で平均480バイト読む。子ディレクトリーサイズは60,000で平均30,000バイト読むので、親子合計で30,480バイトと、1ディレクトリーの場合の1/10以下です(16分割なのでおおよそ16分の1)。つまりメモリーのキャッシュやバッファの効果を無視すると十倍以上速い。(実際にはストレージの読み書きはバイト単位じゃなくてセクター単位なので、バイト数をセクターサイズで割って切り上げた回数の読み書きが発生します)
10
10
 
11
11
  あと、ディレクトリーエントリーは可変長なので、ファイル名の長さが異なるファイルを追加・削除を繰り返すと、空き領域の断片化が発生して、ディレクトリーサイズが肥大します。手元の`/tmp`はファイル数18個なのにサイズが112KBとかなり肥大化してます。作り直せば4KBで収まるはず。
12
12
  なので、キャッシュファイルの格納など、大量のファイルの追加削除が発生する場合は、ファイル名の長さを一定にすることが多いようです。ファイル名の長さが一定なら、全てのディレクトリーエントリーのサイズが同一で、削除したファイルの場所をそのまま再利用できるので、肥大化しません。肥大化すると読む量が増えるので、これも高速化のコツですね。

1

補足

2023/08/17 15:11

投稿

otn
otn

スコア86295

test CHANGED
@@ -6,7 +6,7 @@
6
6
  Unix/Linux系の全てのファイルシステムを知っているわけではないですが、一般にディレクトリーの構造は、可変長のディレクトリーエントリー(可変長のファイル名と管理情報)が並んだ形式になっていて、データベースのような索引は無いので、ファイルを探すには先頭から見つかるまでディレクトリーファイルを読む必要があります。例えば、手元の`/usr/bin`は36KBなので、`/usr/bin/ls`の管理情報を知るために、平均すると18KBのファイルを読むことになります。
7
7
 
8
8
  質問の例だと、ファイル名が40バイトくらい(ちゃんと数えてませんが)のようなので、管理情報込みで1つのディレクトリーエントリーが60バイトだと仮定します。で、ファイルが1万6000個あったとすると、1つのディレクトリーに入れた場合、ディレクトリーサイズは、960,000 で、ファイルオープンや削除などをするために1ファイルの管理情報を得るために、平均480,000バイト読むことになります。
9
- これを1000個ずつ16分割すると、親ディレクトリーサイズは960で平均480バイト読む。子ディレクトリーサイズは60,000で平均30,000バイト読むので、親子合計で30,480バイトと、1ディレクトリーの場合の1/10以下です。つまりメモリーのキャッシュやバッファの効果を無視すると十倍以上速い。
9
+ これを1000個ずつ16分割すると、親ディレクトリーサイズは960で平均480バイト読む。子ディレクトリーサイズは60,000で平均30,000バイト読むので、親子合計で30,480バイトと、1ディレクトリーの場合の1/10以下です(16分割なのでおおよそ16分の1)。つまりメモリーのキャッシュやバッファの効果を無視すると十倍以上速い。
10
10
 
11
11
  あと、ディレクトリーエントリーは可変長なので、ファイル名の長さが異なるファイルを追加・削除を繰り返すと、空き領域の断片化が発生して、ディレクトリーサイズが肥大します。手元の`/tmp`はファイル数18個なのにサイズが112KBとかなり肥大化してます。作り直せば4KBで収まるはず。
12
12
  なので、キャッシュファイルの格納など、大量のファイルの追加削除が発生する場合は、ファイル名の長さを一定にすることが多いようです。ファイル名の長さが一定なら、全てのディレクトリーエントリーのサイズが同一で、削除したファイルの場所をそのまま再利用できるので、肥大化しません。肥大化すると読む量が増えるので、これも高速化のコツですね。