2009-03-24 7 views
10

私はSQLiteデータベースを扱う2つ以上のプロセスを持っているとしましょう。 "プレーヤ"プロセスと多くの "エディタ"プロセスです。異なるプロセスでSQLiteデータベースの変更をプロセスに通知するにはどうすればよいですか?

"player"プロセスはデータベースを読み込んでビューを更新します - 私の場合、データベースに格納されたイベントに応じて波形がサウンドカードにミックスされます。

「エディタ」プロセスは、そのデータベースのエディタです。データベースを常に変更します。

これで、プレイヤーに編集の変更をすばやく反映させたいと思います。

SQLiteは同じプロセス内でデータベースの変更を追跡するためのフックを提供していますが、複数のプロセスでこれを行う方法についてはほとんど情報がないようです。

データベースを常にポーリングしてレコードとトリガーイベントを比較することはできますが、特にデータベースが大きくなった場合は非常に非効率的です。

私はログテーブルとトリガーを使用することを考えていますが、もっと簡単な方法があるのだろうかと思います。

答えて

6

リレーショナルデータベースはこれにとって最善の方法ではありません。

なぜですか?

すべての編集者にあなたのプレーヤーに変更を渡したいと思っています。

あなたのプレイヤーは、すべての編集者のサーバーです。あなたのプレイヤーは複数のオープンな接続を必要とします。変更のためにすべての接続を聴かなければなりません。これらの変更を表示する必要があります。

変更が実際に大きい場合、編集者が変更を永続させるハイブリッドソリューションに移動することができます。がプレーヤに通知します。

いずれにしても、編集者は変更があったことをプレーヤーに通知する必要があります。これは、プレーヤーがデータベース内の変更を発見しようとするよりずっと簡単です。


より良い設計とは、エディタからのメッセージを受け取り、それを維持し、プレーヤに通知するサーバです。このサーバーはエディターでもプレーヤーでもなく、すべてのメッセージが処理されることを保証するブローカーです。編集者やプレイヤーからの接続を受け入れます。データベースを管理します。

2つの実装があります。サーバーはプレーヤーです。サーバーはプレーヤーとは別です。サーバーの設計は変更されず、プロトコルのみが変更されます。サーバーがプレーヤーの場合、サーバーはプレーヤーオブジェクトを直接呼び出します。サーバーがプレーヤーとは別の場合、サーバーはプレーヤーのソケットに書き込みます。

プレイヤーがサーバーの一部である場合、プレーヤーオブジェクトは、エディターからメッセージを受け取ったときに直接呼び出されます。プレーヤーが別の場合、小さなリーダーがソケットからメッセージを収集し、プレーヤーオブジェクトを呼び出します。

プレーヤーはサーバーに接続し、情報の流れを待ちます。これは、エディタから入力するか、またはサーバがデータベース内で保持していたデータへの参照とすることができます。

ネットワークの待ち時間が問題にならないようにメッセージのトラフィックが十分小さい場合、エディタはすべてのデータをサーバー/プレーヤーに送信します。メッセージトラフィックが大きすぎる場合、エディタはデータベースに書き込み、データベースFKだけのメッセージをサーバ/プレーヤに送信します。


「通知中にエディタがクラッシュすると、プレイヤーは永久に台無しになっています。

これは、プレイヤーサービスのデザインが悪いようです。それは、それが様々なエディタから状態を取得していない限り、 "永久に混乱"することはできません。エディターからステートが取得されている場合(たとえば、その状態を反映しようとしている場合)、プレーヤーはエディターから状態を取得し、「永久に台無し」にならないようなデザインを検討する必要があります。

+0

アイデアは、変更が失われないように強く永続的なデータ設計を行うことでした。私はすべてのプロセスをデータベースの周りに中央ハブとして配置することを想像しました。通知なしでデータベースが変更された場合、プレイヤーは再起動されるまでリフレッシュされません。あなたのアイデアは面白く聞こえる – paniq

+0

"リレーショナルデータベースはこれにとって最善の選択肢ではありません。" - 私の最善の選択肢は何でしょう? – paniq

+0

あなたの編集は、さまざまな投稿の私の理解から現れたものに近くなります。どうもありがとうございました。 – paniq

2

2つのプロセスの間でソケットを開き、エディタにすべてのプレイヤーに更新について伝えるようにしてください。

+0

私もそれについて考えていました。しかし、それは多くの編集者とただ1人のプレイヤーです。彼らはそれぞれ接続を維持しなければならないだけでなく(ある種のXMLRPCがうまくいくと思います)、通知自体は信頼できません。通知中にエディタがクラッシュした場合、プレイヤーは永久に台無しになります。 – paniq

+0

@paniq、私はあなたがSQLiteは複数のupdaterでうまく動かないことが分かるでしょう。更新時にテーブル全体をロックする傾向があり、デッドロックが発生する可能性があります。 –

+0

@Paul Tomblin:SQLiteはファイルレベルでロックします。これは通常データベース全体です。これはデッドロックを回避しますが、遅くなる可能性があります。 http://www.sqlite.org/lockingv3.html –

1

編集:私は同じマシン上でプロセスをasumingしています。

私の意見では、2つの方法があります(あなたが述べたように)

  • はポーリングが、(ちょうど他のテーブルのLastUpdateTimeを保持し、テーブルのような)単一の値に保つ

  • ターゲットプラットフォームで利用可能なプロセス間通信を使用します。これは、Windowsでのイベント(たとえば、C#(私はPythonについてはわかりません)ではManualResetEvent、AutoResetEvent、または各プロセスでウェイタースレッドを犠牲にしたい場合はMutex)、LinuxではSignalsです。

1

同じマシン上にある場合、最も簡単な方法は、DBを変更するたびにパイプにトークンを入れるread()と "editors"をブロックする "player"という名前のパイプを持つことです。

+0

これは、複数のエディタで自分のアイデアを上回る素晴らしい改善です - シングルプレイヤー環境。 –

+0

実際にあなたのアイデアは、その環境でも動作します - プレイヤーはポートとエディタを聴いてそのポートに接続して通知します。私はそれが最も簡単なIPCだからパイプを言った。 – vartec

1

いくつのエディタプロセス(プロセスが必要なのか)、および更新頻度はどれくらいですか?これは良いデザインのようには思えません。特にsqliteが実際にはではないと思っていない人もいます。は、データベースへの複数の同時アクセスがうれしいです。

もし複数のプロセスは、おそらくエディタがソケット、パイプ、共有メモリなどを介してプレーヤーを通知し、その後、プレイヤー(別名、サーバー・プロセス)が持つように賢くなり、あなたが永続化をしたい意味を行い、永続化しなさい。

+0

なぜプロセス:これはすべてPythonなので、GILはマルチコアCPUを効率的に使用できないようにします。今、オーディオスレッドはUIを停止させます。私はまた、エディタに問題がある場合、オーディオを分解したくない。 – paniq

+0

私はview(player)と永続的なモデルを完全に分離したいと思っていましたが、あなたの解決策もOKです。私はまだプレイヤーとエディターを同期させる中央の "db i/o"プロセスを持つことができます。 – paniq

2

私はこの場合、データベースの読み書きを管理するプロセスをとると思います。

データベースに何らかの変更を加えたい各エディタは、このプロセスへの呼び出しを行います.IPCやネットワークなどの方法で呼び出します。

このプロセスは、データベースの変更をプレーヤーに通知できます。プレイヤーは、何らかのデータを取得する必要がある場合、データベースを管理するプロセスに必要なデータを要求する必要があります。 (または、dbプロセスが変更を通知したときに、必要な情報をDBプロセスに通知する)

これを実行すると、SQLite DBにアクセスするプロセスが1つしかないという利点があります。データベースの並行性の問題

+0

あなたは遅すぎます;)でも、それは最良のアプローチのように聞こえます。 – paniq

3

SQLiteには、あなたが望むように機能するupdate_hookがあります。

SQLiteのCインタフェース

データ変更通知コールバック

void *sqlite3_update_hook(
    sqlite3*, 
    void(*)(void *,int ,char const *,char const *,sqlite3_int64), 
    void* 
); 

sqlite3_update_hook()インタフェースは たびに呼び出される最初の引数によって識別 データベース接続にコールバック関数を登録します行は、ROWID表で更新、挿入、または削除されます。任意の 同じデータベース 接続のこの関数への以前の呼び出しによってコールバックがオーバーライドされます。

残念ながら、それはPython sqliteのモジュールによって公開されていません...ここで

は、それを利用するために(Pythonコードから)CのAPIに食い込む少しハック回避策です: https://stackoverflow.com/a/16920926

+0

これは、最初の引数で渡したのと同じデータベース接続でトリガされた変更に対してのみ機能します。だからマルチプロセスではありません。 – pcworld

+0

良い点。これはsqliteの動作に適しています:_複数のプロセスが同時にSELECTを実行することができます。しかし、1つのプロセスだけがいつでもデータベースに変更を加えることができます._これは、OPがDB接続を保持する単一のプロセスを必要とすることを示唆しています。 'エディタ'プロセスと 'プレーヤー'プロセスは、 – Anentropic

関連する問題