CNID (Netatalk)

以前調べたものを貼り付けます。
何かあればご指摘ください。

#Resarch of CNID

###参考ページ
[MacDeveloper Library](https://developer.apple.com/library/mac/documentation/networking/conceptual/afp/Introduction/Introduction.html)

[Netatalk & Samba(日本語)](http://www003.upp.so-net.ne.jp/hat/netatalk/andsamba.html)

[netatalt公式(CNID backends)](http://netatalk.sourceforge.net/3.1/htmldocs/configuration.html#CNID-backends)

[netatalk の CNID で mysql を使う方法](http://navy-anecdote.tumblr.com/post/69368683595/netatalk-cnid-mysql)

##What's "CNID"!?

MacOSの為に作られた[HFS+](https://github.com/n-fukidome/fuki/wiki/HFS-plus)というファイルシステムでは、ファイルやフォルダにCNID (Catalog Node ID)と呼ばれる番号を付けて管理しています。File ID、Directory IDと呼ぶ場合もあります。これはAFPの場合も同様です。  

CNIDはinode番号の概念に似ていますが同じではありません。netatalkはCNIDの管理方法をいくつか用意しており、これをcnid schemeといいます。デフォルトのdbdでは、Berkeley DBを使って ```var/netatalk/CNID/(ボリューム名)```ディレクトリでCNIDのデータベースを管理します。  

###cnid schemeの種類
1.```cnid scheme = dbd```  
これがデフォルト、afpdが直接データベースを書き換える。CNIDデーモン(cnid_metadデーモン)がデータベースを一括管理し、別ディレクトリにデータを保存する。各afpdはCNIDデーモンと通信するだけ。  

2.```cnid scheme = tdb```  
CNIDデーモンで何らかの問題が発生したとき、代わりとしてメモリ上でCNID管理する。  

3.```cnid scheme = last```  
afpdプロセス毎にその場限りの管理をする(データベース管理していない)。これを使うと自動的にリードオンリーになる。リードオンリーのファイルシステム(CD-ROMとか)だと```.AppleDB/```ディレクトリを作れないので、これを使います。  

4.```cnid scheme = mysql```  
大規模サーバ向け(3.1.x~)

通常は```dbd```で運用しますが、データベースに何らかの不具合が発生した場合は自動的に```tdb```に移行する仕組みになっています。  
管理ディレクトリ内のデータベースは滅多に壊れませんが、もし壊れた場合はメンテ用のdbdコマンドで修復します。このコマンドはnetatalkを起動しっぱなしで使います。それでも直らない場合は-fオプションを使えば、データベースを全部削除してから再構築します。  

> (昔の情報)  
サーバーの電源が突然落ちると（停電などで）、
OSXからマウントができなくなってしまいます。
一応、認識はしているようですが、マウントができません。  
そんなときは、
[Netatalk & Samba(日本語)](http://www003.upp.so-net.ne.jp/hat/netatalk/andsamba.html)
を参考に、
マウントポイント直下の隠しディレクトリを削除してからNetatalkを再起動すると結構直ります。  
**<以下、[Netatalk & Samba(日本語)](http://www003.upp.so-net.ne.jp/hat/netatalk/andsamba.html)から引用>**  
netatalkでは、Berkeley DBを使って ```.AppleDB/```というディレクトリでCNIDのデータベースを管理しています。 何らかの理由でこのディレクトリの中のファイルが壊れると、クライアントからうまく接続出来ないといったトラブルが発生します。  
CNIDの管理方法は何種類かあり、```AppleVolumes.default```で設定出来ます。デフォルトでconfigureしたnetatalkの場合は3種類です。  
#####1.```cnidscheme:cdb```  
ぼちぼち安定している。afpdが直接データベースを書き換える。複数afpdが動いている場合、どれかのafpdがクラッシュするとデータベースが壊れる。
#####2.```cnidscheme:dbd```
かなり安定している。cnid_metadデーモンがデータベースを一括管理する。各afpdはcnid_metadと通信するだけ。  
#####3.```cnidscheme:last```
データベース管理していない。大昔のnetatalkにファイルを大量コピーするとエラーになったのはこれが原因です。リードオンリーのファイルシステム(CD-ROMとか)だと.AppleDB/ディレクトリを作れないので、これを使います。  
デフォルトのnetatalkはcdbになっていますが、リードオンリーである場合を除き、dbdを使う事を強くお勧めします。これを使っている場合は実質的にデータベースは壊れません。壊れているかどうかは自動的にチェックされます。  
データベースが壊れた場合、修復するツールとして```cnid_maint```が付属していますが、これは自分の環境に合わせて書き換えないと動かないし、ドキュメントも用意されていません。```cnid_index```というコマンドもあり、これはちゃんとman pageがあります。試してみたところ、完璧に修復してくれるわけでもないようです。一番確実なのは、netatalkを停止してから.AppleDB/ディレクトリを削除し、netatalkを再起動することです。こうすると新たに.AppleDB/ディレクトリが作られます。  
<引用終わり>  
実際、2007/2/21にあやまってサーバーのコンセントを抜いてしまい、Macから接続しようとすると、虹のカーソルがぐるぐる回り、接続できなくなってしまったのですが、
マウントポイント直下の.AppleDBディレクトリを削除したところ、再び接続できるようになりました。  
上記HPによると、これで直った場合、CNIDのデータベースが壊れていた証拠とのこと。**これを消しても重要なデータは消えないので、実質的な損害はないということです。**  
**ボリュームに対して使用されるCNID（Catalogue Node ID）のバックエンドを指定します。AFPでは、ファイルやボリュームをその名前ではなくIDで参照します。従って、NetatalkはこれらのIDを記録しなければなりません。そのために、様々なCNIDバックエンドが用意されています。**  
- cdb  
並列データベースになります。複数のafpdデーモンが直接CNIDデータベースにアクセスします。1つのデーモンがクラッシュすると、データベース全体が破損する恐れがあります。
- dbd  
CNIDデータベースへのアクセスはcnid_metadデーモンに限定されます。つまり、afpdデーモンはこのデーモンと接続し、データベースの情報を操作します。cdbに比べ動作は遅くなりますが、クラッシュの可能性を低く抑えることができます。
- last  
IDは現在のセッションでのみ有効です。CD-ROMを共有するときに便利です。通常はこのバックエンドの使用は推奨されません。


##Problem of Performance using CNID

[ FreeBSD 上に ZFS+netatalk3.1 の環境の参考](http://borg4.vdomains.jp/~goro/diary/2014/2536)
> 
- CNID は SSD とかメモリに置くと快適(メモリに置くのはリスキーだけどな!)
  - CNID 置き場が遅いと afpd の動作は重くなる
- netatalk 3.1 を使うなら spotlight yes のほうが幸せ(のような気がする)  
#####…クラッシュが怖いけど、 tmpfs に CNID 置いて、定期的に HDD にコピーして多少の不整合には目を瞑る、というのが正解なのかなぁ(多分[続く](http://borg4.vdomains.jp/~goro/diary/2014/2573))

[その続き](http://borg4.vdomains.jp/~goro/diary/2014/2573)
> 
CNID を tmpfs に置けばそれなりのスピードになるよねってのは分ったので、そこを自動化するだけの話ですが。  
netatalk が起動する前に tmpfs に CNID が準備されてて、 netatalk が終了した時に tmpfs に置いた CNID が real fs にコピーされてればいいだろうという方針で Practical rc.d scripting in BSD を読みながら /usr/local/etc/rc.d/netatalk を編集してみました。  
更に続きは[こちら(netatalk 3.1 が遅いのをお金の力で解決した)](http://borg4.vdomains.jp/~goro/diary/2014/2573)

[netatalk パフォーマンスチューニング(ver2.2.2, BerkleyDB)](http://blog.keshi.org/hogememo/2013/01/03/netatalk-performance-tuning)
> 
####問題
これまで HP MicroServer で運用してきた netatalk 2.2.2 の AFP ボリュームでは、 iPhoto や Aperture のフォトライブラリを置いて使うととにかく遅くて話にならないということが問題になっており、今回のストレージ更新ではこれの改善が目標のひとつです。  
調べてみると netatalk の cnid_dbd というデーモンプロセスがボトルネックとなっているらしいことがわかります。このデーモンは AFP ボリュームの全ファイル・ディレクトリに CNID という一意の数値を割り当てるため、 Berkeley DB の環境を各 AFP ボリュームの .AppleDB というディレクトリに作り、ファイル・ディレクトリの更新があると同時にこの DB も更新しているのでした。  
小さなファイル・ディレクトリが多くメタデータの更新が大量にあるようなワークロードでは、本来のファイル・ディレクトリ更新の間に cnid_dbd の fdatasync() が挟まることになります。  
#####***AFP ボリュームと CNID DB が同じデバイスに存在する場合、これはひどいパフォーマンスの低下をもたらします。そこでこれらを異なるデバイスに分離するだけで、相当な速度改善が望めるのではと考え、実験してみました。***  
####まとめ
#####**netatalk において AFP ボリュームと CNID DB (```.AppleDB``` ディレクトリ) を別デバイスに分けることでメタデータ更新性能が大きく向上することがわかりました。**  
CNID DB を tmpfs (RAM ディスク) に置くと非常に高速になりますが、システムが再起動したときに消えてしまうので、現実的には ```/var``` のような普通のストレージに割り当てることになるでしょう。ここを SSD にするといいかもしれまえせん。  
netatalk 2.2 までではデフォルトで AFP ボリュームと同じ場所に CNID DB を作ってしまいます。 マニュアル の例にもありますが AppleVolumes のデフォルト設定として次のように dbpath を指定するのがよいでしょう。  
```
:DEFAULT: options:upriv,usedots dbpath:/var/lib/netatalk/CNID/$v dperm:0775 fperm:0664
```
netatalk 3.0 以降のデフォルトでは CNID DB を```:STATEDIR:/netatalk/CNID/$v/``` に作成する設定 (vol dbpath) になっていますので、特になにもする必要はないようです。バイナリパッケージではビルドの設定を確認してください。  
バックエンドのファイルシステムとして XFS と EXT4 を試しましたが、それぞれが評判通りの特性を示す結果となりました。  
どちらを使うべきかはなかなか悩ましい選択といえます。動画など 10MB 単位のファイルのみであれば迷わず XFS ですが、大量の小さなファイルを大量に扱う必要があるならば、多少の I/O スループットを犠牲にしてでも EXT4 のメタデータ更新性能をとるべきかもしれません。  
OSX ではアプリケーションがパッケージやバンドルのようなデータ形式 (実体はただのディレクトリとファイル) をよく作るため、そのようなケースに該当することもあるのではないでしょうか。  

| /  | I/O Write | I/O Read |メタデータ更新性能|
|----|-----------|----------|---------------- |
|XFS |高い|高い|非常に低い|
|EXT4|そこそこ|高い|非常に高い|

###When nesting volumes
ボリュームのパスをネストすると、CNIDデータベースが競合して以上が発生する。  
```cnid scheme = last```のオプションにより競合せずに済む。  
また、```vol dbnest = yes```のオプション設定でも良い（こちらの方が一発で書けて楽）
```
[Global]
  vol dbnest = yes
```
[参考(ボリュームのネストに注意)](http://www003.upp.so-net.ne.jp/hat/netatalk/andsamba.html)