1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Added HandlerSocket plugin

- Fixed compiler errors
- Modified Makefiles to be part of plugin directory
- Some minor changes in database.cpp to use the new MariaDB handler interface
This commit is contained in:
Michael Widenius
2011-02-20 15:22:10 +02:00
parent 26aa83bfc0
commit 2c7d6f12ee
109 changed files with 21060 additions and 0 deletions

View File

@ -0,0 +1,51 @@
-----------------------------------------------------------------
ソースコードの利用にあたっての免責事項
本ソフトウェアの開発者および株式会社ディー・エヌ・エーは、本フト
ウェアの不稼動、稼動不良を含む法律上の瑕疵担保責任、その他保証責
任を負わないものとします。また、本ソフトウエアの開発者および株式
会社ディー・エヌ・エーは、本ソフトウェアの商品性、またはお客様の
特定の目的に対する適合性について、いかなる保証も負わないものとし
ます。
-----------------------------------------------------------------
handlersocket pluginについて
mysqlサーバに常駐し、innodb等のストレージエンジンへの直接のアクセ
スを提供するプラグインです。handlersocketプラグインは自前のリス
ナーを持ち、専用のクライアントライブラリ(libhsclient)を使ってそれ
にアクセスします。
mysqlの標準クライアントライブラリ(libmysql)を使ったアクセスと比べ
て、以下のような利点があります。
・接続あたりに消費するリソースが少ないため、同時接続数が事実上無
制限。したがって接続数を気にせず持続接続を使えます。
・高速(単純な参照クエリで3倍〜10倍程度)。
・通信プロトコルがコンパクト。libmysqlを使うとデータ転送時にレ
コード名などが付随するために通信内容が冗長ですが、libhsclientで
はデータのみが転送されるため、帯域消費が少なくなります。場合に
よっては10倍以上libmysqlのほうが冗長になります。
現在のバージョンでは以下のような処理をサポートしています。
・指定された索引について、指定された値と完全一致するようなレコー
ドを取得。(SELECT ??? FROM tbl WHERE k1 = v1 AND k2 = v2...)。
索引を使わない検索はサポートしていません。
・指定された索引について、指定された値の位置の前後のレコードを取
得。(SELECT ??? FROM tbl WHERE k1 >= v1 LIMIT 100)
・前述のような手段で取得したレコードに対するUPDATEとDELETE
・レコードのINSERT
以下のような言語をサポートします。
・C++。libhsclientをリンクします。
・Perl。Net::HandlerSocketをuseします。
現在のバージョンではGNU/Linuxでのみ動作します。
-----------------------------------------------------------------
既知の問題
・killでhandlersocketスレッドを殺すと、スレッド数が減ったまま回復
しません。

View File

@ -0,0 +1,87 @@
-----------------------------------------------------------------
HandlerSocketプラグインのビルド方法(RPMを使わない方法)
以下のようにしてconfigureを実行します。
$ ./autogen.sh
$ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
ここで--with-mysql-sourceにはMySQLのソースコードのトップディレク
トリを指定します。--with-mysql-bindirにはインストール済みのMySQL
のmysql_configコマンドが有るディレクトリを指定します。
その後以下のようにビルド・インストールします。
$ make
$ sudo make install
-----------------------------------------------------------------
クライアントライブラリのビルド方法(RPMを使わない方法)
クライアントライブラリをビルドする際には、MySQLのソースコードは
必要ありません。またMySQLがインストールされている必要もありません。
$ ./autogen.sh
$ ./configure --disable-handlersocket-server
$ make
$ sudo make install
$ cd perl-Net-HandlerSocket
$ perl Makefile.PL
$ make
$ sudo make install
-----------------------------------------------------------------
ビルド方法(RPM)
以下のように実行すれば、rpmパッケージがビルドインストールされま
す。
(MySQLサーバ側、HandlerSocketプラグインをインストールする)
$ ./autogen.sh
$ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
$ make rpm_cli
$ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
$ make rpm_c
$ sudo rpm -U dist/RPMS/*/handlersocket*.rpm
(クライアント側、クライアントライブラリをインストールする)
$ ./autogen.sh
$ ./configure --disable-handlersocket-server
$ make rpm_cli
$ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
$ make rpm_perl
$ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm
-----------------------------------------------------------------
起動
mysqlを起動した状態で、mysqlの設定ファイル(my.cnf等)に以下の内容を
追加します。
[mysqld]
handlersocket_port = 9998
# handlersocketが接続を受け付けるポート(参照系リクエスト用)
handlersocket_port_wr = 9999
# handlersocketが接続を受け付けるポート(更新系リクエスト用)
handlersocket_address =
# handlersocketがバインドするアドレス(空のままでOK)
handlersocket_verbose = 0
# デバッグ用
handlersocket_timeout = 300
# 通信タイムアウト(秒)
handlersocket_threads = 16
# handlersocketのワーカースレッド数
thread_concurrency = 128
# handlersocketが幾つかのスレッドを占有するため、大きめの
# 値を指定してください
open_files_limit = 65535
# ソケットを大量に開けるようにするため、大きめの値を指定し
# てください
以下のクエリを実行します。
mysql> install plugin handlersocket soname 'handlersocket.so';
Query OK, 0 rows affected (0.06 sec)
以上でhandlersocketへクライアントからアクセスできるようになります。

View File

@ -0,0 +1,118 @@
-----------------------------------------------------------------
handlersocketプラグインへの接続を開くには、Net::HandlerSocketオブ
ジェクトを作成します。
use Net::HandlerSocket;
my $args = { host => 'localhost', port => 9998 };
my $hs = new Net::HandlerSocket($args);
-----------------------------------------------------------------
検索などの命令を実行する前に、処理対象となる索引を開く必要があり
ます。
my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY',
'f1,f2');
die $hs->get_error() if $res->[0] != 0;
最初の引数は開く索引に付ける番号です。付けた番号は同一の
Net::HandlerSocketオブジェクトについてのみ有効です。第4引数は開く
索引の名前で、「PRIMARY」が指定され場合はプライマリキーが開かれま
す。第5引数は「,」で区切られた列名のリストです。
-----------------------------------------------------------------
テーブルから索引を使って行を取得するには、execute_singleメソッド
を呼びます。
my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0);
die $hs->get_error() if $res->[0] != 0;
shift(@$res);
最初の引数は索引の番号で、同じNet::HandlerSocketオブジェクトへ
open_indexで付けたものでなければなりません。第2引数には操作を指定
します。現在のバージョンでは、「=」、「>=」、「<=」、「>」、「<」
の操作が利用可能です。第3引数は配列への参照で、これは探すべき行の
キー値を指定します。配列の長さは索引のキーの個数と同じか少ない数
でなければなりません。第4引数と第5引数はそれぞれ、取得する最大行
数、取得前に読み飛ばす行数を指定します。取得される列は対応する
open_index呼び出しの第5引数で指定されたものになります。
execute_singleメソッドは常に配列への参照を返します。最初の要素は
エラーコードで、これが0ならば成功を表します。残りの要素は列の値で
す。もし取得されたデータが複数行の場合は、それが一つの配列へ連結
された形で格納されています。例えば、5行3列のデータの場合、次のよ
うなコードによってその内容を取得できます。
die $hs->get_error() if $res->[0] != 0;
shift(@$res);
for (my $row = 0; $row < 5; ++$row) {
for (my $col = 0; $col < 3; ++$col) {
my $value = $res->[$row * 5 + $col];
# ...
}
}
-----------------------------------------------------------------
行を更新または削除するには、更に多くの引数を指定して
execute_singleメソッドを呼び出します。書き込み処理をするには、
対象のNet::HandlerSocketオブジェクトは更新用handlersocketワーカ(既
定ではポート9999)へ接続されたものでなくてはなりません。
(安全のため、ポート9998は参照処理だけを受け付け、ポート9999は更新
処理も受け付けるようになっています。ポート9999は参照処理も受け付
けますが、レコードロック等の影響で遅くなります。ポート番号は
mysqldの「handlersocket_port」と「handlersocket_port_wr」の設定項
目で変更できます。)
my $args = { host => 'localhost', port => 9999 };
my $hs = new Net::HandlerSocket($args);
my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U',
[ 'fubar', 'hoge' ]);
die $hs->get_error() if $res->[0] != 0;
my $num_updated_rows = $res->[1];
my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D');
die $hs->get_error() if $res->[0] != 0;
my $num_deleted_rows = $res->[1];
execute_singleの第6引数は変更処理の種類を指定します。現在のバー
ジョンでは「U」と「D」が利用可能です。「U」については、第7引数で
新しい値を指定します。更新される列は、対応するopen_index呼び出し
の第5引数で指定されたものになります。「D」については第7引数は省
略できます。
-----------------------------------------------------------------
execute_singleメソッドは列の挿入にも使用できます。
my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
die $hs->get_error() if $res->[0] != 0;
my $num_inserted_rows = $res->[1];
第3引数は、対応するopen_index呼び出しの第5引数の列リストと同じだ
けの長さの配列への参照でなければなりません。open_index呼び出しの
第5引数に指定されていない列については、その列の既定値がセットされ
ます。
-----------------------------------------------------------------
execute_multiメソッドを使えば、複数のリクエストを一つの呼び出しで
実行することができます。これはリクエストを個別に実行するより高速
です。
my $rarr = $hs->execute_multi([
[ 0, '>=', [ 'foo' ], 5, 0 ],
[ 2, '=', [ 'bar' ], 1, 0 ],
[ 4, '<', [ 'baz' ], 10, 5 ],
]);
for my $res (@$rarr) {
die $hs->get_error() if $res->[0] != 0;
shift(@$res);
# ...
}
-----------------------------------------------------------------
エラーが起こると返値の配列参照の最初の要素が0以外になります。負の
数の場合はI/Oエラーが起こったことを示し、その場合はその
Net::HandlerSocketオブジェクトは破棄するべきです。正の値の場合は
接続は維持されているため、そのオブジェクトはそれ以後も再利用でき
ます。

View File

@ -0,0 +1,94 @@
-----------------------------------------------------------------
handlersocketの通信プロトコル
-----------------------------------------------------------------
構文
・コマンド行は改行(LF)で終わる。
・コマンド行は複数のトークンからなり、トークン間はTABで区切られる。
・トークンはNULLトークンか、文字列トークンのいずれか。
・NULLトークンは単一のNUL文字であらわされる。
・文字列トークンは、0バイト以上の文字列であらわされる。ただし0x10
未満の文字については0x01を前置し、0x40を加えたコードであらわさ
れる。それ以外の文字はその文字自身のコードであらわされる。
-----------------------------------------------------------------
リクエストとレスポンス
・接続が確立した直後の状態では、まずクライアントがコマンド行を送
る。(リクエスト)
・サーバはクライアントが送ったリクエストと丁度同じ数のコマンド行
を返す。(レスポンス)
・リクエストはパイプライン化してよい。つまりクライアントは前に
送ったリクエストに対する返事を待たずに次のリクエストを送っても
よい。
-----------------------------------------------------------------
リクエスト
・open_index命令は次のような構文を持つ。
'P' indexid dbname tablename indexname fieldlist
indexidは開いている索引に付けられる番号で、同一接続上で後に実行
する命令の、対象索引を指定するために使われる。dbname、tablename、
indexnameはそれぞれ開きたいDB、テーブル、索引の名前。索引の名前
として"PRIMARY"を指定するとプライマリキーが開かれる。fieldlist
はカンマ区切りの列名のリスト。
・find命令は次のような構文を持つ。
indexid op nflds v1 ... vn limit offset
indexidは実行対象の索引を指定する。opは索引検索の演算子(後述)。
v1からvnは可変長で、その個数はnflds。nfldsはindexidで指定された
open_index命令のindexnameの索引のfieldlistのフィールド数に等し
いか小さくなくてはならない。m2からmkは可変長で、その個数は
indexidで指定されたopen_index命令が発行された際のfieldlistに一
致しなければならない。コマンド行のlimit以降は省略できる。limit
とoffsetは、検索条件に合致する列のうちレスポンスに返す列数の上
限と、スキップする列数。limitとoffsetを省略した場合はそれぞれ1
と0が指定されたときと同じ動作をする。find命令はレスポンスとして、
条件に合致した列のリストを返す。opとして指定できる演算子は次の
とおり。
'=' - v1 ... vnと一致するものを取得
'>' - v1 ... vnより大きいものを昇順に取得
'>=' - v1 ... vnに一致するか大きいものを昇順に取得
'<' - v1 ... vnより小さいものを降順に取得
'<=' - v1 ... vnに一致するか等しいものを降順に取得
nfldsが1より大きい(v1 ... vnが2個以上)ときは辞書式順序で比較さ
れる。
・find_modify命令は次のような構文を持つ。
indexid op nflds v1 ... vn limit offset modop m1 ... mk
modopより前の部分はfind命令と同等で、これによって操作対象の行を
指定する。その操作対象の行に対しmodopで指定された変更処理を実行
する。m1 ... mkは可変長で、省略できる。modopは次いずれか。
'U' - indexidで指定されたopen_index命令のfieldlist列
の内容を、m1 ... mkの値で更新する。
'D' - 対象の行を削除する。m1 ... mkの値は無視される。
・insert命令はのような構文を持つ。
indexid '+' nflds v1 ... vn
indexidで指定されたテーブルに、列を挿入する。v1 ... vnは可変長
で、その個数はnflds。nfldsはindexidで指定されたopen_index命令の
indexnameの索引のfieldlistのフィールド数に等しいか小さくなくて
はならない。
-----------------------------------------------------------------
レスポンス
・open_index命令が成功したとき、レスポンスは次の構文を持つ。
'0' '1'
・find命令が成功したとき、レスポンスは次の構文を持つ。
'0' nflds v1 ... vn
nfldsは結果セットの列の数をあらわす。v1 ... vnは可変長で、その
長さはnfldsの整数倍。v1 ... vnは空のこともあり、それは条件に合
致するレコードが存在しなかったことをあらわす。結果セットが複数
行になったときはv1 ... vnの長さがnfldsの2倍以上となり、最初の
行から順にv1 ... vnにセットされる。
・modify命令が成功したとき、レスポンスは次の構文を持つ。
'0' '1' nummod
nummodは変更が施された行数。nummodが0のときは変更された行が無
かったことをあらわす。
・insert命令が成功したとき、レスポンスは次の構文を持つ。
'0' '1'
・命令が失敗したとき、レスポンスは命令に関わらず次の構文を持つ。
err '1' message
errは0以外の数値で、エラーコードをあらわす。messageは人間可読な
エラーメッセージ。ただしmessageが無いこともある。