Hatena::ブログ(Diary)

kazuhoのメモ置き場

2010-01-14

Perlでマルチプロセスデーモンを作るためのモジュール「Parallel::Prefork」に(Min|Max)SpareServers対応を追加した話 (もしくは read(2) / write(2) の atomicity)

Perl で複数のワーカープロセスを制御するためのモジュールとしては Parallel::ForkManager が古参なんだけど、このモジュールプロセスを fork するだけで、シグナルを受信したらワーカープロセス再起動とかそういうことができないので、自分は Parallel::Prefork というモジュールを自作して、たとえば Plack の Server::Standalone::Prefork とかで使っています。

で、まあ、prefork なサーバとか書いてると、(Min|Max)SpareServers 対応してないんすか? というのは FAQ なわけで。プロのサーバ管理者の間では存在価値が疑問視されて久しい (Min|Max)SpareServers だと思うんですが、まあ書いてみるのもいいかと思って Parallel::Prefork のディストリビューションParallel::Prefork::SpareWorkers という (Min|Max)SpareServers 対応のクラスを追加しました。

作った理由はもうひとつあって、応答がなくなったワーカーを自動的に kill したり、スコアボードで処理状況を可視化したり、とかそういったこともできたらいいかな、みたいな。

閑話休題。でまあ、ワーカープロセス群の状態を管理しようと思うとスコアボードが必要になります。これをどう実現するか。C なら mmap + lock-free algorithm による読み書き、とかが楽だと思うんですけど、XS (Perl の C 拡張) 書くの面倒だし。現状は、各プロセス毎に1バイトしか (lock なしで) 読み書きしないので、race condition は問題にならないんですが、処理状況の可視化とかやり始めると、競合のこと考えないといけないし、どうしようかな...

というのが、

複数のプロセスが単一のファイルを同時に read / write をする場合、それぞれのオペレーションはアトミックなんでしょうか? (on linux or unix)

Kazuho Okuさんのツイート: "複数のプロセスが単一のファイルを同時に read / write をする場合、それぞれのオペレーションはアトミックなんでしょうか? (on linux or unix)"

twitter で相談した背景。で、knu さんに、ずばり、

@kazuho POSIX.1-2008では、通常ファイルについてはread(2)/write(2)ともアトミックだとあります。

Akinori MUSHAさんのツイート: "@kazuho POSIX.1-2008では、通常ファイルについてはread(2)/write(2)ともアトミックだとあります。"

と教えていただきました。ありがとうございます (他に返答をいただいた方々もありがとうございます)。

もうちょっと古い判から引用しておくと、

I/O is intended to be atomic to ordinary files and pipes and FIFOs. Atomic means that all the bytes from a single operation that started out together end up together, without interleaving from other I/O operations.

read

というわけで、普通に read(2) / write(2) (perl では sysread / syswrite) を使ってスコアボードを作れば、ロックとか気にしなくてもいいみたい。

@kazuho read/writeがアトミックでも、意図したバイト数を一発でread/writeする方法はないのでは?例えば、signalで割り込まれたり、バッファが足りなかったりすると、途中でsystem callやめて実際のread/writeバイト数を返す仕様ですよね。

Keiichi Koyamaさんのツイート: "@kazuho read/writeがアトミックでも、意図したバイト数を一発でread/writeする方法はないのでは?例えば、signalで割り込まれたり、バッファが足りなかったりすると、途中でsystem callやめて実際のread/writeバイト数を返す仕様ですよ

という指摘は一般論としてはその通りだと思いますが、各ワーカープロセスの書き込み位置が固定で複数ページにまたがることがないスコアボードのようなケースでは partial write は発生しないでしょうし、partial read になっちゃった場合は再試行すればいいよね、みたく思っています。

Twitter で反応いただいた方々、ありがとうございました。

sodasoda 2010/01/15 16:20 pipeでもPIPE_BUFを越えたサイズでは駄目だし(RATIONALEにもあります)ファイルでも、NFSv3に対して大きなサイズで書いたりすると駄目なので、この intended to be atomic to ordinary files and pipes and FIFOs って部分は、"意図してたんだけど..." っていう解説に過ぎないのでは?
2008版はこちらです: http://www.opengroup.org/onlinepubs/9699919799/functions/read.html

kazuhookukazuhooku 2010/01/15 17:03 sodaさん、ご指摘ありがとうございます。おっしゃる通りですね。(ロックしない場合は)注意して使うことにしたいと思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/kazuhooku/20100114/1263443654