q4m-forwardコマンドの処理

Q4Mを使う上で避けて通れないのが「q4m-forward」
これを使えば、テーブルの中身がRelayされるんだけど、内部的になにをしているのか知りたくてコードを読んでみました。
q4m-forwardはPerlで書かれているんだけど、Perlを普段使わないので、言語自体も調べつつのメモです)

q4m-forwardの構成

構成自体は非常にシンプル。大まかに書くとこんな感じ。

// -- モジュール読み込み -- //
use DBI;            //DB用
use Getopt::Long;   //コマンドラインのオプション用

// -- サブルーチン -- //
sub usage{}         //使い方
sub connect_to_db{} //DB接続

// -- main処理 -- //
// コマンドライン引数からDBへ接続
while(1){
  // 転送元を待つ
  // 転送元からレコードを取り出す
  // 転送先にレコードを書き込む
}

main処理について

サブルーチンはシンプルなので保留にして、main処理をまとめます。

コマンドライン引数からDBへ接続
my ($src, $dst) = @ARGV;
my ($src_conn, $src_table) = connect_to_db($src);
my ($dst_conn, $dst_table) = connect_to_db($dst);
my $mode = $do_reset ? 'w' : 'a';

ここでは、コマンドライン引数(@ARGV)から、転送元DB($src)、転送先DB($dst)への接続設定をしています。
また、do_resetオプションの判定もしています。$modo変数によってあとの処理が変わります。
このあと、無限ループに入ります。

転送元を待つ
    # wait until a row gets ready
    my $wait = $src_conn->selectall_arrayref(
        'select queue_wait(?)',
        {},
        $src_table,
    ) or die $src_conn->errstr;
    die "received an error from source (table not found?)\n"
        unless defined $wait->[0][0];
    next unless $wait->[0][0];

ここでは、$src_conn->selectall_arrayrefによって$src_tableからqueueを取得します。
オープンに失敗したらdie。
取得した結果は、{}と指定しているようにハッシュで取得します。
$waitがハッシュとなるのですが、$wait[0][0]が未定義だったらdie。空じゃなければ次のループです。

転送元からレコードを取り出す
    # receive row
    my $rowid = $src_conn->selectall_arrayref('select queue_rowid()')
        or die $src_conn->errstr;
    die "unexpected response from source\n"
        unless $rowid->[0][0];
    my $row = $src_conn->selectall_arrayref(
        "select * from $src_table",
        { Slice => {} },
    ) or die $src_conn->errstr;

$src_conn->selectall_arrayref("select * from $src_table",{ Slice => {} },)で$rowに転送元からレコードを取り出してます。
その前の、select queue_rowid()についてはちょっと勉強不足で不明。
ちなみにqueue_rowid()は、ownerモードのときにだけ動きます。

転送先にレコードを書き込む
    # write row
    my $res = $dst_conn->selectall_arrayref(
        "select queue_set_srcid(?,?,?)",
        {},
        $sender_index,
        $mode,
        $rowid->[0][0],
    ) or die $dst_conn->errstr;
    die "failed to set source id (sender index out of range?)\n"
        unless $res->[0][0];
    $mode = 'a';
    $dst_conn->do(
        "insert into $dst_table ("
            . join(',', sort keys %{$row->[0]})
                . ') values ('
                    . join(
                        ',',
                        map {
                            $dst_conn->quote($row->[0]{$_})
                        } sort keys %{$row->[0]},
                    )
                        . ')',
    ) or die $dst_conn->errstr;

joinは、指定文字で配列を結合して文字列で返しています。
sort 関数は、keys 関数が任意にリスト化したキーの順番を、文字コード順で並び替えます。
mapは、引数同士で評価して一致したものを返しています。
insert into できるように正しく並べ替えていると言った感じでしょうか。

このあとwhile(1)のループに戻ります。