テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

GreenBuckets

GreenBucketsというオブジェクトストレージのコード調査です. 私はPerlを知らないので完全には理解出来ないのと, 関数や変数の名前から適当に推測してます.

GreenBucketsの概要自体はこちらを参照してください. GreenBuckets という Object Storage を作りました - blog.nomadscafe.jp

  • これがメイン関数のようなもので, サーバを実行状態にする.
  • Plack::Loaderは, ポートを監視して, そこからのリクエストをappにdispatchする.
  • appというのは, Loaderが何をするか.
  • appを作るのがbuild_app.
sub run {
    my $self = shift;

    my $dispatcher_status_access = $self->config->dispatcher_status_access;
    my $front_proxy = $self->config->front_proxy;

    my $app = $self->build_app;
    ...
    my $loader = Plack::Loader->load(
        'Starlet',
        port => $self->config->dispatcher_port,
        host => 0,
        workers => $self->config->dispatcher_max_worker,
    );

    $loader->run($app);
  • Routerによってパターンマッチ的にリクエストをdispatch.
  • GETメソッドはget_objectにdispatchされる.
  • connectの第一引数は, リクエストを受け取るパスであろう. (http://search.cpan.org/~tokuhirom/Router-Simple-0.17/lib/Router/Simple.pm)
  • 実際に実行されるのはsub { のところ.
  • Routerをmatchする. 結果をpとする.
  • pのactionを実行. (たぶん. どこでやってるのかは不明)
  • $c->args($p);は, cというConnectionのargsを設定している?(単に代入してるだけのように見える. コピーする文法だろうか?)
sub build_app {
    my $self = shift;

    #router
    my $router = Router::Simple->new;

    # get
    $router->connect(
        '/{bucket:[a-zA-Z0-9_][a-zA-Z0-9_\-\.]+}/*',
        { action => 'get_object' },
        { method => ['GET','HEAD'] }
    );

   my $p = try {
       ....
       $router->match($env)
   }
   ...
   sub {
        my $env = shift;
        my $psgi_res;

        my $s_req = GreenBuckets::Dispatcher::Request->new($env);
        my $s_res = GreenBuckets::Dispatcher::Response->new(200);

        ...
        if ( $p ) {
            my $action = delete $p->{action};
            my $code = $self->can($action);
            croak('uri match but no action found') unless $code;

            $c->args($p);

            my $res = $code->($self, $c );
            croak( "undefined response") if ! defined $res;

            my $res_t = ref($res) || '';
            if ( blessed $res && $res->isa('Plack::Response') ) {
                $psgi_res = $res->finalize;
            }
        }  
        $psgi_res;  
  • cはConnectionっぽい.
  • たぶん, bucketには, matchしたところの正規表現内の名前付き後方参照.
  • 逆算すると, argsというのは何かテーブル的な存在で, matchした時の情報を保持しておく?
  • Modelのget_objectに委譲してるだけ.
sub get_object {
    my ($self, $c) = @_;
    my $bucket_name = $c->args->{bucket};
    my ($filename) = @{$c->args->{splat}};
    $self->model->get_object($bucket_name, $filename, $c->req);
}
  • agent->getはたぶん, 単にWebDAV問い合わせをする. コード的に, FurlというライブラリでHTTP問い合わせを行っている. Curlのようなものでは?と推測.
  • 問い合わせをして, 結果からDispatcher::Responseオブジェクトを作っている.
  • Dispatcher::Response, RequestはPlackというライブラリのものを直接使っているっぽい.
  • WebDAVストレージからの結果を上に伝搬してクライアントにOK.
sub get_object {
    my $self = shift;
    my ($bucket_name, $filename, $req) = @_;

    ...
    my ($res,$fh) = $self->agent->get(\@r_uri, \@proxy_headers);
    ...
    my $r_res = GreenBuckets::Dispatcher::Response->new($res->code);
    $r_res->header($res->headers->flatten);
    $r_res->header('X-Content-Type-Options', 'nosniff');
    $r_res->content_type( Plack::MIME->mime_type($filename) || 'text/plain' );
    $r_res->body($fh);
    $r_res;
}

よくわからないことが多くて, 推測だらけになった.

  • ドキュメントにはハッシュがどうとか書いてあるだが, どこで使われているのか分からなかった.

もしかして, 以下のコードでslaveというのがSchema型で, ここから暗号化された内部uriを生成してる?

sub get_object {
    ...
    my $slave = $self->slave;
    my $bucket = $slave->select_bucket(
        name => $bucket_name
    );
    ... 
    my @uri = $slave->retrieve_object_nodes(
        bucket_id => $bucket->{id},
        filename => $filename,
        flat => $self->config->flat_dav
    );
    ...
    my @r_uri = map { $_->{uri} } grep { $_->{online} && !$_->{remote} } @uri;
    ...
    @r_uri = map { $_ . '?'. $query_string } @r_uri if defined $query_string;

PerlじゃなくてせめてRubyならばもう少し理解出来たと思う.

広告を非表示にする