こせきの技術日記 このページをアンテナに追加 RSSフィード

2012-02-08

Perl 互換の正規表現再帰的に grep して Emacs で開く。  Perl 互換の正規表現で再帰的に grep して Emacs で開く。を含むブックマーク  Perl 互換の正規表現で再帰的に grep して Emacs で開く。のブックマークコメント

リファクタリングのお共に。


コマンドで開く

emacs $(grep -Prl '正規表現' * | grep -v '\.svn')

Prlっていうのが覚えやすくてよい。ほんとは-Perlって書きたいけど無理だった。


Emacs から開く

基本っぽい機能なのに、今まで使ったことなかった。

  • M-x find-grep-dired …… grepにマッチしたファイルをdiredで表示
  • M-x find-name-dired …… ファイル名をワイルドカードで探してdiredで表示。
  • M-x find-dired …… findコマンドのオプションを指定してdiredで表示。

find-name-diredが使いやすそう。

find-grep-diredで特定のディレクトリを除外する方法は見つからなかった。残念。


参考

2012-01-05

TAILQ のソースを読んで C のポインタをマスターする。  TAILQ のソースを読んで C のポインタをマスターする。を含むブックマーク  TAILQ のソースを読んで C のポインタをマスターする。のブックマークコメント

正月は TAILQ のソースを読んでいた。普段 C を読み書きしないので、とても勉強になった。ポインタの使い方がわかった(ような気持ちになれた)。


TAILQって?

TAILQ は C のマクロで書かれた双方向リンクリストの実装。

BSDOSXglibc に含まれている。

基本的な使い方は以下のページが参考になった。

本記事では OSX の、

  • /usr/include/sys/queue.h

を参照する。glibc のTAILQでも基本は同じ。


めまい

元々は C の勉強のつもりで tmux のソースを見ていて、何気なく queue.h を開いてめまいがした。

例えばこんな感じ。

#define TAILQ_LAST(head, headname)                                      \
        (*(((struct headname *)((head)->tqh_last))->tqh_last))

#define TAILQ_PREV(elm, headname, field)                                \
        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

ぜんぜん意味がわからない。

#define TAILQ_ENTRY(type)                                               \
struct {                                                                \
        struct type *tqe_next;  /* next element */                      \
        struct type **tqe_prev; /* address of previous next element */  \
        TRACEBUF                                                        \
}

なんでnextとprevで型が違うのか。こわい。コメントも何が言いたいのかわからない。前の次の要素のアドレス?prevは前の要素ではないのか。

結局、理解できたと思えるまで2日くらいかかった。


リストを作ってアドレスを出力するサンプル

サンプル

#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h>

/*
双方向リンクリスト /usr/include/sys/queue.h の TAILQ を理解するための、
サンプルです。
*/

/* リスト要素 */
struct list_item {
  /* ポインタがどこを指しているかわかりやすくするため、
     TAILQ_ENTRYの前後にメンバー(num1,num2)を入れる。 */
  int num1;

  /*
   要素をリンクする構造体。
   tqe_nextに次の要素のアドレスが設定される。
   tqe_prevに前の要素のtqe_nextのアドレスが設定される。
  */
  TAILQ_ENTRY(list_item) links;

  /* ポインタがどこを指しているかわかりやすくするため、
     TAILQ_ENTRYの前後にメンバー(num1,num2)を入れる。 */
  int num2;
};
 
/* 
  リストの最初と最後を管理するヘッド構造体を宣言する。
  tqh_firstに最初の要素のアドレスが設定される。
  tqh_lastに最後の要素のtqe_nextを指すアドレスが設定される。
*/
TAILQ_HEAD(list_head, list_item);

/* 渡されたヘッドに要素を追加する。 */
void add_items(struct list_head *head)
{
  int i = 0;
  struct list_item *item;

  for (i = 0; i < 3; i++) {
    item = (struct list_item*)malloc(sizeof(struct list_item));
    item->num1 = i;
    item->num2 = 0;

    /* 末尾に追加する。 */
    TAILQ_INSERT_TAIL(head, item, links);
  }
}

/* ヘッドのアドレスを出力する。 */
void print_head(struct list_head *head)
{
  printf("-- HEAD\n");
  printf("%p: head\n", head);
  printf("%p: head->tqh_first      = %p\n", &(head->tqh_first), head->tqh_first);
  printf("%p: head->tqh_last       = %p\n", &(head->tqh_last), head->tqh_last);
}

/* リストの各要素を出力する。 */
void print_items(struct list_head *head)
{
  struct list_item *item;

  /* headが参照するリストをlinksメンバを使ってループする。要素はitemに入れる。 */
  TAILQ_FOREACH(item, head, links) {
    printf("-- TAILQ_FOREACH %d\n", item->num1);

    /* itemのアドレス */
    printf("%p: item\n", item);

    printf("%p: item->num1           = %d\n", &(item->num1), item->num1);
    printf("%p: item->links.tqe_next = %p\n", &(item->links.tqe_next), item->links.tqe_next);
    printf("%p: item->links.tqe_prev = %p\n", &(item->links.tqe_prev), item->links.tqe_prev);
    printf("%p: item->num2           = %d\n", &(item->num2), item->num2);

    /* 
      以下、TAILQ_PREV がどういう仕組みなのか調べるための出力。

      TAILQ_PREVは、指定した要素の1つ前の要素を得るためのマクロ。
      (*(((struct list_head *)(item->links.tqe_prev))->tqh_last))
      のように展開される。

      item->links.tqe_prev が指す先を
      list_headと見なし(struct list_head * にキャスト)、
      構造体の2番目のメンバ(tqh_last = tqe_prev)が指す先に書かれた
      アドレス(tqe_next or tqh_last)が「1つ前の要素」を指している。
      「2歩戻って1歩進む」

      headまでいくと、tqh_lastによってNULLが返る。
      ループが正順でも逆順でも、最後の要素のtqe_nextが終了条件として機能している。
    */
    struct list_item **prev = item->links.tqe_prev;
    struct list_head *prev_head = (struct list_head *)prev;
    printf("             prev_head            = %p\n", prev_head);
    printf("             prev_head->tqh_last  = %p\n", prev_head->tqh_last);
    printf("            *prev_head->tqh_last  = %p\n", *prev_head->tqh_last);
  }
}

/* リスト用に確保したメモリを解放する。 */
void free_list(struct list_head *head)
{
  printf("-- FREE\n");

  /* 要素を順にリストから外して解放 */
  struct list_item *item;
  while(!TAILQ_EMPTY(head)) {
    item = TAILQ_FIRST(head);
    printf("%p -> free\n", item);
    TAILQ_REMOVE(head, item, links);
    free(item);
  }

  /* ヘッドを解放 */
  printf("%p -> free\n", head);
  free(head);
}

int main(int argc, char *argv[])
{
  /* 
    mallocを使って、リストの要素とアドレスを揃える。表示をわかりやすくするため。
    mallocはヒープに、ローカル変数はスタックに保存される。 
  */
  struct list_head *head = (struct list_head*)malloc(sizeof(struct list_head));
  
  TAILQ_INIT(head);    /* リスト作成 */
  add_items(head);     /* 要素追加 */
  print_head(head);    /* ヘッド出力 */
  print_items(head);   /* 要素出力 */
  free_list(head);     /* メモリ解放 */

  return 0;
}

これを実行すると、

$ gcc test.c
$ ./a.out
-- HEAD
0x100100080: head
0x100100080: head->tqh_first      = 0x100100090
0x100100088: head->tqh_last       = 0x1001000d8
-- TAILQ_FOREACH 0
0x100100090: item
0x100100090: item->num1           = 0
0x100100098: item->links.tqe_next = 0x1001000b0
0x1001000a0: item->links.tqe_prev = 0x100100080
0x1001000a8: item->num2           = 0
             prev_head            = 0x100100080
             prev_head->tqh_last  = 0x1001000d8
            *prev_head->tqh_last  = 0x0
-- TAILQ_FOREACH 1
0x1001000b0: item
0x1001000b0: item->num1           = 1
0x1001000b8: item->links.tqe_next = 0x1001000d0
0x1001000c0: item->links.tqe_prev = 0x100100098
0x1001000c8: item->num2           = 0
             prev_head            = 0x100100098
             prev_head->tqh_last  = 0x100100080
            *prev_head->tqh_last  = 0x100100090
-- TAILQ_FOREACH 2
0x1001000d0: item
0x1001000d0: item->num1           = 2
0x1001000d8: item->links.tqe_next = 0x0
0x1001000e0: item->links.tqe_prev = 0x1001000b8
0x1001000e8: item->num2           = 0
             prev_head            = 0x1001000b8
             prev_head->tqh_last  = 0x100100098
            *prev_head->tqh_last  = 0x1001000b0
-- FREE
0x100100090 -> free
0x1001000b0 -> free
0x1001000d0 -> free
0x100100080 -> free

のように出力される。

左側の0x00000000: が、各構造体のメンバが格納されているアドレス。8バイトずつ、0x100100080 〜 0x1001000ef までを使っている。

num1とnum2はリスト要素のデータ。ポインタがどこを指しているか明確にするため、リンク(links)の前後に配置している。

prev_* は TAILQ_PREV がどのように機能しているか調べるための出力。


ポインタはそれぞれ何を指しているか。

おおまかなイメージは、

の図がわかりやすい。実際にはもう少し複雑にできている。上記のサンプルを実行すると、要素3つのリストが作成され、

のようにリンクされる。


TAILQ_FIRST

簡単なところから。TAILQ_FIRSTは先頭の要素を取得する。

#define TAILQ_FIRST(head)       ((head)->tqh_first)

head構造体のメンバ tqh_first にはリスト先頭要素のアドレスが入っている。tqh_firstの宣言のアスタリスク(*)は1個。* は「この先struct」を意味する。

#define TAILQ_HEAD(name, type)                                          \
struct name {                                                           \
        struct type *tqh_first; /* first element */                     \
        struct type **tqh_last; /* addr of last next element */         \
        TRACEBUF                                                        \
}

ポインタが指している先の構造体のメンバを取得するときは、アロー演算子(->)が使える。


TAILQ_NEXT

指定された要素(elm)の次の要素を取得するマクロ

#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)

たとえば上のサンプルコードだと、 マクロ引数のfieldにはlinksが指定されて、

(item)->links.tqe_next

と展開される。

最後の要素item2のtqe_nextにはNULLが設定されている。最後までいくと、TAILQ_NEXTはNULLを返す。


TAILQ_FOREACH

TAILQ_FIRSTとTAILQ_NEXTを使うと、正順のループができる。

#define TAILQ_FOREACH(var, head, field)                                 \
        for ((var) = TAILQ_FIRST((head));                               \
            (var);                                                      \
            (var) = TAILQ_NEXT((var), field))

最後までいくと、TAILQ_NEXTがNULLを返し、ループが終了する。


TAILQ_PREV

PREVは、NEXTよりもずっと複雑になる。

#define TAILQ_PREV(elm, headname, field)                                \
        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

以下の図はitem2のTAILQ_PREVを取得する場合。

TAILQ_PREVをサンプルコードの変数名で展開すると、

(*(((struct head *)((item)->links.tqe_prev))->tqh_last))

となり、これを分解すると、

struct list_item **prev = item->links.tqe_prev;
struct list_head *prev_head = (struct list_head *)prev;
*(prev_head->tqh_last)

になる。

まず、item2のtqe_prevを取得する。tqe_prev には、item1のtqe_nextのアドレスが格納されている。

次に、キャストを使って item2 の tqe_prev が list_head を指しているものと見なす。item1 の tqe_prev を tqh_last と呼び換える。

item1の tqh_last (= tqe_prev) には、 item0 の tqe_next のアドレスが格納されている。

最後に、アスタリスク * で item0 の tqe_next に格納されたアドレスを返す。これで item1 の先頭のアドレスが得られる。

item2からitem1を得るために、

  • item2->links.tqe_prev
  • item1->links.tqe_next
  • item1->links.tqe_prev
  • item0->links.tqe_next

と辿っていく。


ポイント:

  • 2個戻って1個進む。
    • 正確には2個戻った先に書かれたアドレスを返す。
    • コード上に、図の青矢印に相当する操作はない。
  • C のキャストは、ポインタが別の型を指していることにできてしまう。
  • struct list_item **tqe_prev;
    • ポインタポインタ
    • 「自分がポインタ、次もポインタ、次の次がstruct」。
    • tqe_prevの次の次を辿ると自要素の先頭にたどり着く。
    • /* address of previous next element */ というコメントは、previousのtqe_nextメンバという意味か。ちょっとどうかと思う。

TAILQ_PREV 先頭要素の場合。

item1 の TAILQ_PREV を得る場合も item2 と全く同じ。では、リストの先頭 item0 の前の要素を得ようとするとどうなるか。

tqh_lastの呼び換えは発生せず、そのまま最後の要素 item2 の tqe_next に飛ぶ。tqe_nextにはNULLがセットされている。

ポイント:

  • item2 のtqe_next が、TAILQ_NEXTとTAILQ_PREV両方の末端を示す値として使われている。
    • なんかすごい。

TAILQ_LAST

末尾の要素を得る。

#define TAILQ_PREV(elm, headname, field)                                \
        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

#define TAILQ_LAST(head, headname)                                      \
        (*(((struct headname *)((head)->tqh_last)     )->tqh_last))

TAILQ_PREV と TAILQ_LAST は、ほぼ一緒。head->tqh_lastのprevのnextでリスト末尾の先頭アドレスを得る。


TAILQ_INSERT_TAIL

リストの更新処理も1つだけ見てみる。

#define TAILQ_INSERT_TAIL(head, elm, field) do {                        \
        TAILQ_NEXT((elm), field) = NULL;                                \
        (elm)->field.tqe_prev = (head)->tqh_last;                       \
        *(head)->tqh_last = (elm);                                      \
        (head)->tqh_last = &TAILQ_NEXT((elm), field);                   \
        QMD_TRACE_HEAD(head);                                           \
        QMD_TRACE_ELEM(&(elm)->field);                                  \
} while (0)

elmが追加する要素。

do-while(0)は、マクロ展開によりセミコロンが問題を起こすのを避けるため。関数呼び出しのように使える、複数の文からなるマクロを書きたい場合は do-while(0)でラップする。

2行目。elmのtqe_nextをNULLに設定する。

3行目。elmのtqe_prevをheadのtqh_lastに設定する。現在の末尾要素のtqe_nextのアドレス。

4行目。これまでの末尾要素の tqe_next に新しく追加する要素の先頭アドレスを設定。

5行目。headのtqh_lastを、新要素のtqe_nextのアドレスに設定。

残り2行はデバッグ用。

リストが空だった場合は、tqe_prev は head の tqh_first を指す。headの初期化時にtqh_lastがtqh_firstのアドレスに初期化されている。

#define TAILQ_INIT(head) do {                                           \
        TAILQ_FIRST((head)) = NULL;                                     \
        (head)->tqh_last = &TAILQ_FIRST((head));                        \
        QMD_TRACE_HEAD(head);                                           \
} while (0)

#define TAILQ_FIRST(head)       ((head)->tqh_first)

gdb で実行

サンプルプログラムgdb で実行してアドレスを確認してみる。

$ gcc -g test.c
$ gdb a.out

# 132行目、リストを解放する前にブレークポイントを設定。
(gdb) break 132 

# 実行。
(gdb) run

# headを表示。
(gdb) p head
$1 = (struct list_head *) 0x100100080

# headからtqh_firstのアドレス取得。
(gdb) p $1->tqh_first
$2 = (struct list_item *) 0x100100090

# tqh_firstの中身であるitem0を表示。
(gdb) p *$2
$3 = {
  num1 = 0,
  links = {
    tqe_next = 0x1001000b0,
    tqe_prev = 0x100100080
  },
  num2 = 0
}

# tqh_lastがlist_headを指しているものとして取得。
(gdb) p (struct list_head *)head->tqh_last
$4 = (struct list_head *) 0x1001000d8

# $4をlist_headとして表示。
(gdb) p *$4
$5 = {
  tqh_first = 0x0,
  tqh_last = 0x1001000b8
}

# item2のtqh_last (= tqe_prev)の先の先が、item2自身。
(gdb) p **($4->tqh_last)
$6 = {
  num1 = 2,
  links = {
    tqe_next = 0x0,
    tqe_prev = 0x1001000b8
  },
  num2 = 0
}

# 残りを実行して終了。
(gdb) continue
(gdb) quit

2011-11-28

Varnish の設定ファイルを使って Basic 認証を実装する。  Varnish の設定ファイルを使って Basic 認証を実装する。を含むブックマーク  Varnish の設定ファイルを使って Basic 認証を実装する。のブックマークコメント

Varnish 本体に Basic 認証の機能はない。VCL を使って、Basic 認証を実装することならできる。


原始的な実装。

Authorizationヘッダが一致しなかったら401エラーを出す。

backend apache {
  .host = "127.0.0.1";
  .port = "80";
}

# vcl_recv は、クライアントからリクエストを受け取った時に実行される。
sub vcl_recv {
  set req.backend = apache;

  # Authorization ヘッダが一致しなかったら401エラー。
  if (req.http.Authorization != "Basic dXNlcjpwYXNz" &&
      req.http.Authorization != "Basic dXNlcjI6cGFzczI=" ) {
    error 401;
  }

  return (lookup);
}

# vcl_error はバックエンドもしくは VCL 内部でエラーが発生したら実行される。
sub vcl_error {
  if (obj.status == 401) {
    # WWW-Authenticate ヘッダで Basic 認証を要求する。
    set obj.http.WWW-Authenticate = {"Basic realm="Authorization Required""};
    synthetic {"Error 401 Unauthorized"};
    return(deliver);
  }
}

これで user/pass もしくは user2/pass2 でログインできる。

設定ファイルで認証機能を実装できてしまう。Varnish すごい。

Authorizationヘッダは次のようにして生成する。

$ echo -n "user:pass" | base64
dXNlcjpwYXNz
$ echo -n "user2:pass2" | base64
dXNlcjI6cGFzczI=

Mac なら gbase64 が入ってるかもしれない。


Varnishの認証とバックエンドの認証を分ける。

vcl_error は VCL のエラーと、バックエンドのエラーを区別しない。

バックエンドの 401 エラーをそのまま返したい場合は、内部用に適当なHTTPステータスを設定すると良い。

例えば上の error 401; を error 701; に変えて、

sub vcl_error {
  if (obj.status == 701) {
    set obj.status = 401;
    set obj.response = "Unauthorized";
    set obj.http.WWW-Authenticate = {"Basic realm="Authorization Required""};
    synthetic {"Error 401 Unauthorized"};
    return(deliver);
  }
}

とする。

内部用とはいえ、勝手にステータスコードを増やすのはためらわれるが、、。wiki にも例が載っている。


平文のパスワードハッシュにするため VMOD をインストールする。

上の設定ファイルには Base64 エンコードされただけの生のパスワードが書かれている。これではセキュリティ上よろしくない。せめてハッシュにしておきたい。

Varnish 3.0 から VMOD というプラグイン機能が使えるようになった。

Authentication Module というのが載っていて、おっと思ったが、リンクが切れている。

Digest module を使って、認証ヘッダをハッシュにすることができた。

コンパイルにはmhashが必要。手元のMacだと、

port installed | grep mhash

で見つかるのだが、dylibをリンクする方法がわからず、、 /usr/local にソースから入れた。

Digest module のインストールは、

./configure VARNISHSRC=/usr/local/src/varnish-3.0.2 VMODDIR=/usr/local/varnish-3.0.2/lib/varnish/vmods 
make
sudo make install

とした。VMODDIR は varnishadm を使い、param.show コマンドで確認できる。

/usr/local/varnish/bin/varnishadm -S ./secret -T :6082 param.show

ドキュメントの生成にrst2manが必要と言われるが、無視した。


Digest モジュールを使って、 Authorization ヘッダをハッシュにする。

# モジュールを読み込む。
import digest;

backend apache {
  .host = "127.0.0.1";
  .port = "80";
}

sub vcl_recv {
  set req.backend = apache;

  # アカウント毎にハッシュを生成するのは無駄なので、ヘッダを一時変数代わりに使う。
  set req.http.X-Varnish-Basic-Auth = digest.hash_sha1("SALT " + req.http.Authorization);

  if (req.http.X-Varnish-Basic-Auth != "07af5b04d92d17b077d86a847cd683ea123503df" &&
      req.http.X-Varnish-Basic-Auth != "264fdc6e41d3526dd282671acb4cc1cd8d670a73") {
    unset req.http.X-Varnish-Basic-Auth;
    error 401;
  }

  unset req.http.X-Varnish-Basic-Auth;
  return (lookup);
}

sub vcl_error {
  if (obj.status == 401) {
    set obj.http.WWW-Authenticate = {"Basic realm="Authorization Required""};
    synthetic {"Error 401 Unauthorized"};
    return(deliver);
  }
}

こんな感じ。

Varnishにはローカル変数がないので、ハッシュを一旦ヘッダに設定し、使い終わったら消している。本当に効率がいいかはわからない。数回ならハッシュを計算したほうが速いかもしれない。

ハッシュの生成は、

#! /bin/bash

SALT="SALT"

PASS=`echo -n "$1" | base64`
echo "Basic $PASS"
echo -n "$SALT Basic $PASS" | sha1sum

で行った。申し訳程度にSALTを設定してみた。

手元だと、hash_md5 はうまく動かなかった。hash_sha1 はうまく動いたが、これで運用してみたわけではないのでご注意を。


その他の方法

認証機能だけを一旦バックエンドに送り、認証に成功したら restart を使ってコンテンツを取得し直す、という例をどこかで見た。けど URL が見つからない、、。


参考

素晴らしすぎます、、。

2011-11-27

Varnish の hit_for_pass ってなに?  Varnish の hit_for_pass ってなに?を含むブックマーク  Varnish の hit_for_pass ってなに?のブックマークコメント


結論

キャッシュしない」ことをキャッシュするのが hit for pass キャッシュオブジェクト

同じ URL に、同時にアクセスされたとき、

  • キャッシュが見つからない場合 …… 先頭のリクエストだけをバックエンドに送り、残りはそのレスポンスを待つ。
  • hit for pass キャッシュが見つかった場合 …… 他のリクエストを気にせず、全部バックエンドに送る。

という動作になる。


発端

Varnish を3.0にバージョンアップしたら vcl_fetch のreturn (pass); がエラーになった。どうやら、単純に return (hit_for_pass); に置き換えればいいらしい。

The difference in behaviour of pass in vcl_recv and vcl_fetch confused people, so to make it clearer that they are different, you must now do return(hit_for_pass) when doing a pass in vcl_fetch.

Upgrading from Varnish 2.1 to 3.0 — Varnish version trunk documentation

vcl_recv の pass と、vcl_fetch の pass が紛らわしいから、hit_for_pass に変えたよ、と書いてある。

hit for pass 機能の詳しい説明は、以下にあった。

同時アクセスで、キャッシュが存在しない場合、最初のレスポンスを待つ??

これを読むまで、キャッシュが無ければ単純に全てバックエンドに送られるものだと思っていた。言い換えると、人気の高いページのキャッシュが消えた場合、バックエンドにアクセスが集中するものと思っていた。

どうやら、そうではないらしい。


実験

hit_for_pass の挙動は、実験で簡単に確認できた。

default.vcl。実験用の Varnish 設定。全リクエストのキャッシュを参照し、レスポンスは全てキャッシュしない(= hit for pass キャッシュを作成する)。

backend apache {
  .host = "127.0.0.1";
  .port = "80";
}

sub vcl_recv {
  set req.backend = apache;
  return (lookup);
}

sub vcl_fetch {
  # 3.0用
  return (hit_for_pass);

  # 2.1用
  # return (pass);
}

test.php。バックエンドがリクエストを受けたタイミングを確認するためのPHP。ログを書いてスリープして、ログを書く。

<?php

error_log("TEST 1");
sleep(5);
error_log("TEST 2");

?>OK

で、これを連続して3回リクエストする。

$ curl http://localhost:8080/test.php &
$ curl http://localhost:8080/test.php &
$ curl http://localhost:8080/test.php &

すると、出力されるログは、

[Sun Nov 27 13:06:47 2011] [error] [client 127.0.0.1] TEST 1 ←先頭のリクエスト
[Sun Nov 27 13:06:52 2011] [error] [client 127.0.0.1] TEST 2
[Sun Nov 27 13:06:52 2011] [error] [client 127.0.0.1] TEST 1 ←2番目のリクエスト
[Sun Nov 27 13:06:52 2011] [error] [client 127.0.0.1] TEST 1 ←3番目のリクエスト
[Sun Nov 27 13:06:57 2011] [error] [client 127.0.0.1] TEST 2
[Sun Nov 27 13:06:57 2011] [error] [client 127.0.0.1] TEST 2

で、先頭のリクエストを待っていることがわかる。もう一度、同じURLに3回リクエストすると、今度は、

[Sun Nov 27 13:07:55 2011] [error] [client 127.0.0.1] TEST 1
[Sun Nov 27 13:07:55 2011] [error] [client 127.0.0.1] TEST 1
[Sun Nov 27 13:07:56 2011] [error] [client 127.0.0.1] TEST 1
[Sun Nov 27 13:08:00 2011] [error] [client 127.0.0.1] TEST 2
[Sun Nov 27 13:08:00 2011] [error] [client 127.0.0.1] TEST 2
[Sun Nov 27 13:08:01 2011] [error] [client 127.0.0.1] TEST 2

と、待たずにバックエンドに送られる。hit for pass キャッシュを見ていることがわかる。

Varnish 2.1.3 と 3.0.2 で確認した。


参考まで、Varnish の起動・終了に使ったスクリプト

start.sh

#! /bin/sh

DIR=/Users/koseki/tmp/varnish
VARNISHD=/usr/local/varnish/sbin/varnishd

$VARNISHD -a :8080 \
          -T localhost:6082 \
          -P $DIR/varnishd.pid \
          -n $DIR/work \
          -f $DIR/default.vcl \
          -S $DIR/secret \
          -s file,$DIR/varnish_storage.bin,10M

stop.sh

#! /bin/sh

DIR=`dirname $0`
cat $DIR/varnishd.pid | xargs kill
rm $DIR/varnishd.pid

2011-11-09

右寄りのプログラマを粛正する。 01:18  右寄りのプログラマを粛正する。を含むブックマーク  右寄りのプログラマを粛正する。のブックマークコメント

まずこれを10回読もう。

コードが2段階以上右に寄ったら、右足はウンコ踏んでると思いましょう。無闇とエディタの横幅を広げるのも良くない。広いディスプレイは甘え。

つぎこれ。

function foo() {
    if (cond) {
        :
        :
        :
        :
    }
}

こういうのは最低です。下のように書きます。

function foo() {
    if (! cond) return; // ガード節で、さっさと帰らせる。
    :
    (正常処理)
    :
}

無駄にインデントが深くなりません。意図が明確になります。

下のようなコードも良くない。

function foo() {
    if (condA) {
        :
        :
    }
    if (condB) {
        :
        :
    }
}

右に寄りすぎ。メソッドを分割することを考えます。