PSGI/Plackを追っかける準備
今は時間取れないのでポインタだけ。
Blog
- PSGI - Perl WSGI - bulknews.typepad.com
- http://d.hatena.ne.jp/tokuhirom/20090904/1252091316
- PSGIまとめ - Angelos in Action - angelosグループ
Googleグループ:
FAQ/SPEC
- GitHub - miyagawa/psgi-specs: Moved to https://github.com/plack/psgi-specs
- FAQ
- PSGI protocol specification
リファレンス実装
WAFアダプター
モバイルアプリで2-legged OAuthを使うことへの疑問
http://developer.mixi.co.jp/appli/appli_mobile/lets_enjoy_making_mixiappmobile/process_flow
mixiモバイルアプリはユーザーからのリクエストを一旦受け取ってアプリケーションサーバーへリクエストするという形をとっています。これ自体は色んな事情があるだろうから全然理解できるんだけど、何で2-legged OAuthを採用したんでしょうか?
mixiモバイルアプリでの認可の仕組みはコンシュマーとプロバイダーが信頼関係があることとユーザーがアプリケーションをインストールした時点でコンシュマーに対してリソースへのアクセス権限を認めるという前提のちょっと乱暴なモデル。
省略されるのは
- コンシュマーからのRequest Token要求とプロバイダーによる発行
- コンシュマーからのRequest Tokenへのサイン要求とユーザーのプロバイダーへの認証後のRequest Tokenへのサイン
- コンシュマーからのRequest TokenとAccess Tokenの交換とプロバイダーによるAccess Tokenの発行
で、Proteced Resourceに対してAccess Tokenなしでアクセスできます。
で、ふと思ったんだけど、Request Tokenの下りはモバイルだと無理なので理解できるけど、なぜAccess Tokenの発行フェーズまで省略する必要があるのかということ。
ユーザーのリクエストはプロバイダーを介してコンシュマーにリクエストされてるわけだから、ここでAccess Tokenを発行してQuery Parameterかなんかに含めてコンシュマーにリクエストすればいいと思うんですよね。もちろん有効期限をつけて。
Access Tokenがないとコンシュマーが無制限にリソースにアクセスできることになってどうかと思うのでやっぱりあった方がいいと思うんだけど、その辺ってどうなんだろうか。
CFStringRefをSVに変換
追記: id:tokuhirom先生に添削してもらった。
- malloc使うべからず -> NewXX()系でアロケート、SafeFree()で解放すべし(そういえばid:hirose31さんも言ってた)
- newSVpvの第二引数(STRLEN)は明示的に指定すべし -> 0で自動計算は\0 終端前提
SV * getString(CFStringRef var) { char *buf; SV *sv; CFIndex len = CFStringGetLength(val); CFIndex max = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); buf = Newxz(max + 1); CFStringGetCString(val, buf, max + 1, kCFStringEncodingUTF8); CFRelease(val); sv = newSVpv(buf, max); SafeFree(buf); return sv; }
CFStringRefのtypemap
CFStringRef T_CFSTRINGREF INPUT T_CFSTRINGREF $var = CFStringCreateWithCString(kCFAllocatorDefault, (char *) SvPV_nolen($arg), kCFStringEncodingUTF8);
これでXSで
Foo Foo(CFStringRef str) CODE: Foo(str);
とか使える。
CFRelease(str)はどこで呼べばいいんじゃろか?
git svn cloneでリポジトリの一部の最新だけ持ってきたい
git svn clone http://svn.coderepos.org/share/websites -r HEAD
でいけると思ったけどだめだったので
svn log --limit 1 http://svn.coderepos.org/share/websites ------------------------------------------------------------------------ r34214 | NeoCat | 2009-07-02 07:11:49 +0900 (木, 02 7 2009) | 2 lines -enterキーで送信時の改行入力防止 ------------------------------------------------------------------------
で
git svn clone http://svn.coderepos.org/share/websites -r 34214:HEAD
した
リポジトリのHEADに/share/websitesの変更が含まれてないからなのかのん
SQLiteとトランザクション
SQLiteの追加/更新はトランザクションを使うと高速化に効果があるというのはよく効くので実際試してみました。
use strict; use warnings; use DBI; use Benchmark qw(:all); my $count = 100; my $loop = 100; cmpthese( $count, { commit_each_insert => \&commit_each_insert, commit_bulk_insert => \&commit_bulk_insert, } ); sub commit_each_insert { unlink('test1.db'); my $dbh = DBI->connect('dbi:SQLite:dbname=test1.db'); $dbh->do( "CREATE TABLE test (id int not null, name text not null, primary key(id))" ); for (1 .. $loop) { $dbh->do("INSERT INTO test(id, name) VALUES($_, 'name_$_')"); } } sub commit_bulk_insert { unlink('test2.db'); my $dbh = DBI->connect('dbi:SQLite:dbname=test2.db'); $dbh->do( "CREATE TABLE test (id int not null, name text not null, primary key(id))" ); $dbh->do('BEGIN'); for (1 .. $loop) { $dbh->do("INSERT INTO test(id, name) VALUES($_, 'name_$_')"); } $dbh->do('COMMIT'); }
結果は
Rate commit_each_insert commit_bulk_insert commit_each_insert 18.8/s -- -71% commit_bulk_insert 64.5/s 243% --
爆速です。
一方でSELECTのトランザクション化は効果あるのかという話があったので試してみました。
use strict; use warnings; use DBI; use Benchmark qw(:all); my $count = 100; my $loop = 100; unlink('test.db'); my $dbh = DBI->connect('dbi:SQLite:dbname=test.db'); $dbh->do( "CREATE TABLE test (id int not null, name text not null, primary key(id))" ); $dbh->do('BEGIN'); for (1 .. $loop) { $dbh->do("INSERT INTO test(id, name) VALUES($_, 'name_$_')"); } $dbh->do('COMMIT'); cmpthese( $count, { commit_each_select => \&commit_each_select, commit_bulk_select => \&commit_bulk_select, } ); sub commit_each_select { for (1 .. $loop) { $dbh->do("SELECT * FROM test WHERE id = $_"); } } sub commit_bulk_select { $dbh->do('BEGIN'); for (1 .. $loop) { $dbh->do("SELECT * FROM test WHERE id = $_"); } $dbh->do('COMMIT'); }
結果は
Rate commit_each_select commit_bulk_select commit_each_select 59.2/s -- -16% commit_bulk_select 70.4/s 19% --
多少効果が見られます。
ちなみに、両テストともデータベースとしてon memoryな:memory:を指定するとinsertは20%、selectは2%程度の向上しかみられませんでした。
YAML色々
コードリファレンスのシリアライズとデシリアライズ
use strict; use warnings; use YAML; use Data::Dumper; $Data::Dumper::Deparse = 1; { no warnings ('once'); $YAML::UseCode = 1; } my $obj = { hello => sub { print "hello\n"; }, name => "hoge", }; # serialize my $yaml = YAML::Dump($obj); warn $yaml; # deserialize my $obj2 = YAML::Load($yaml); warn Dumper $obj2; # call coderef $obj2->{hello}->();
$YAML::UseCode = 1で$YAML::LoadCodeと$YAML::DumpCodeがtrueになる。
no warningsしないとused only onceのwarningsが出る。
結果は
--- hello: !!perl/code | { use warnings; use strict 'refs'; print "hello\n"; } name: hoge $VAR1 = { 'hello' => sub { use warnings; use strict 'refs'; print "hello\n"; }, 'name' => 'hoge' }; hello
blessされたオブジェクトのシリアライズとデシリアライズ
{ package Foo; use strict; use warnings; sub new { bless {name => 'hoge'},'Foo'; } sub hello { print 'hello ' . shift->{name} . "\n"; } } { package main; use strict; use warnings; use YAML; use Data::Dumper; $Data::Dumper::Deparse = 1; { no warnings ('once'); $YAML::UseCode = 1; } my $obj = Foo->new; # serialize my $yaml = YAML::Dump($obj); warn $yaml; # deserialize my $obj2 = YAML::Load($yaml); warn Dumper $obj2; # call method $obj2->hello; }
実行結果
$VR1 = bless( { 'name' => 'hoge' }, 'Foo' ); --- !!perl/hash:Foo name: hoge $VAR1 = bless( { 'name' => 'hoge' }, 'Foo' ); hello hoge
blessされたオブジェクトもシリアライズできるのはしらなんだ。