データ収集系で使われるデータベースを考えてみましょう。VMSではデータ ベース機能の一部をロジカルネームという機能が担っていました。OS自身の持 つ機能で、プロセス間で共有できる辞書のようなものです。UNIXの場合、それ に該当する機能はOSには備わっていません。シンボリックリンクはその一部を 肩代わりしていますが十分ではありません。(ファイル名の置き換えのみをやっ てくれると言う意味で。)別に環境変数という概念はありますが、これはプロ セスの中でだけ有効です。
現在のデータ収集システムを考えるとロジカルネームだけでも不十分です。 実際にデータ収集システムはネットワークに分散しています。一つのホストの 上でデータベースを変更しても他の機械にそれが反映しないのでは困ります。 このようにネットワークに広がっているすべてのDAQプロセスに見え、変更が 同時にすべての機械に反映するというデータベースを導入する必要があります。
このような全く汎用のネットワーク分散データベースで、オンラインの使用 に耐える高速応答が出来るものは設計するとしても非常に難しいでしょう。幸 い、DAQシステムではそのように汎用性を要求されません。データベースの項 目毎にどのプロセスが変更を行い、どのプロセスが参照するという関係はよく 定まっており、かつ常にほぼ同じです。また、データベースにある項目の数も それほど多くなく、あらかじめ定義されていて、動的に定義したり廃棄したり することはそれほど多くありません。こういった特徴を捉えてデータベースを 設計することはそれほど難しいことではありません。
データベース設計の実際を見ていきましょう。まずデータベースを参照する プロセスですが、項目はあらかじめ決まっています。そして参照するタイミン グはデータベースそのものから通知されるのではなく、別の機構によって与え られます。それゆえデータベースの参照は無同期で行えます。まず考えつく手 法は共有メモリーです。参照するプロセスはまず共有メモリーを開き、該当す る項目のデータへのポインターを受け取るとあとはその内容を読むのはいつで も自由です。
更新するプロセスを考えましょう。参照するプロセスは単に共有メモリーを 読むだけですから、単一の計算機だけで走らせるシステムでは更新する側も共 有メモリーに書くだけで良くなります。ネットワーク分散の場合それぞれの機 械の共有メモリーは基本的に独立ですから、ネットワークを通してデータのコ ピーをするか、すべての計算機で同時に更新する必要が出てきます。このこと を考慮するとデーモンをそれぞれで走らせて相互に通信させる必要がわかりま す。実装にはソケット通信が利用できます。
例えば次のような設計が思い浮かびます。まずマスターサーバを決め、その うえにデータベース管理デーモンを走らせます。これをマスターデーモンと呼 びましょう。マスターサーバ以外の機械ではマスターの指示に従ってデータベー スを更新したり確認したりするスレーブデーモンを走らせます。データベース を更新するプロセスはマスターデーモンに更新要求を伝えます。マスターデー モンはそのメッセージをソケットで接続されたすべてのスレーブデーモンに通 知します。それぞれのデーモンはメッセージに従って共有メモリー上のデータ ベースを更新します。場合によってはデータベースの内容を比較したりコピー したりする機能もマスターとスレーブの間で決めておいてやれば、より信頼性 の高いシステムも可能です。更新メッセージが一カ所に集中するので、例えば マスターデーモンが更新履歴を記録すると言ったことも可能です。
これはあくまでも一例です。マスターやスレーブの代わりにUDPを受け取る サーバをすべての機械に走らせ、更新プロセスはブロードキャストで更新メッ セージをばらまくと言った設計も可能です。TCPソケットを張った方が相手が 存在するかどうか、TCPコネクションが落ちたかどうかなどを確認しながら運 用できますから、より強靭なシステムが構築できるでしょう。
データベースが実装できるとその管理や保守のためのコマンドも用意しましょ う。シェルの中でバッククォートでコマンドを呼び出して使えばほぼVMSのロ ジカルネームのような使い方も可能です。
(演習問題) ネットワークに分散するデータベースを設計する。項目は名前で参照され、内容は文字 列とする。数値も文字列にして記憶する。 まず参照のための関数を用意する int odb_open( ) データベースへの接続 int odb_close( ) 終了 char * odb_get( char * item ) 項目itemに該当する文字列を返す なければNULLを返す 更新のための関数を用意する int odb_uopen( char * master ) 接続 int odb_uclose( ) 切断 int odb_set( char * item, char * val ) 項目itemの値をvalにセットする int odb_init( ) データベースの全初期化 int odb_save( char * file ) データベースの保存 int odb_load( char * file ) データベースの復元 int odb_remove( char * item ) 項目itemの削除 これらの関数を用いて次のコマンドを用意する odb_get item 標準出力にitemの値を出力 odb_set item val itemをvalにセット