棚からパルチャギ

日々の雑記、ニュース拾いとか

2008. 12. 15

openpear/Net_Q4M

Q4MのPHPインターフェースラッパを書いたのでopenpear.orgで公開してみました。

基本的な使い方はこんな感じで。

$queue = new Net_Q4M(); $queue->connect('mysql://user:pass@localhost:3306/database'); $row = $queue->dequeue('my_queue'); if (process_row($row)) { $queue->end(); } else { $queue->abort(); } $queue->disconnect();
dequeue()を呼ぶとキューのレコード情報が返ります。 内部的にはqueue_wait()を発行しているので、取得したキューの値はこの接続のみが扱えることになります(OWNERモード)。

キューの値は配列で返るので適当に処理します(上のサンプルだとprocess_row()のところ)。 処理に成功した場合はend()を呼ぶことでキューから値を削除します。 逆に失敗した場合はabort()を呼ぶと値はキューに戻され、他の接続からも参照可能になります。

取得したキューの値はend()が呼ばれるか次のdequeue()が呼ばれた時点で削除されます。 また、end()もabort()も呼ばれないまま切断された場合は、取得した値はキューに戻ります。

// キューへの接続 $queue->connect('mysql://user:pass@localhost:3306/database'); $queue->connect('mysqli://user:pass@localhost:3306/database'); $queue->connect('pdo_mysql://user:pass@localhost:3306/database');
接続にはPEAR::DBと同様の書式のDSNを指定します。
phptypeにはmysql/mysqli/PDO(mysql)の3種類が指定可能です。

// キューから値を取得 $queue->dequeue('my_queue', 5); $queue->dequeue('my_queue', 'my_queue2', 'my_queue3', 10);
dequeue()を発行してもキューに値がない場合、値がinsertされるまで一定時間待機します。 このタイムアウト時間はdequeue()の最後の引数で指定します。デフォルトは10秒間待機します。

また、Q4Mでは取得先のキューを優先度順に複数指定する事が可能です。 この場合はdequeue()の引数に取得先のキュー(テーブル名)を優先度の高い順に指定します。 キューを複数指定する場合、タイムアウト時間を省略することはできません。

// キューに取得条件を指定 $queue->dequeue('my_queue:id=1000'); $queue->dequeue('my_queue:score<30');
キューに取得条件を付加する場合は、テーブル名の後ろに「:」で条件式を繋いで記述します。 条件指定には様々な演算子が使用できるので詳しくはQ4Mのドキュメントを参照してください。

// キューに値を追加 $data = array( 'user_id' => 1000, 'message' => 'Hello!' ); $queue->enqueue('my_queue', $data);
キューに値を追加するときはenqueue()を使用します。
テーブルのカラムに対応したキーと値を保持する連想配列を引数に渡して実行します。

// キューの状態を取得する $result = $queue->status(); var_dump($result);
status()を呼ぶとキューの状態を保持する配列が返ります。 SHOW ENGINE QUEUE STATUS; の実行結果で得られる情報を連想配列化したもので、Queue::Q4M::Statusを見てなるほどなーと思って真似してしまいました。

ということで、リポジトリは誰でも編集可能なはずなので適当に弄ってあげてください。

2008. 12. 14

MacBookにQ4Mをインストールしたメモ書きの補足
make test について省略したので追記。
というか長くなったので別エントリにしてみた。DBD::mysql入れるのが面倒だった。。。
$ sudo cpan cpan> install Data::Compare cpan> install DBD::mysql
DBD::mysqlのビルドは失敗するので、LeopardにMySQLとDBD::mysqlを入れる方法を参考にmakeしなおす。
$ sudo ln -s /opt/local/lib/mysql5/bin/mysql_config /usr/local/bin/mysql_config $ sudo su - # cd /var/root/.cpan # cd build/DBD-mysql-XXXXXXXX # perl Makefile.PL \ --cflags=-I/opt/local/include/mysql5/mysql \ --libs="-L/opt/local/lib -L/opt/local/lib/mysql5/mysql -lmysqlclient -L/opt/local/lib -lz -lm -L/opt/local/lib -lssl -lcrypto" # make # make install
自分の環境だけかもしれないけど、/opt/local/bin/perl と /usr/local/bin/perl がどちらも入っていて後者だと@INCが違うところを参照してしまうので、テストスクリプトのperlパスを修正する。
$ cd /usr/local/src/q4m-0.8.3 $ vi run_tests.pl - #!/usr/local/bin/perl + #!/opt/local/bin/perl
make test する。
$ DBI='dbi:mysql:database=test;host=localhost' \ DBI_USER='username' \ DBI_PASSWORD='password' \ MYSQL_UNIX_PORT=/opt/local/var/run/mysql5/mysqld.sock \ make test ... Multireader benchmark result: Number of messages: 6400 Number of readers: 32 Elapsed: 25.878 seconds Throughput: 247.315 mess./sec. ... Multi-reader-writer benchmark result: Number of messages: 6400 Number of readers: 32 Elapsed: 43.944 seconds Throughput: 145.641 mess./sec. ... Multi-reader-writer benchmark result under semi-starvation: Number of messages: 6400 Number of readers: 32 Elapsed: 96.602 seconds Throughput: 66.251 mess./sec. ... All tests successful. Files=17, Tests=68921, 2240 wallclock secs (20.83 usr 2.26 sys + 150.25 cusr 22.16 csys = 195.50 CPU) Result: PASS
ちなみに、上のは--with-sync=fcntlの場合のベンチマーク(Cure2Duo 2.1GHz/Mem 4GB)。
--with-sync=fsyncにした場合はこんな感じ↓
... Multireader benchmark result: Number of messages: 6400 Number of readers: 32 Elapsed: 1.725 seconds Throughput: 3711.007 mess./sec. ... Multi-reader-writer benchmark result: Number of messages: 6400 Number of readers: 32 Elapsed: 2.724 seconds Throughput: 2349.228 mess./sec. ... Multi-reader-writer benchmark result under semi-starvation: Number of messages: 6400 Number of readers: 32 Elapsed: 3.445 seconds Throughput: 1857.784 mess./sec. ... All tests successful. Files=17, Tests=68921, 289 wallclock secs (17.33 usr 2.06 sys + 144.66 cusr 20.77 csys = 184.82 CPU)
10倍以上速いよ!! この辺の話なのかな。
試験環境なのでデータ飛んでも困らないし、当面はfsyncのままでいいような気がする。
MacBookにQ4Mをインストールした

…ので、そのメモ書き。
http://q4m.31tools.com/

MySQL5.1をインストールする
5.1系はまだdevelにしかないので、5.0系をインストールしている場合はdeactivateする。 データベースの初期化とかパスワードの設定とか自動起動とかの諸々は割愛。

$ sudo port deactivate mysql5 $ sudo port install mysql5-devel +server

Q4Mをダウンロードしてビルドしてみる。

$ cd /ur/local/src $ wget http://q4m.31tools.com/dist/q4m-0.8.3.tar.gz $ tar -zxf q4m-0.8.3.tar.gz $ cd q4m-0.8.3 $ ./configure --prefix=/opt/local/lib/mysql5/mysql --includedir=/opt/local/include ... checking for mysql source code... configure: error: "no mysql source provided"

MySQL本体のソースが必要みたいなので用意する。
MacPortsのソースはビルド完了後に削除されてしまうので、別途ダウンロードして展開しておく。

$ cd /usr/local/src $ wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.30.tar.gz/from/http://ftp.iij.ad.jp/pub/db/mysql/ $ tar -zxf mysql-5.1.30.tar.gz

再挑戦。

$ cd /usr/local/src/q4m-0.8.3 $ ./configure --prefix=/opt/local/lib/mysql5/mysql \ --with-mysql=/usr/local/src/mysql-5.1.30 \ --includedir=/opt/local/include ... checking for mysql source code... "/usr/local/src/mysql-5.1.30" failed to lacate mysql 5.1 installation Please specify mysql 5.1 directory with --prefix option.

ライブラリヘッダのパスが解決できないみたいので、prefixを変更してインストール後に調整することに。 それだけだと微妙に通らないのでシンボリックリンクも使ってちょっと強引に回避する。

$ cd /opt/local/include $ sudo ln -s mysql5/mysql mysql $ $ cd /usr/local/src/q4m-0.8.3 $ ./configure --prefix=/opt/local \ --with-mysql=/usr/local/src/mysql-5.1.30 \ --includedir=/opt/local/include

configureは通ったのでmake。こける。
boostが必要とかヘッダフィルが読み込めないとかライブラリがどうとかいろいろ怒られるので頑張る。 CPPFLAGSとかには mysql_config -libs の出力結果を参考に指定するといいらしい。

/opt/local/lib/mysql5/bin/mysql_config -libs
boostをインストールしてビルド。--with-syncも追加した。
$ sudo port install boost $ $ CPPFLAGS="-I/opt/local/include/mysql5/mysql -I/usr/local/src/mysql-5.1.30/sql -I/opt/local/include" \ LDFLAGS="-L/opt/local/lib -L/opt/local/lib/mysql5/mysql -lmysqlclient -L/opt/local/lib -lz -lm -L/opt/local/lib/ -lssl -lcrypto" \ ./configure --prefix=/opt/local \ --with-mysql=/usr/local/src/mysql-5.1.30 \ --with-sync=fsync $ $ make

正常にビルド完了したら、MySQLにプラグインをインストールする。
prefixを変更していたのでちょこっと調整してからインストールスクリプトを実行。

$ sudo make install $ $ cd /opt/local/lib/mysql5/mysql/plugin $ sudo ln -s /opt/local/lib/libqueue_engine.so libqueue_engine.so $ sudo ln -s /opt/local/lib/libqueue_engine.la libqueue_engine.la $ sudo ln -s /opt/local/lib/libqueue_engine.a libqueue_engine.a $ $ cd /usr/local/src/q4m-0.8.3 $ mysql5 -u root -p mysql < support-files/install.sql

動作確認してみる。

$ mysql5 -u root -p mysql mysql> SHOW ENGINE QUEUE STATUS;
おしまい。

2008. 10. 21

drawrのイラストをあとで見るようにクリップするGreasemonkey書いた
こんなの。

drawrの新着を辿りながらげしげしタブを開いていたら、タブの数が大変なことになったよ!という人向け。

とりあえず何も考えずに気になったイラストをどんどん放り込んで、あとでまとめて見るような使い方してます。 調子に乗って新着辿ってたら300件以上溜まってしまったので、それはそれで困った。。。
拡張マイリスト (0.9.2)
Pager部分のスタイルが変更になっていて表示が崩れていたので修正。
SeaHorse版も併せて更新。 最近はあまりニコニコしていない。

2008. 10. 03

拡張マイリスト (0.9.1)
ということで、ネタがあったので更新したわけですがニコニコ動画(秋)対応です。
今回は結構デザインが変わっていたので微妙に面倒だったというか、 id属性が削除されていたりとかレイアウト的に結構キツキツだったりとかで、なかなかグリモン泣かせの改変でした。

10/1更新分の0.9.0からちょっと表示の調整が入っています。ちょっぴり忘れていたんですが、要望いただいたのでSeaHorse版も。スクリーンショットがRC2のままですねー。

2008. 03. 17

SeaHorse版 拡張マイリスト (0.8.1_sh)
flvplayer_wrapperと併用すると登録に失敗するとの報告をもらったので修正。

動画タイトルの取得に失敗すると登録されないというのは以前にもあって、タイトル部分のHTMLを書き換えてしまうような仕組みがあると共存が難しかったりします。 この手の機能を作る場合は、あまり元の構造を崩さないように作ってもらえると嬉しいかもですね。 あと、たまに登録ボタンが複数表示されることがあったので、ついでに修正しています。
SeaHorse版 拡張マイリスト
SleipnirのSeaHorseが、Greasemonkeyとどの程度互換性があるのか気になったので、需要無視で作ってみたりとか。 簡単な動作検証していないので、一応人柱版ということで。

SeaHorse(SleipnirScript?)では、画像の読み込み完了までスクリプトが実行されないので、 ニコニコ動画のように画像数が多い場合は、なかなかリストが表示されないかもしれないです。 データはSQLiteのデータベースとして保存されるので、コピーするだけで他の環境に移動できるのはGreasemonkey版よりも便利。

SeaHorse用に変更が必要なところはGM_setValue()なんかの専用処理だけで、 基本的にはクロスブラウザを意識していなかったJavaScriptコードを修正するのがメインだった気がします。 Firefoxの恵まれた環境に比べると、IEでの開発やデバッグはいろいろと面倒ですねー。
Greasemonkey→SeaHorse移植時の変更点
とりあえず変更したところをメモ。
SeaHorseに合わせたというよりも、Internet Explorerで動作することを考慮しなさすぎバカスという感じでした。


1. Object のプロパティ列挙で、最後に「,」つけてるとNG
var Hoge = { foo = 1, bar = 'fuga', // ←最後に「,」があるとNG }

2. イベントハンドラの設定方法を変更
attachEvent()を使用する。第一引数も微妙に違うのでたまに忘れる。
- obj.addEventListener("click", onClinkHandler, false); + obj.attachEvent("onclick", onClinkHandler);

3. setAttribute()で設定できないプロパティがある
「.」でアクセスする。classとかstyleとかcolspanとか。
- obj.setAttribute('class', 'hoge'); - obj.setAttribute('style', 'border:none; color:red'); - obj.setAttribute('colspan', '4'); + obj.className = 'hoge'; + obj.style.cssText = 'border:none; color:red'; + obj.colSpan = 4;

4. イベントハンドラでthisが参照できない
applyとか使う。thisで参照したいobjectをローカル変数に保存してから渡してもいいみたい。

5. toSource() が使えない
シリアライズを実装する必要がある。 CodeReposのObject.toSourceとか、 小飼弾氏のunevalとかを参考にしてみる。 後者は複数行のstringに非対応っぽいので、ちょっと修正が必要。こんなのでいいのかな。
var name2uneval = { 'boolean':uneval_asis, 'number': uneval_asis, 'string': function(o){ return '\'' + o.toString().replace(/[\\\"\']/gm, function(m0){ return '\\' + m0; }).replace(/\r\n|\n/gm, "\\n") + '\''; }, 'undefined': function(o){ return 'undefined' }, 'function':uneval_asis };

6. document.evaluate() が使えない
XPathで検索できないので別の方法で頑張る。 JavaScript-XPathという手段も。

7. メモリリークする
「IE 循環参照 メモリリーク」とかで検索すると結構ヒットする問題。 一晩放置するとメモリ消費量が1GB超えたりとか大変なことになっていたので、いろいろと対応。 ほとんどリークしないようにはしたつもり。

8. windowオブジェクトは暗黙のthisとして存在しないので明記する
window.setInterval(...);

9. Greasemonkey API
GM_setValue/GM_getValue しか使っていないのでSQLiteでなんとかなるかなーと思っていたら、 既にAPI一式のラッパーライブラリを作っている方が。 互換性は微妙とは書いてあるけど、GM_setValue/GM_getValueについては今のところ問題なし。一番使われてそうなGM_xmlhttpRequestはどうなんだろう。

10. ファイルのエンコードはShift JIS
コメントや文字列に日本語を使っている場合は注意。

  [ 1 | 2 | 3 | 4 | 5 | 6 ]