誰得な発見という感じもするのですが、備忘録として。

Obsoleted by Nettalk 2.2.x and OS X Lion

netatalkというオープンソースソフトウェアがあります。

netatalk - Wikipedia
netatalkはUnix系OS上でMac OSやMac OS Xに対してAFPによるファイルサーバの機能を提供するオープンソースのソフトウェアである。

これを使うと余ったPCをMac用ファイルサーバーに仕立て上げられるという優れもので、AFP対応を謳ったNASの多くも内部でこれを動かしていたりします。当然私も愛用しているのですが、2.1系列になったとたん、遅くなったのです。

もう少し詳しく言うと、大きなファイルの転送は遅くないのに、多数の小さなファイルだとやたら遅くなる。多かれ少なかれネットワークストレージというのはローカルストレージよりも多数の小さなファイルに弱いもので、だからこそTime Capsuleでも、ファイル共有をそのまま使うのではなく、そこにあるディスクイメージ(Sparse Bundle)をマウントしてしてバックアップをしているのですが、それを考慮しても遅い…

結論から言うと、cnidscheme:lastAppleVolumes.defaultでするだけでした。

AppleVolumes.default の一例
:DEFAULT: options:upriv,usedots
~/netatalk   $u@$h cnidscheme:last options:noadouble dperm:0700 fperm:0600

解説

なぜこれで速くなるのか、というより元通りの速さになるのかを理解するには、AFPというプロトコルについてざっくり知っておく必要があります。

Chapter 3. Setting up netatalk - netatalk 2.1
Unlike other protocols like smb or nfs, the AFP protocol mostly refers to files and directories by ID and not by a path (the IDs are also called CNID, that means Catalog Node ID). A typical AFP request uses a directory ID and a filename, something like "server, please open the file named 'Test' in the directory with id 167". For example "Aliases" on the Mac basically work by ID (with a fallback to the absolute path in more recent AFP clients. But this applies only to Finder, not to applications).

「SMBやNFSと違って、AFPではパスではなくIDでファイルやディレクトリを指定する」とあります。なぜそんな仕様になっているかといえば、今は亡き Mac OS のローカルファイルシステムがそうなっていたからで、そのおかげで「システムフォルダ」をどこかに移動しても起動できたり、エイリアスは元のファイルを移動しても元のファイルにアクセスできたりするのですが、今をときめく Mac OS X もHFS+は受け継いでいて、そんなわけでAFPもそういう仕様になっているわけです。

というわけでAFPを実現するにはファイルにIDを振らなければならないのですが、これを実装のしかたが2.0と2.1では異なるわけです。厳密にはデフォルトの実装が。

2.0系列では、cdbという形式がデフォルトでした。/path/to/the/shared/.AppleDBというディレクトリの中にデータベースファイルを置いて、これをafpdが直接読み書きしていたのですが、2.1系列以降はcnid_metadというデータベース管理デーモンを別に動かして、それに問い合わせる形式にかわったのです。SQLiteをMySQLに代えたようなものです。

これだと確かにデータベースの整合性は向上するのですが、前述のとおり遅くなります。

それでは cnidscheme:cdb を指定すれば元通りになるかといえば、確かになるのですが、セッション開始時にこんな警告も出るようになります。

余談ですが、Ubuntuのパッケージが2.0.5のままなのはこれが理由かも知れません。FreeBSDのPortsは2.1.5になっちゃいましたが。

で、警告が出ないようにするたった一つのやり方が cnidscheme:last です。"last resort"、最後の手段というわけなのでしょう。解説も脅し口調です。

Chapter 3. Setting up netatalk - netatalk 2.0
In the past, many users used the so called "last" CNID scheme. However, this scheme has some serious drawbacks, as it is based on the device and inode of a file. Therefore, IDs will be eventually be reused and you can get duplicate IDs as well.

しかしよく考えてみると、これが一番「冴えた」やりかたのはずです。

まずinodeの一意性は、Unix系のOSではファイルシステム単位で確保されています。唯一問題があるとしたら、共有ボリュームの中にシンボリックリンクがあってこれのおかげで別のファイルシステムが同じ共有ボリュームとして見えてしまった場合ですが、「共有ディレクトリ内にシンボリックリンクがあったら責任もてません」というのはちゃんとnetatalkの取説にも書いてあります。

こうなると残りはIDの再利用ですが、これもセッション内でそれがおこらなければ充分なのは、セッションを終了してから.AppleDBディレクトリを削除しても、再接続すれば2.0でも2.1でもnetatalkは何食わぬ顔で作り直していたことからもわかります。なお、上記の方法をとったばあい、.AppleDBは不要になり、公開ボリュームを新規に作った場合にも作成されなくなります。

そもそもMac OS Xでは、HFS+のCNIDをそのままinode番号として昔も今も使っていますし、Carbon APIを使えば今もなおCNIDでファイル指定はできるのですが、Classic環境なき今、今ではOS Xでもファイルの指定はパスで行うのが普通。専用のデータベースサーバーまで用意してまでCNIDの整合性にこだわる理由がわかりません。まだX以前の Mac OS を使っているなら話は別かも知れませんが…

というわけで、お試しあれ。もちろんあくまで自己責任で。私の場合はその価値大いにありました。

Dan the Man with Too Many Files to Share

追記[2010.08.03] OS X Lion の AFP 3.3 と Netatalk 2.2.0 の組み合わせだと cnidscheme:last で一部ファイルが見えなくなりました。デフォルトに戻してnetatalk再起動できちんと使えるようにはなりましたが、速度に関しては要再検証。