PSGI/Plackを追っかける準備

今は時間取れないのでポインタだけ。

Blog


Googleグループ:


FAQ/SPEC


リファレンス実装


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

http://developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/Reference/reference.html

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されたオブジェクトもシリアライズできるのはしらなんだ。