PerlからTokyoTyrantを使っているのですが、ときおり
Odd number of elements in hash assignment at /usr/share/perl5/TokyoTyrant.pm line 1397.
というワーニングが出ることに気づいた。 出ているところは昨日使い始めたばかりのmget関数。 使い方が間違ってるのかなーと思っていろいろやっていたのですが.... 以下サンプル。
#!/usr/bin/perl # 別窓でttserver -port 10100 test.tctで起動しておく use strict; use TokyoTyrant; use Data::Dumper; my $pm = TokyoTyrant::RDBTBL->new(); $pm->open("localhost", 10100); # 値に空値を含んだハッシュを作成 my $cols = { '1'=>'hoge', '2'=>'', '3'=>'piyo', }; # 登録 $pm->put("123", $cols); # getで取得,これはワーニングでない my $rcols = $pm->get("123"); print "(1)" . Dumper($rcols); # mgetで取得 my %rtable = ( "123"=>undef ); # ここでOdd number of elements in hash assignment my $rcount = $pm->mget(\%rtable); # データ自体は正しいように見える print "(2)" . Dumper($rcols); $pm->close();
まさかこんな仕様ではなかろう。Perl module側のバグな気がする。 そこでTokyoTyrant.pmのsub mgetを読んでみると...
while(my ($pkey, $value) = each(%$recs)){ $$recs{$pkey} = split(/\0/ , $value);
となっている。これはゼロ値を終端子としたバイナリプロトコルの一部なのかな....。 とりあえず改悪してみたけど、これでいいとは思えない。
while(my ($pkey, $value) = each(%$recs)){ my @coll = split(/\0/ , $value); push(@coll, '') if (scalar @coll % 2 == 1); my %cols = @coll; $$recs{$pkey} = \%cols;
これ末尾だけ帳尻合わせしてるだけなんだけど、 データの途中でインデックスとバリューのアラインが狂うことはないのか というのがすごい気にかかる。
一応最新バージョンを使ってるつもりなんですが。
OSはLinux-2.6.32(Debian squeeze)です。
なんせ2000レコード読み出すと 2000行エラー出る ので ログがものすごい勢いで流れるのです。参った参った。
TokyoTyrant.pmのmisc関数の配列プッシュしてる部分の直前にprintf。
printf STDERR "esiz:%d eref:%s\n", $esiz, $$eref; push(@res, $$eref);
これで先ほどのテストスクリプトを実行すると...
esiz:1 eref:1 esiz:4 eref:hoge esiz:1 eref:3 esiz:4 eref:piyo esiz:1 eref:2 esiz:0 eref: # ちゃんと送られている (1)$VAR1 = { '1' => 'hoge', '3' => 'piyo', '2' => '' };
しかしmget関数(規定クラスの方)をダンプしてみると....
printf STDERR "SIZ:%d VREF:[%s]%s\n", $vsiz, $$vref, unpack("H*", $$vref); $recs->{$$kref} = $$vref;
SIZ:16 VREF:[1hoge3piyo2]3100686f67650033007069796f003200 Odd number of elements in hash assignment at /usr/local/share/perl/5.10.0/TokyoTyrant.pm line 1382. (2)$VAR1 = { '1' => 'hoge', '3' => 'piyo', '2' => '' };
何が起きているのか整理すると....
サーバ側じゃないのかこれ...と思って辿っていったらttserver.cのtcadbget()で既に16バイトで TCのtctdb.cのtctdbget()まで追うハメになっているでござる.... もしかしてTC/TTのテーブルデータベースってほとんどテストされてなくね? 仕様書に「空値は一切許さない」という記述も見つけられないし.....
![]() |