キャッシュが危険
moshはAuto Compile Cacheとして、コンパイラを通したバイトコードをキャッシュする仕組みがある。
しかし、これは十分にデザインされていないので、間違ったスクリプトをキャッシュしたり、キャッシュが破損していたり(チェックサムもない)することがたまにある。(多分ypsilonも同じ問題があるだろう)
特に僕は結構大規模にmoshを使っている(〜16 core x2 node)ので、キャッシュを無効にした特製moshを作って実験してみたところ結構結果が違うことが解った。不味い。
悪いことに、僕が作るR6RSのプログラムやライブラリは、R6RSのライブラリ機構に結構依存しているのでこの問題を拡大してしまう。
前提 : ユニークな識別子を導入する
一般に、ファイル名をユニークな識別子として利用してはいけない。利用しても良いケースは非常に限られている。少なくとも/usr/local/share/mosh/VER/hoge.scmは世界で唯一ではない。
例えば、Firefoxのようなブラウザはプロファイル毎にユニークな識別子を定め、識別子ごとにプロセスを一つに限っている。
解決策 A. ファイル名はランダムにして、後からリネームする
本来、同じファイルに書くのを避け、更に書き込みの完了が正当であることを保証するにはrenameのようなアトミックなファイル操作を使うしかない。感覚としては、同期プリミティブの構成にかならずCAS命令のような命令が必要なことに近い。
これはそれなりに上手く働くが、かなり効率が悪い。移植性の無いファイルロックやプリミティブを使うことで改善は出来るが。。
解決策 B. 面倒なのでDBMを使う
DBMはこの手の問題を抽象化する。しかし、移植性に問題がある実装が多い。
解決策 C. 基本的に自動的なキャッシュはしない
少なくとも僕のforkではこの方針にするつもり。どっちにせよyuniは一旦コンパイルする必要があるのでワークフローは変わらない。
自動的なキャッシュをしたければ、何か一つプロセスを常駐させる以外に上手い方法は無いように思える。
他の言語
多くの言語実装は、このようなキャッシュを持たないか、明示的なコンパイルプロセスを持つ。
Pythonはmoshと同様のストラテジを持つが、ネイティブに排他オープンを実装している。NFS上ではO_EXCLが働くとは限らないので何か間違ったことが起こる可能性がある。
static FILE * open_exclusive(char *filename, mode_t mode) { #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC) /* Use O_EXCL to avoid a race condition when another process tries to write the same file. When that happens, our open() call fails, which is just fine (since it's only a cache). XXX If the file exists and is writable but the directory is not writable, the file will never be written. Oh well. */ int fd; (void) unlink(filename); fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC #ifdef O_BINARY |O_BINARY /* necessary for Windows */ #endif #ifdef __VMS , mode, "ctxt=bin", "shr=nil" #else , mode #endif