myfinderの技術や周辺的活動のblog

2009年12月15日火曜日

DBIのDBハンドルメソッドとステートメントハンドルメソッドの対応メモ

DBIの各メソッドの呼び出し関係のメモ。

各メソッドと裏で呼んでるメソッド
・DBハンドルメソッド
1. selectrow_array
- fetchrow_arrayref

2. selectrow_arrayref
- fetchrow_arrayref

3. selectrow_hashref
- fetchrow_hashref

4. selectall_arrayref
- fetchall_arrayref

5. selectall_hashref
- fetchall_hashref

6. selectcol_arrayref
- fetch

7. prepare_cached
- prepare

・ステートメントハンドルメソッド

8. execute_array, execute_for_fetch
- execute

9. fetchrow_arrayref
- execute

10. fetchrow_array
- none

11. fetchrow_hashref
- execute

12. fetchall_arrayref
- fetch, fetchrow_hashref

13. fetchall_hashref
- fetch

2009年9月27日日曜日

Snow LeopardでShipItを使えるようにする

PerlモジュールのリリースツールShipItを勧められたので入れてみた記録。

1.必要なモジュールのインストール
ShipItを使うのに必要なモジュールをインストールする

$ cpan -i ShipIt
$ cpan -i AppConfig::Std
$ wget http://search.cpan.org/CPAN/authors/id/B/BR/BRADFITZ/cpan-upload-http-2.4.tar.gz
$ tar zxvf cpan-upload-http-2.4.tar.gz
$ cd cpan-upload-http-2.4
$ perl Makefile.PL
$ make
$ make install
$ cpan -i ShipIt::Step::CommitMessageWrap

2.「~/.pause」ファイルの準備
ホームディレクトリに.pauseファイルを作成

$ vim ~/.pause
$ cat ~/.pause
user xxxxxx
password xxxxxxx
mailto xxxxxxx@xxxxxx.xxx
$ chmod 600 ~/.pause

3.「.shipit」ファイルを用意する
ShipItを利用するには、プロジェクトのトップディレクトリに.shipitファイルが必要。
Module::Setupとかを使っていれば自動的に生成されているので特に気にする必要はない。

4.dry-runオプションで試してみる
いきなり実行するのはよくないので、「--dry-run」をつけて実行して結果を確認する。

5.おわり
ここまでで使えるようになっているはず

2009年9月21日月曜日

DBD::mysqlのインストールができないとお嘆きの方へ

もしこの記事を読んだ方が下記のようなエラーメッセージでインストールできないでいるのであれば、きっと後述の解決策でうまくいくでしょう

t/80procs.t ................. 1/29 DBD::mysql::db do failed: alter routine command denied to user ''@'localhost' for routine 'test.testproc' at t/80procs.t line 41.
DBD::mysql::db do failed: alter routine command denied to user ''@'localhost' for routine 'test.testproc' at t/80procs.t line 41.

このメッセージは、テストスクリプトがDBに接続しにいく際のユーザ名が設定されていないために出ているもので、ちゃんと指定すればテストにパスできます

1.cpanシェルからインストールする場合

> o conf makepl_arg "--testuser=root"
> install DBD::mysql

2.tar玉からインストールする場合

perl Makefile.PL --testuser=root

Snow LeopardでPerlの開発環境を整える

最近MacのOSをSnow Leopardに入れ替えてPerlの環境を確かめたところ、残念なことにバージョンが5.10.0だったりした
なのでPerl5.10.1をインストールしてlocal::libを使えるようにするところまでを記録しておきたい
※この記事はXcode(開発環境)が入っていることが前提

そろそろMac新しいの買いたい&以前までは割と考えずにモジュール入れまくってたから次はちゃんと管理したい
などという方のお役に立てば幸いかなと

1.Perl5.10.1の入手とインストール
このへんは弾さんの記事をみてやるとよい

2.環境変数の設定
~/.basrhcに/usr/local/binを見に行くよう設定

export PATH="/usr/local/bin:$PATH"

3.perl -vで確認

$ perl -v

This is perl, v5.10.1 (*) built for darwin-2leve

これでこのユーザの環境ではperl5.10.1が使えるようになりました。

4.local::libの設定
leopardの設定と同様です

5.local::libをSVNで管理する
local::libの中身をSubversionに入れておくと、インストールした内容の記録とか、ややあって戻したいときもすぐに戻せるので便利
手順は(自分の環境では)下記の通り

$ mkdir ~/Development/svn/local-lib
$ cd ~/local-lib
$ svn import -m 'init local::lib' ~/local-lib/ file:///Users/user/Development/svn/local-lib
$ mv ~/local-lib ~/local-lib.bak
$ rm -rf ~/local-lib
$ svn co file:///Users/user/Development/svn/local-lib .

6.もとに戻したい場合
元々のPerlを使いたい場合は/usr/bin/perlを明示的に利用するか、ユーザのPATH設定を削除すれば元の5.10.0を使いにいくようになる
また、local::libを撤収したい場合は、~/.bashrcにある環境変数の設定を削除し、~/local-libディレクトリを消せばOK

2009年9月13日日曜日

DBIx::Encodingというモジュールを書いた

YAPCおつかれさまでした。

YAPC中、今まさに課題になっているDB周りの問題を解消すべくDBIx::Encodingというモジュールを書きました。
このDBIx::EncodingはDBIのサブクラスで、executeとfetchの際に指定した文字コードでencode/decodeしてくれるものです。

そもそもDBの文字コード設定がUTF8なら余り悩むこともないのですが、世の中いろいろと事情があってDB側を変更できない事も多いでしょう。
そんなときにこのモジュールを使うと、DBI側で文字コードをencodeしてinsert/updateしてくれ、selectしたときにはutf8 flagを有効にした文字列を返してくれます。

使い方はSYNOPSISにもありますが、下記の通り

my @dsn = (
'dbi:mysql:host=localhost;database=mysql;mysql_socket=/tmp/mysql.sock;',
'root',
'',
{
RootClass => 'DBIx::Encoding',
encoding => 'cp932',
},
);
my $dbh = DBI->connect(@dsn) or die;

アトリビュートに設定を渡すか渡さないかでDBIx::Encodingを利用するかしないか決められるので簡単です。

SEE ALSO
生 DBI ユーザーのための DBI Cookbook (2)

※9/21追記
githubに移しました->こちら

2009年9月3日木曜日

「実践Common Lisp」読書録3

前回は属性リストを作る関数を定義してみた。
なので今回は属性リストを複数保持する変数を定義したり、その変数の中身をdumpする関数を定義してみる。

1.変数の定義
前回作った属性リストを複数保持するための変数を定義する。
変数の定義はdefvar(define variable)マクロを使う。

* (defvar db nil)


2.変数に要素を追加
この変数に要素を追加するにはpushマクロを利用する。

* (push (music "群青日和" "東京事変" 7) db)

((:TITLE "群青日和" :ARTIST "東京事変" :RATE 7))
* (push (music "喧嘩上等" "東京事変" 1) db)

((:TITLE "喧嘩上等" :ARTIST "東京事変" :RATE 1) (:TITLE "群青日和" :ARTIST "東京事変" :RATE 7))


3.変数の中身をみる
変数の中身を確認するだけであれば、単にREPLに変数名を渡せばよい。

* db

((:TITLE "喧嘩上等" :ARTIST "東京事変" :RATE 1) (:TITLE "群青日和" :ARTIST "東京事変" :RATE 7))

ただ、これだけだと先ほど変数に格納したときに出力されたものと何ら変わらなくて面白くない。
そこで、もう少し読みやすい形に出力してみる。

4.dbの全要素を整形して出力
変数dbにはいくつかのレコードが入っているが、これを一つ一つ処理するにはdolistマクロを用いる。
また、出力内容を整形する場合にはformat関数を用いる。
組み合わせると下記のようになる。

* (dolist (record db) (format t "~{~a:~10t~a~%~}~%" record))
TITLE: 喧嘩上等
ARTIST: 東京事変
RATE: 1

TITLE: 群青日和
ARTIST: 東京事変
RATE: 7

NIL

dolistはよいとして、ここで気になるのはformat関数である。
format関数は少なくとも2つの引数を取る。
最初の1つ目が、標準出力を表すtで、2つ目がフォーマット文字列である。
フォーマット文字列の詳細はこちらのページに任せる

5.format関数
format関数は「~{」と「~}」に挟まれた部分にある指示子を処理していく。
先ほどのフォーマット文字列では最後が「~%」となっていたが、これは一つ余分に改行コードを出力するもので、先ほどの出力結果と下記出力結果で多少違う事がわかると思う。

* (dolist (record db) (format t "~{~a:~10t~a~%~}~%" record))
TITLE: 喧嘩上等
ARTIST: 東京事変
RATE: 1

TITLE: 群青日和
ARTIST: 東京事変
RATE: 7
* (dolist (record db) (format t "~{~a:~10t~a~%~}" record))
TITLE: 喧嘩上等
ARTIST: 東京事変
RATE: 1
TITLE: 群青日和
ARTIST: 東京事変
RATE: 7
NIL

最後の~%の有無で、1レコード毎に入っていた改行部分が変化しているのがわかる。

今回はこのくらいで。
次回はファイル入出力の予定。

ではまた。

2009年9月2日水曜日

「実践Common Lisp」読書録2

引き続き「実践Common Lisp」やります。

今回はLispオペレータのさわりのあたり(リスト)を。

1.リスト
Lispのリストはlist関数で作る。
list関数は複数の引数からなるリストを返す関数(まんまですが)

* (list 1 2 3)

(1 2 3)

リストは入れ子にもできる。

* (list 1 (list 1 2) 2 3)

(1 (1 2) 2 3)


2.属性リスト
シンボルとその要素を交互に並べるリストを「属性リスト」といい、属性リストはgetf関数でシンボルを指定して値を返す事ができる。

* (list :a 1 :b 2 :c 3)

(:A 1 :B 2 :C 3)
* (getf (list :a 1 :b 2 :c 3) :a)

1

実行結果からわかるように、getf関数を使うと属性リストをハッシュのように利用できる。

3.属性リストを使って関数を定義する
例えば3つのフィールド(タイトル、アーティスト、レート)を受けとって属性リストを返す関数を定義してみる

* (defun music (title artist rate) (list :title title :artist artist :rate rate))

MUSIC

defunというのはdefine functionの略で、関数定義という意味になる。
この関数を用いて曲を表す属性リスト(レコード)を作りたい場合、下記のようにmusic関数を呼べばよい。

* (music "群青日和" "東京事変" 7)

(:TITLE "群青日和" :ARTIST "東京事変" :RATE 7)


次回はここで作成した属性リストを複数保持する変数を定義したり、その変数の中身をdumpする関数を定義するなどする。

2009年8月31日月曜日

「実践Common Lisp」読書録

ある方から「実践Common Lisp」を譲っていただいた。
折角なので読書(写経)録をつけてみたい。

この本って、既に全部公開されてるものの訳本らしいすね。

Common Lispが一体なんなのかという話はここなどに任せておくとして、主に手を動かしてみた記録を晒します。
あ、ちなみに関数型言語は全然やったことないです><

1.Lisp処理系のインストール
要は実行環境の整備。
MacのCommon Lisp動作環境について調べてみたら、2ch評価でSBCLがよさげってな話らしいのでこれを採用したい。
(他にいいのがあったら教えてください><)

このサイトを参考にしつつ設定する。
ダウンロードしたパッケージを解凍してinstall.shを実行すればインストールできる、割と手軽。
その際にINSTALL_ROOT環境変数を設定するのを忘れずに。

その後sbclコマンドを打つと下記のようになる。

$ sbcl
This is SBCL 1.0.30, an implementation of ANSI Common Lisp.
More information about SBCL is available at .

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
*

これでとりあえず実行環境はできた。

2.Hello, World
sbclを起動すると、そのままLispプロンプトになるので、そこにプログラムを打てば実行される。

* "Hello, World"

"Hello, World"

こんな感じ。

3.関数
ただのHello, Worldしただけでは別に面白くも何ともないので、早速「文字列を標準出力に出力する」副作用を持ったコードを書いてみる。

* (format t "Hello, World")
Hello, World
NIL

formatというのは関数で、その後につく「t」と「出力対象の文字列」は必須らしい。
書式は下記の通り。

(format destination control-sequence arg 0 ... arg n )

今回の場合第一引数に「t」を指定したが、これは標準出力に出すもの。
出力結果の後の「NIL」が気になるが、これはformatを評価した結果をREPLが出力したもの。
「NIL」はLispにとっての「偽」と「null」である。

4.REPLって?
Lispプロンプトでは、シェルのようにコマンドを1行ずつ読み込んで解釈するのではなく、Lispの式を読み込み、評価し、その結果を出力する。それが終わるとまた次の式を入力できるようになる。
そういうサイクルを「read-eval-printループ」といい、縮めて「REPL」というそうだ。

5.REPLのサイクル
REPLの動作を簡単におさらいしてみる。

1: * 10
2: 10
3: *

1行目の「10」は最初に入力したもので、「reader」はこの「10」を読み取り、数値の10を表すLispオブジェクトを作成する。
このオブジェクトは「自己評価型のオブジェクト」といい、「evaluater(eval)」に与えられるとオブジェクト自身として評価される。
そのオブジェクトが「printer(print)」に渡され、2行目に「10」が表示され、3行目で次の入力を受け付けるというサイクルになっている。

6.関数の定義
Lispにおける関数の定義は「defun」という式を利用する。

* (defun hello-world () (format t "hello, world"))

HELLO-WORLD

「defun」のあとの「hello-world」が関数名。
関数名の次の「()」は引数リストだが、今回は引数を取らない関数なので空になる。
引数リストの次の括弧が関数の本体ということになる。
一旦関数を定義すれば、下記のように呼び出して利用できる。

* (hello-world)
hello, world
NIL


7.作業の保存
先ほど定義した関数はプロンプトを終わらせると消え去ってしまう。
もったいないので実行ファイルに書き出して、使えるようにしてみる。(参考サイト)

* (sb-ext:save-lisp-and-die "hello-world-bin" :executable t :toplevel 'hello-world)
[undoing binding stack and other enclosing state... done]
[saving current Lisp image into hello-world-bin:
writing 2784 bytes from the read-only space at 0x04000000
writing 1712 bytes from the static space at 0x04100000
writing 25530368 bytes from the dynamic space at 0x10000000
done]

ただこの手法、リンク先にも書いてある通りやたらとサイズがでかくなる。

$ ls -lha
total 50336
drwxr-xr-x 2 user staff 136B 9 1 01:00 .
drwxr-x--- 15 user staff 544B 9 1 00:55 ..
-rwxr-xr-x 1 user staff 25M 9 1 01:00 hello-world-bin
-rw-r--r-- 1 user staff 49B 9 1 00:56 hello-world.lisp

25MBとかどんだけ。。。実用じゃないすね。
誰かいい方法教えてください><

今日はとりあえずここまで。

Vimperatorを導入

LLTVの何かのセッションでVimperatorを知ったのでインストールしてみた。

VimperatorというのはFireFoxのアドオンで、操作をvim風にしてくれるというもの。
いまvim力向上に取り組んでいるところなので、良さそうと思って入れてみた。

インストールはFireFoxのアドオン追加で簡単にできる。
再起動後はナビゲーションバーの表示が消えているので驚かないように。

基本操作は下記ページにあります。
http://project-p.jp/halt/wiki/Vimperator
http://d.hatena.ne.jp/toshi123/20070629/p1

早速使い始めたのですが、vimmerはとりあえず入れておいて損のないアドオンだと思います。
というか入れた方がFireFoxの操作がさらに快適になるかも。

2009年8月19日水曜日

hyoshiokさんが楽天に。

最近忙しめで、フィードを消化できてなかったのだけどもちょっと驚いた事1点。

YLUGとか、最近だと勉強会勉強会で有名なhyoshiokさんが楽天に転職してたらしい。
http://b.hatena.ne.jp/entry/d.hatena.ne.jp/hyoshiok/20090803%23p1

知らなかったなぁ〜
(追記:はてブしてたことを後で思い出した)
最近「独立行政法人情報処理推進機構」に出向していらっしゃったというところまでは聞き及んでいましたが。

生涯プログラマ宣言されたhyoshiokさんなので、楽天でもきっとプログラマとしてバリバリやっていらっしゃるんだろうな〜
Romaとかfairyが今年オープンソースになるらしいので、その辺にコミットしてらっしゃるのかなと想像してます。

実はまだhyoshiokさんの書いたコードは見た事がないんですが、これを機にお目にかかる事が出来るのかなとわくわくしてます。

プログラマ35歳限界説を打ち破ったプログラマとして、楽天でもぜひぜひ頑張って、若輩プログラマな自分にも勇気を与えて欲しいと思う所存です><

2009年7月20日月曜日

Leopardでlocal::libを設定する

CPANモジュールの管理はいろいろ大変で、単にcpanコマンドでインストールしていると管理が行き届かなくなったり、モジュールのバージョン違いを試すのが難しくなったりする。
そこで「local::lib」を使って、ユーザ領域だけのCPAN環境を作ってみた。

0.前提
今回は~/localに環境を作る。
なので事前に「$ mkdir ~/local」などとしてディレクトリを作っておくこと。

1.local::libのインストール
CPANから最新のアーカイブを取得してインストールする。
取得とか解凍は割愛。

$ perl MakeFile.PL --bootstrap=$HOME/local
この「--bootstrap」オプションを指定することで、$HOME/local/lib/perl5にlocal::libが必要とするモジュールが入る。
終了したら「make && make install」してインストールを実行。

2.シェルの設定
必要な環境変数設定を~/.bashrcに追記する。

echo 'eval $(perl -I$HOME/local/lib/perl5 -Mlocal::lib=$HOME/local)' >>~/.bashrc
注意点として、~/.bash_profileから~/.bashrcが呼ばれていない場合は呼ぶように設定を追記しておくこと。
しないと、いつまでたっても環境変数が設定されない。

3.ローカル環境の準備
ここまでできたら、下記のようにすれば環境設定は完了するはず。

$ cpan
> install Bundle::CPAN
ちゃんと完了したかどうか調べるために、何かインストールしてみるとよい。
設定が完了していれば「~/local/lib/perl5/」以下にインストールされているはずである。
さらに気になる人は、下記ワンライナーでローカルの環境が@INCに入っているか確認できる。

$ perl -MData::Dumper -e 'print Dumper @INC'


あわせて読みたい
http://blog.hide-k.net/archives/2009/02/locallibrootcpa.php

2009年7月19日日曜日

VMware Serverがトラブったと思ったら - カーネルアップデート編 -

LinuxでVMware Serverを運用しているときに起こった問題についての記録。

カーネルのアップデートを掛けて再起動したあと、VMware Serverのコンソールにはつながるのに、仮想マシンが起動しない(接続状態の進捗が95%で止まってしまう)問題が発生することがある。
そんなときは、VMwareに関するプロセスが走っていない状態でvmware-config.plを再度実行すればよい。
(にっちもさっちも止まらない><という場合は最悪killするしかないかもですが)

不意の電源断などで再起動が掛かかると、読み込まれるカーネルが新しいものになったりするのでVMware Serverを運用するときは自動アップデート等は切り、必要に応じて手動で実施するのがトラブルが少なくなるので良いと思います。

すっかり忘れてたYO
いけませんね。。。

あわせて読みたい:
VMwareServerがカーネルバージョンアップ後にエラーで起動しない件

Perlモジュールの開発方法まとめ

目的
Perlモジュールの開発環境を整えるいち手法をまとめる。
最近だとModule::Setupが使われている?ぽいのですが、このエントリではModule::Starter::PBPを使ったやり方について書く。
(もう野良.pmファイルをhogeるのは嫌なのじゃよ〜><)

対象環境
LinuxもしくはMacOSX Leopardが対象。
Windows環境でのやり方はわかりません><

必要なモジュールのインストール
何はともあれ、セットアップに必要なCPANモジュールをインストールする。

$ sudo cpan -i PPI
$ sudo cpan -i Module::Build
$ sudo cpan -i Test::Pod
$ sudo cpan -i Test::Pod::Coverage
$ sudo cpan -i Test::Perl::Critic
$ sudo cpan -i Module::Starter
$ sudo cpan -i Module::Starter::PBP
$ sudo cpan -i Module::Starter::Smart
Module::Starter::Smartは、モジュール開発中に同じパッケージ以下にさらにモジュールを追加したくなったときに必要なので入れておくべき。

Module::Starter::PBPの初期設定

$ perl -MModule::Starter::PBP=setup
Please enter your full name: YourName
Please enter an email address: mailaddr@example.com
これで「~/.module-starter/PBP/」というディレクトリがホームに出来る。
一部ひな形となるファイルの修正が必要なので、対応する。

$ vi ~/.module-starter/PBP/Module.pm
Module.pmを下記のように修正する。

use version; $VERSION = qv('0.0.3');
# ↓
use version; our $VERSION = qv('0.0.3');
また、Makefile.PLにも修正が必要なので、下記内容に書き換える。

$ vi ~/.module-starter/PBP/Makefile.PL


use lib qw(lib);
use Module::Build::Compat;

Module::Build::Compat->run_build_pl(args => \@ARGV);
Module::Build::Compat->write_makefile(build_class => 'Module::Build');


Module::Starter::Smartの設定
Module::Starter::PBPだけでは一つのpmファイルしか作れないので、ちょっと凝ったモジュールを作ろうとすると少々面倒。
なので、Module::Starter::Smartの設定も併せて行なっておく。
(※Module::Starter::Smartはインストールしただけでは有効にならないので注意)

$ vi ~/.module-starter/config
下記のように「Module::Starter::Smart」という記述を追加する。

plugins: Module::Starter::PBP Module::Starter::Smart


モジュールのひな形を作る
ここまでで、Module::Starter::PBP周りの設定ができたので、任意のディレクトリでモジュールの開発を始められる。
モジュールのひな形を作るには、下記コマンドを利用する。

module-starter --module=MODULE::NAME
このコマンドによって、カレントディレクトリにモジュールのひな形が生成されるので、あとはがしがし開発していけばOK

モジュールを追加する
機能毎、あるいはMooseなどでクラスを分けるときに、.pmファイルを追加したい要求が出他場合、下記コマンドで.pmファイルを現在のひな形に追加できる。

$ module-starter --module="MODULE::NAME::ADDMODULENAME" --distro="MODULE-NAME"


ビルドのテスト
開発が出来たら、ビルドできるかどうかテストする。

$ cd MODULE-NAME
$ perl Build.PL
$ perl Build
$ perl Build test


パッケージング
ビルドまでウマくいったら、後は配布可能な形にパッケージングするだけ。

まず、ひな形のBuild.PLファイルに、依存しているモジュールを追記する。

$ vi Build.PL


requires => {
'Test::More' => 0,
'version' => 0,
# この行以下に依存モジュールを追記
},
次に、パッケージングに不要なファイルを除くためのMANIFEST.SKIPファイルを作成

$ vi MANIFEST.SKIP


\bRCS\b
\bCVS\b
^MANIFEST\.
^Makefile$
^Build$
^Build.bat$
^_build/
\.(bak|tdy|old|tmp)$
~$
^blib/
^pm_to_blib
\.cvsignore
\.gz$
ここまでできたら、MANIFESTファイルを作成してパッケージングする。

$ perl Build manifest
$ perl Build dist
$ perl Build disttest
「perl Build disttest」は、作成したディストリビューションの動作確認を行なうものなので忘れずに実施したい。

ここまでやると、カレントディレクトリに「MODULE-NAME-v0.0.3.tar.gz」という名前のファイルが出来上がる。
モジュールを配布したい場合はこのアーカイブを利用すればOK


参考サイト
正しいPerl/CGIの書き方
はじめてのPerlモジュール開発メモ
Module-Starterのカスタマイズ
Module::Starter使ってみる

2009年7月15日水曜日

Apache1.3系の処理時間を出力するコードについて少し追ってみる

Apache1.3のログフォーマットの指定に「%T」を追加すると、各リクエストの処理時間を秒単位でログに出力することが出来る。
が、大抵のリクエストは1秒以内で終わるので、大抵0になってしまう。

ここで気になったのが、1秒に満たない場合どこまでを0秒として扱っているのかという点。
つまり四捨五入なのか小数点以下切り捨てなのかなどなど。

あまりググっても出てこなかったので、ソースを開いてみた。
(C&C++バリバリわかる!とかApacheのソースコードバリバリわかる!というわけじゃないので間違った認識だったりしたら突っ込みいただけるとうれしいです)

LogFormatの指定については「src/modules/standard/mod_log_config.c」に書かれている。

static struct log_item_list {
char ch;
item_key_func func;
int want_orig_default;
} log_item_keys[] = {

{
'a', log_remote_address, 0
},
{
'A', log_local_address, 0
},
{
'b', clf_log_bytes_sent, 0
},
{
'B', log_bytes_sent, 0
},
{
'c', log_connection_status, 0
},
{
'e', log_env_var, 0
},
{
'f', log_request_file, 0
},
{
'h', log_remote_host, 0
},
{
'H', log_request_protocol, 0
},
{
'i', log_header_in, 0
},
{
'l', log_remote_logname, 0
},
{
'm', log_request_method, 0
},
{
'n', log_note, 0
},
{
'o', log_header_out, 0
},
{
'p', log_server_port, 0
},
{
'P', log_child_pid, 0
},
{
'q', log_request_query, 0
},
{
'r', log_request_line, 1
},
{
's', log_status, 1
},
{
't', log_request_time, 0
},
{
'T', log_request_duration, 1
},
{
'u', log_remote_user, 0
},
{
'U', log_request_uri, 1
},
{
'v', log_virtual_host, 0
},
{
'V', log_server_name, 0
},
{
'X', log_connection_status, 0
},
{
'\0'
}
};

これの

{
'T', log_request_duration, 1
},

が対応する関数を呼び出しているようで、その関数が

static const char *log_request_duration(request_rec *r, char *a)
{
return ap_psprintf(r->pool, "%ld", time(NULL) - r->request_time);
}

というような実装だった。
time関数による現在時間とリクエストのあった時間を引いている。
この関数って精度が1秒だったかな?なので、1秒に満たない場合は0として扱われると捉えてOKかなと。

すなわち、1秒に満たない場合は0、1秒以上2秒以下の場合は1と表示されるはず。

2009年6月30日火曜日

ハードディスクをまるっとコピーして引っ越す

ハードディスクが壊れそうになってきたり、もっと大きい容量に乗り換えたい時にやる手として、増設したHDDにデータをcpやらmvやrsyncなんかで移動させたりすることもあるかなと思う。
が、それだと数十GB単位のデータをコピーするときにとんでもねぇ時間がかかったりして、大変非効率的。
そんな時にはddコマンドを使うのがよい。

利点
  1. LinuxでもWindowsでも、この手でHDDをまるっとコピーすることができる。
  2. 容量の大きいHDDにコピーした場合は新たなパーティションとして、空き容量部分を追加できる。
  3. もとのディスクのパーティションがLVMで作られていれば、空き容量部分を利用して、既存の領域を拡張できちゃう。
やり方
空いているPCに、コピー元HDDとコピー先HDDを積んで、以下のコマンド一発でOK。
この場合はsdaがコピー元、sdbがコピー先です。間違えるとカオスなので、絶対に確認してからコマンドを打つべし!

# dd if=/dev/sda of=/dev/sdb bs=1024M conv=sync,noerror


処理時間の目安
容量時間
20GB10
80GB40分
160GB80分
250GB2時間
500GB4時間

某社様が、たいそう参考になる資料をUPしてくれています。感謝

補足
経験値的にはPATAだと40GBで30~40分かかります。

Xenで仮想サーバ環境構築 その1

先日衝動買いしてスペックアップさせたサーバで、Xenを利用したクラスタを構築することにした。
今運用しているreposサーバでは、構築する時にちょうどVMware Server 2.0がリリースされたのでそれを利用してみたが、今回はXenでやった。

ホストとなるOSのインストールはCentOS5.3を利用する、そのインストールについては割愛。
今回はXenのセットアップまで。

Xenのインストール
CentOSインストール時点で「仮想化」のサポートを有効にしていない場合は下記コマンドでXenをインストールしておく。


# yum groupinstall Virtualization


Xenの設定

「/etc/modprobe.conf」の最下行に「alias scsi_hostadapter xenblk」を追加。


#vi /etc/modprobe.conf
・・・
alias scsi_hostadapter xenblk


Xen対応のKernelを利用するので「/etc/sysconfig/kernel」の「DEFAULTKERNEL=kernel」行を「DEFAULTKERNEL=kernel-xen」に変更。


# vi /etc/sysconfig/kernel

#DEFAULTKERNEL=kernel
DEFAULTKERNEL=kernel-xen


Xen対応のKernelで起動させるため、「/boot/grub/menu.lst」「default=X」の番号を変更。


# vi /boot/grub/menu.lst

#default=1
default=0


ここまでできたら再起動する。
再起動後、「xm list」と入力し、以下のように表示されればXenの最初の一歩は完了。


# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 454 1 r----- 16.5


今日はとりあえずここまで。

2009年6月28日日曜日

強度の高いパスワードを作りたいときのTips

Linuxのアカウントを作るときやら、どこぞのWebサービスなどに会員登録するときにパスワードを考える必要があるタイミングは多いと思う。
が、考えるのはめんどい上に、自分で考えたパスワードの強度が高いとは限らない。

そんなときに使える一手に、apgコマンドがある。
apgコマンドは、ある程度音読可能で強度の高めなパスワードが生成できる。
cygwinでもインストール可能なので、Windowsの人でもいけます><

apgは標準では入ってないので、aptやyumでインストールすること。

使用例

$ apg -n 10 -m 10 -x 10 -M NCL -E 0O1I -t
wujcewHod8 (wuj-cew-Hod-EIGHT)
Lalj6quoig (Lalj-SIX-quoig)
(途中省略)
GoujAmbij8 (Gouj-Am-bij-EIGHT)

これで作ったパスワードが本当に強いパスワードなのかどうかを、MSのパスワードチェッカーを使うなどして確認するとmore betterなんじゃないかと。

2009年6月27日土曜日

ApacheでHTTPメソッドを制限したいときにやる事

Subversionを使うときは大抵WebDAVを使うと思うのですが、認証のオーバーヘッドを減らす工夫の一つとして「読み出しの時だけBasic認証をかけない」というやり方があるのでメモ。

ApacheのディレクティブにはLimitExceptというものがあり、ディレクティブの引数に含まれていないHTTPのアクセスメソッドに対して適用するためのアクセス制御ディレクティブを記述することができる。

設定例
#---------------------------------
AuthType Basic
AuthBasicProvider ldap
AuthName "Basic Auth"
AuthzLDAPAuthoritative off
AuthLDAPURL ldap://hogehoge?uid
<limitexcept>
require valid-user
</limitexcept>
#---------------------------------
こうしておけば、書き込みを伴う(コミットするとか)アクセスに対してだけ認証をかけ、読み出しに対しては認証がかからなくなる。

Unicode::EastAsianWidthを使う

文字列を特定サイズの画像に埋め込むプログラムを書く機会があり、文字幅を計算する必要に迫られた。
すなわち「全角」を2文字「半角」を1文字分として数えたい、というケース。
(画像に埋め込むフォントは等幅を想定してます)

文字幅を計算する必要がある、ということはlengthなんかの文字数でのカウントはできない。

そこでいろいろ考えたりググったりしてみたところ、tokuhiromさんのblogでUnicode::EastAsianWidthの話を見つけた。

このモジュールはUnicodeコンソーシアムの定めるEastAsianWidthに基づき「全角に該当する文字」「半角に該当する文字」etcにあたるUnicode属性を提供するもので、useすると下記のようなUnicode属性が正規表現で使えるようになる。

/(?:(\p{InFullwidth}+)|(\p{InHalfwidth}+))/g

これを使うと「文字幅」をカウントできるようになるのです。
下記はそのプログラムの一例

use strict;
use warnings;

use Unicode::EastAsianWidth;
use utf8;

sub visualLength {
my $text = shift or '';

my $length = 0;

while ($text =~ /(?:(\p{InFullwidth}+)|(\p{InHalfwidth}+))/g) {
# 全角に該当すれば2、そうでなければ1インクリメント
$length += ($1 ? length($1) * 2 : length($2));
}

return $length;
}

my $text1 = "あいうえお"; # 10
my $text2 = "hogehoge"; # 8

print visualLength($text1), "\n";
print visualLength($text2), "\n";

多少冗長なコードかも。

ちなみにその「EastAsianWidth」の定義ってどんなん?という疑問がわいた方はここを見ると全部のってます。

補足
Unicode関係で超参考になったページ
http://totonica.s41.xrea.com/doc/delphi_tiburon/doc_unicode/eastasianwidth.htm

BloggerでPerlをシンタックスハイライトする

最近Perlプログラマになったので、このBloggerでもSyntaxハイライトをちゃんとできるようにしたいと思い調べてみた。

Bloggerで使えて結構良い感じなのが下記なのだが、これがPerlをサポートしていない。
http://code.google.com/p/syntaxhighlighter/

が、有志がPerl対応のためのコードを投稿してくれていた。
http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js

これをガジェットのJavaScriptに追加すれば、晴れてBloggerでもPerlのコードを載せられる。
いままでは適当にrubyとか指定していたが、今後はこれでやりたい。

ちなみにそのコードを踏襲すればどんな言語でもいける。
(というか自分でやればよかった。。。)

Syntax HighlightのPerlサポートテスト

perlサポートのテスト

use strict;

my $text = "Apple";

while ($text =~ /(?:(A)|(p)|(l)|(e))/g) {
if ($1) {
print $1, "\n";
}
elsif ($2) {
print $2, "\n";
}
elsif ($3) {
print $3, "\n";
}
elsif ($4) {
print $4, "\n";
}
else {
warn;
}
}

2009年6月21日日曜日

「サーバを箱から出してセットアップして使えるようにするまでをやる会」を開催した。

NTT-X Storeで安売りしていたExpress 5800 110Geを先日衝動買いしたので、セットアップする会を開催してみた。

http://atnd.org/events/826

atndとTwitterだけでゆるりと募集してみたところ、意外と反応があり、最終的に7人の方にお越しいただく事ができた。
今回は普段あまり触れない、いわゆる「箱もの」サーバに手を入れてセットアップしてみるまでをやった。

今回は思いつきで開催したにも関わらず、cesareさんとの新たな出会いもあったので、自分が思った以上に収穫があった。

細かい話は写真を誰かがUPしてくださると思うのでそちらを待ちつつ、110GeをCentOSで使うときの問題なんかをまとめておきたい。

2009年5月24日日曜日

エンジニアの未来サミット0905に行ってきた

昨年行きそびれたのだけども、今回運良く当選したので出てきました。

構成その他もろもろは他ブログあるいは公式ページに譲って、ここでは自分の感想、思う事などについてまとめる。

全体的なお話
登壇された方々と距離が近かったのが何より好印象。
特定のメールアドレスにメッセージを送ると、本文がスクリーンに流れる仕掛けになっていたのが面白く、コメントから話の流れが変わったりする時もあった。

あと、去年のクリスマス以来久々に生ござ先輩に会った。また焼肉したいです。

全体通しての感想

第一部は第二部に比して非常に落ち着いた雰囲気で進んだ。
進行役の吉岡さんが最近言及されているように、今は自分の意思一つでいろんな事ができるようになってきたことが挙げられていた。
その中でも気になった点は、勉強会の数は格段に増えたけども、そこで何かを発信する人としない人の差というのはますます出てきてるのかなと。
それを端的に表す発言として「勉強会に出て聞くだけの人は素人」というのがあった。

自分自身blogを書くとか、わずかずつではあるがLTで2桁の人を前に喋ることをこの半年ほどやって来たわけだけども、まだ成果にはなってない。
言うなればスタートラインにたったばかりなのであって、もっと自分に出来る事を積上げないとなと。

以前のLTでも挙げた内容とかぶるのだけども、発信した情報の価値を判断するのは受け手なので、少しでも「価値あるかな?」と思った事はblogなり勉強会で喋っていいと思う。

ダメだったらスルーされるかdisられるわけだけども。
むしろdisられた方が、より正しい情報を知る手がかりになる。

楠さんが「blogに間違った事を書いてしまうよりも、間違った認識のままでいることの方が怖い」という風におっしゃっていたが、超同意。

なので、発信することについては自重せずにやった方が良いと思う。

第二部は一部に比して会場の雰囲気もだいぶ変わって、よりリラックスというか、砕けた感じで話が進んだ。
弾さんのメガネとか良い大人が自重しろよwとか思ったけどそれがいいのかも。

第二部でも結構いろいろと良い言葉が拾えたのだけども、特に自分に刺さったのは
「自分のスイッチを知って、自覚することが重要」
という言葉。

セルフスターター型人間とかよく言われてますが、エンジニア的にはこの辺自分でスイッチが押せないと進むものも進まないなんて事がよくあるわけで、これは常々忘れないようにしたいと思うのです。公私とも。

結局
最終的に自分の中で行き着いたのは、自分に対する
「だまってコードを書けよハゲ」
という一言。

いい歳なんだししっかり成果見せられるように動こうよっと。

2009年5月14日木曜日

【とりあえずエントリ】OOPJog #4で走ってきた

GWも明けたので、恒例OOPJogで走ってきました。

今回のテーマは「再帰とポインタ」

すでにOOPじゃないんじゃねってな話ではありますが、ところがどっこいいろいろとためになる話が飛び出してきた。
特にgitの話。

id:tsuyoshikawaがtwitしているので、細かい話はそっちに譲る(というか詳しく書いてくれると思う)。

とりあえず今日は寝る。。。

2009年4月30日木曜日

[ニコニコ動画]なぜ0で割ってはいけないのか?

SocialWeb Japan #2に行ってきました。

28日にSocialWeb Japan勉強会 #2に行ってきました。
今回は後半からの参加でしたが、mixiとYahoo!といった大手サービス事業者の取り組みについて聞くところには間に合ったのでよかった。。。

内容についてはid:ZIGOROuさんのエントリがまとまっているのでそちらをご覧いただくといいです。

mixiの話
割と以前から公開されている内容について、現在の進捗と今後の公開スケジュールなどについて発表されていた。
「広告」「課金」「ファンド」を普及というか、開発の起爆剤にするということで、既にファンドで投資している会社もあるとのこと。

割とちゃんとしたプラットフォームを用意するよ〜という感じになっているが、モバイルのほうがどうなっていくのかが気になるところ。
「アプリ」という形がmixiモバイルのユーザに伝わるかな、とかそういうレベルから、開発どうやんのかな、とかまで。

Yahoo!の話
よくまとめられており、Yahoo!の今後の方向性について理解しやすい内容であったと思う。
特に、「つながり」についての考え方は参考になった。
  • 1way = いわゆる「お気に入り」などの1方向のつながり
  • 2way = いわゆる「お友達(相互承認)」などの双方向のつながり
  • Nway = いわゆる「コミュニティ」などの多対多のつながり

その他で特に気になったのは、「苦労していること」として発表されていた内容で
  • ソーシャル化の効果を、売上/利益で他の要因と切り分けて数値化するのが難しい
  • 金額換算すると、他のサービスや施策よりも効果が低い?
  • 全体最適VS部分最適(Y!全体としての最適とサービス毎の最適が違う)
  • 開発チームが部門別になっている(これはこのほど一つに統合したとのこと)

という点。
技術要素の絡む横断的施策を打ちたいときに、開発が部門単位に別れているといろいろと面倒事が多いんだろうなというのは容易に想像されるので、まとめるのは正しい動きだと思う。

おわりに
各社結構着々と進めている&方向性も定まってきているので、今年後半にかけての動きが気になるところ。
これについては6月くらいにまたSocialWeb Japanの会合が行なわれるそうなので、追いかけたいと思います。

直接関係ないけど、Poken持ってる人が結構居たことに驚き。
Poken APIなるものも公開されるそうなので、意外とそっちも面白いんじゃないかななどと感じました。
Pokenについてはまだいろいろと改善の余地ありまくるなと感じるのだけどもそれは気が向いたら別のエントリで書いてみたい。

いじょ。

2009年4月27日月曜日

17歳教

今日はどう書く?.orgにお題がいろいろあったので、その中の「17歳教」についてPerlで書いてみた次第。

use strict;
use warnings;
use Date::Simple;

my $birthday = $ARGV[0];

die "入力された日付フォーマットがおかしいです><" if ($birthday !~ /(\d{4})(\d{2})(\d{2})/);
die "入力された日付は存在しません><" if (!Date::Simple->new($birthday));
die "あなたはまだ17歳になってません><" if (((localtime(time))[5] + 1900) - $1 < 17);

my $countYear = ((localtime(time))[5] + 1900) - ($1 + 17);
my $countDay = Date::Simple->new() - Date::Simple->new(($1 + 17, $2, $3));
my $countMonth = $countYear * 12;
my $progressDay = (Date::Simple->new() - Date::Simple->new(((localtime(time))[5] + 1900, $2, $3)));

print "あなたは17歳と" . $countDay . "日です\n";
print "または\n";
print "17歳と" . $countMonth . "ヶ月と" . $progressDay . "日です\n";

「17歳教」についての詳細はこちらを参照のこと。おいおい。

2009年4月25日土曜日

GenesisLightningTalks Vol.15に出てきました。

今月もGenesisLightningTalksに出てきました。

今回のテーマは「DB」
だけども、データベースについて書かなければならないというわけではなく
「D」と「B」が入っていればよい、というもの。

今回は「どうしてもBlogが続かない」でDBとした。
このBlogを始めるまでに、実に二桁くらいのBlogをダメにしてきたのでその辺の原因などなどについて振り返ってみた話です。

動画は↓

2009年4月23日木曜日

OOPJog#2で走ってきました。

イベント詳細は→http://atnd.org/events/577

今週もOOP Jogで走りながらOOPに(類する)ことについて喋ってきた。
2回目になると、前回より余裕を持って走ることができた。

以下話した事の箇条書き。

・四角と長方形と正方形のis-a関係
・Key-Valueストレージについて
・Google的なサーバのスケール感覚?と、一般的なサーバのスケール感覚について

あんましOOPについての喋りが少なかった。。。反省。

終わった後に、「懇親会はアルコールじゃなくて、VAAMとプロテインバーにしましょう」と提案してみた。

2009年4月21日火曜日

Linuxシステム調査のためのコマンド パッケージ編


$ rpm -qa // インストール済みパッケージ一覧(量が多いので、lessなどに渡すとよい)
$ dpkg -i // 同上
$ rpm -ql // パッケージがインストールしたファイルの一覧
$ dpkg -L // 同上
$ rpm -qf // 指定したファイルが含まれるパッケージを表示
$ dpkg -S // 同上
$ rpm -Va // パッケージからインストールしたファイルが改変されていないかを確認

Linuxシステム調査のためのコマンド ユーザの調査


$ cat /etc/passwd // 登録されているユーザの情報
$ cat /etc/group // 登録されているグループの情報
$ w // ログイン中のユーザ情報
$ lastlog // 登録されているユーザのログイン情報
$ last // 最近のログイン記録

Linuxシステム調査のためのコマンド ネットワーク編


$ /sbin/ifconfig -a // NICの情報をすべて表示
$ cat /etc/sysconfig/network-scripts/ifcfg-eth{number} // NICの設定値を表示
$ hostname --fqdn // ホスト名のFQDN
$ netstat -lA inet // 接続を受け付けているポートや許可するIPを表示
# /usr/sbin/tcpdump // NICが送受信するすべてのパケット情報を表示
$ cat /etc/host.conf // 名前解決方法の優先順位を表示
$ cat /etc/resolv.conf // 名前解決に使用するDNSを表示
# /sbin/iptables --list // ファイアウォールのフィルタリング設定を表示
$ /sbin/route // ルーティングテーブルを表示

Linuxシステム調査のためのコマンド ランレベルなど編


$ cat /etc/inittab | grep id // 標準のランレベルを確認
$ /sbin/runlevel // 現在のランレベルを確認
$ ls -R /etc/cront.* // cronの内容を確認
$ /sbin/chkconfig --list // 自動起動の設定を一覧する
$ ls /etc/rc{runlevel}.d/S* // 指定したランレベルで自動起動するサービスの確認
$ /sbin/service --status-all // /etc/init.d以下に起動スクリプトがあるすべてのサービスのステータスを確認

Linuxシステム調査のためのコマンド システムライブラリ・ブートローダ編


$ cat /etc/ld.so.conf // /lib,/usr/lib以外にシステムライブラリが格納されているディレクトリ
$ /sbin/ldconfig -v | grep {library} // システムに認識されているライブラリのバージョン
$ ldd {command} // コマンド実行に必要なライブラリを表示


# cat /boot/grub/grub.conf // 起動時に使用する情報
$ cat /proc/cmdline // 起動時にカーネルに渡されたオプション

2009年4月20日月曜日

Linuxシステム調査のためのコマンド カーネル編


$ uname -r // 使用中のカーネルのリリース情報など
$ cat /proc/version // カーネルに関するより詳しい情報など
$ /sbin/lsmod // 現在カーネルが読み込んでいるモジュール情報など
$ /sbin/modinfo {module} // カーネルモジュールの情報を表示

Linuxシステム調査のためのコマンド ファイルシステム編


$ cat /proc/ide/{device}/model // ディスクドライブのモデル名
$ cat /proc/scsi/scsi // SCSI接続のデバイスについて
$ cat /proc/sys/dev/cdrom/info // CDROMのデバイスについて
# /sbin/fdisk -l /dev/{device} // ハードディスクの総容量など
$ cat /etc/fstab // マウントするパーティションの情報など
$ df -hT // マウントされているパーティションの情報など
$ cat /proc/mdstat // ソフトウェアRAIDデバイスの情報

Linuxシステム調査のためのコマンド ハードウェア編


$ dmsg // ハードウェアやシステムの基本的情報を表示
$ procinfo // ハードウェアやシステムの主要情報(カーネルのVer,メモリの使用状況)
$ cat /proc/cpuinfo // CPUの情報
$ cat /proc/interrupts // IRQの使用状況
$ cat /proc/ioports // I/Oポートアドレスの使用状況
$ free // メモリの使用状況
$ vmstat // 仮想メモリの情報
$ /sbin/lspci // PCI接続されている機器の情報
$ /sbin/lsusb // USB接続されている機器の情報

procディレクトリの中身をちらっと見てみる

カーネルとプロセスの関係を知りたい。
ということで、procディレクトリについてまとめて書いて、後で見られるようにしておく。

今日書いた内容についてはこのページに詳しい。

プロセスごとの環境

プロセスごとの環境とはそもそも何か。
それは、例えばカレントディレクトリやメモリ、環境変数を指す。
この辺の値はプロセス毎に別々のものを持っている。

この辺の情報が集まっているのが/procディレクトリで、特殊なディレクトリだが通常のディレクトリと同じようにアクセス可能になっている。

例えとして、Apacheのプロセス情報を覗いてみる。

# ps auxw | grep httpd
apache 21871 0.0 0.3 235300 12328 ? S Apr19 0:00 /usr/sbin/httpd


この場合、/proc/21872にApacheプロセスの情報が入っていることになる。
例えば当該プロセスのカレントワーキングディレクトリは

# ll /proc/21872/cwd
lrwxrwxrwx 1 root root 0 4月 20 00:18 /proc/21872/cwd -> /

という風にシンボリックリンクなっている。
この場合、Apacheのカレントワーキングディレクトリは/ということになる。

さらに、環境変数が知りたい場合は

# cat /proc/21872/environ | tr "\0" "\n"
HOSTNAME=ayumi
SHELL=/bin/bash
TERM=xterm-color
HISTSIZE=1000
USER=root
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
MAIL=/var/spool/mail/root
PATH=/sbin:/usr/sbin:/bin:/usr/bin
INPUTRC=/etc/inputrc
PWD=/root
LANG=C
SHLVL=3
HOME=/root
LOGNAME=root
CVS_RSH=ssh
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/usr/sbin/httpd

という風にすることで、当該プロセスの環境変数を知る事ができる。

他のプロセスにアクセスする

各プロセスには、「標準入力」「標準出力」「標準エラー出力」などがあり、「/proc/[pid]/fd」以下のものがそれにあたる。
例えば、特定プロセスの標準出力にメッセージを飛ばしたい場合、下記のようにコマンドを実行すると、指定したプロセスの標準出力に出力される。

# echo hello > /proc/{pid}/fd/1

ちなみに先ほどのプロセスを指定して、下記のような出力を送ると、Apacheのエラーログにメッセージが出力される。

# echo hello > /proc/21872/fd/2

※上書きされるのが嫌な場合は>>にすればOK

これを応用すると、ローカルのシェル同士でチャットごっこのような事ができる。
もちろん実際はチャットソフトを使うべきだけれども。

というわけで、プロセス毎の動作などを確認したいときなどはprocディレクトリ以下を見るとよいです。

2009年4月19日日曜日

Yellow Dog LinuxをPS3にインストールしてみる話その1

自宅にはなぜかPS3が2台あって、片方が埃をかぶっている状態だったのでPS3にLinuxをインストールしてみました。





細かいインストール手順などはこちらにお任せするとして、いろいろとインストール中に情報を集めたりしているところです。

気になるのがこのエントリ

確かに浮動小数点演算が得意なCellにWebサーバとかやらすのは違う気がする。
でも、何事もやってみないとわからないし、やったら面白いかもしれないのでやってみる。

と、いうことで今日はインストールするだけして終了。
ちゃんと立ち上がりましたよ。

2009年4月17日金曜日

OOPJog#1で走ってきました。

詳細はコチラ→http://atnd.org/events/555

いつものLTと違って、今回は走りながら技術系の話をするということであった。
意外と喋りながら走った方が続くんだなと感じたり。

ただ、やはりせいぜい一度に喋れるのが2〜3人で、最初にご挨拶させていただいてからJog中には喋れなかった方もいた。

毎週やるらしいので、今後も出ていろいろとお話をしたいなと思うイベント?でした。


P.S. 皇居1周、喋りながらだと45分くらいなので、結構ちゃんとした運動にもなりますよ。

2009年3月27日金曜日

Genesis Lightning Talks vol.14にでてきました。

遅ればせながらエントリ。
今回のテーマは「プロジェクタ無しのLT」ということで、どうしようか悩んだところでしたが

「みんなディスプレイと通信機能のあるデバイスもってるじゃん。」

と思いついたところで、今評価しているmod_chxjのテストを兼ねてページを作成して発表してみた次第。
ただ、このやり方は他の人のBlogでもご指摘いただいているように、
資料の進行を発表者が制御できないので、制御できないなりの資料作りをしなければいけないのでありました。

以下動画

2009年2月12日木曜日

Q4Mを使うときにやってはいけない一つのこと

ある日Q4Mを利用したシステムを運用していたところ、プログラマの方から

「Q4Mのテーブルが壊れたっぽいのだけども。。。」

との報告があり、状況を聞いてみた。
どうも、Queueに突っ込んだけども処理したくないデータがあったという理由で一部の行をDELETEしたとのこと。

で、早速DBを調べてみると、全部queue_waitで取り出したにも関わらず行数が0にならなかったり、
発行しているqueue_endが実行されずにずっとプロセスが残っていたりして大変カオスな状態になっていた。
(insertも止まっていた)

その場ではMySQLを強制的に再起動して、tableやschemaをdropして再作成してもらうことでことなきを得た。
が、今日帰ってきてQ4Mのページを見て謎が解決。
Q4Mの「Limitations and Known Issues」に

removal of multiple rows from a single DELETE statement is not atomic
(複数行に対する一つのDELETE文による削除はアトミックじゃありません)

と書いてあるじゃありませんか。
というわけで、これからQ4Mを使いたいという方でもし

「Queueに入れたけどやっぱり処理させたくないものは取りやめる」

というような要件がある場合
  1. 1行1DELETE文で削除する。
  2. もしくはignoreテーブルとかを作ってQueueを特定する情報を突っ込んでおいて、dequeueした時にignoreと照合する。
  3. QUEUEストレージエンジンを利用するschemaと、それ以外のschemaは分ける。
    (あるいは別にMySQL5.0を用意してそっちに入れとく)
などの対策が必要になるかなと思います。

なので、Q4Mを使うときには

複数行に対して1つのDELETE文による削除はやってはいけない

です。
以上、ご参考まで〜

2009年2月5日木曜日

gzipの効用

最近面倒を見ているサーバのログ出力が1日あたり2.5GB程度とサイズが大きくなり、
放置しておくとすぐにHDDを圧迫するため、日次で前日分のログをgzip圧縮することにした。

ここでふと、
「そういやgzip使う機会はそれなりにあるけど、どのくらいの容量をどのくらいの時間で処理できるんだろ」
という疑問が沸いたので測ってみた。
(今回使ったマシンのCPUはP4 2.8GHz)

$ time gzip -9 YYYYMMDD.log
real 2m27.162s
user 1m59.045s
sys 0m8.167s

圧縮前が2,271,220,673バイト(2.2GB)で、圧縮後が215,331,701バイト(210MB)になった。
ただの文字データ2.2GBなら2分半で10分の1程度に圧縮可能という結論が出た。

以上。
作業時間の目安なりにしてください〜

2009年2月4日水曜日

過去のLT動画

・第11回 「Aから考えてみる...」

  • Aから始まるテーマだったので、無理矢理こじつけてアンペアにしてみました。
  • でも注意してないとおもわぬところで足をすくわれるのも事実。

・第10回 「パソコン1台で始める俺俺データセンター」

  • 仮想マシンと1台のPCでどこまで面白い環境が作れるのかということにチャレンジしてみた内容。

GenesisLightningTalksの動画がUPされました。

先日挙げたエントリの内容の動画です。

2009年1月30日金曜日

CentOS5.2と合うintelのマザーボード - 続報 -

昨日書き忘れました。
DQ35MPを使う場合はBIOSのバージョンに注意してください。

「BIOS Version 0704」未満のバージョンの場合、QuadCoreのCPUが利用できない問題があるようです。
intelのBIOSアップデートリリースノートにそんな内容が書いてありました。

というわけで、使うかたは最新のBIOSにアップすることを推奨します。

と、ここまで書いて、前回お薦めした根拠が覆されたのであった。。。

2009年1月29日木曜日

CentOS5.2と合うintelのマザーボード

先日intel DG45IDでNICが認識しない問題などと題してエントリを上げたのだけども、
そのあとで(特に何もしなくても)NICが動くintelのマザーボードみっけました。

Intel Desktop Board DQ35MPです。

こいつはちゃんとNICを認識するし、何よりインターフェースがシンプルでよけいなものがついてないのでいい感じです。
「CentOS5.2で自宅サーバしてみたい!」とか、あるいは「業務用に自作が必要なんです、MicroATXで」などというはてなとかpixivのようなインフラをやっている方には参考にしていただければなどと。

NICの認識はある程度自力で頑張ればどうにかなるけど、はじめから悩まないですむやつを買った方が時間を有意義に使えると思います。

では。

GenesisLightningTalksの本質はその自由性にある

タイトルはホッテントry

というわけで今月もGenesisLightningTalksに参加してきました。
このイベントは前回まで違う名前だったのだけども、3度目の参加。
資料はGenesisLightningTalksのWikiに過去のも合わせてはっつけてあります。

1回目は自宅(他宅だけど)サーバと仮想マシンで ちょっとした構成を組んでみた話。
2回目は自宅サーバを運用するときに注意すべき電源の話。
そして今回は会社を変えた話。

他の参加者様の話題も結構多種多様で、
  • すぎゃーん : 臨機応変ヒッチハイク一人旅
  • なるひこ : 変化球的技術者向けカヤックのススメ
  • あきみち : 変化するインターネットトラフィック
  • yuske : 変化について
  • hyoshiok : 変えること、変えないこと。(変わること、変わらないこと)
  • やまとも : 変速機のはなし
と、テーマが「変」が入ったタイトルって縛りがあるものの、基本的にそれを何に結びつけるかは自由。
テーマを共有しつつその先は自由、というのがGenesisLightningTalksのいいところであり、「面白い」と感じられる部分なのだと、そう考えるのである。

が、今回おいらが最も印象に残ったのは、id:hyoshiokさんの「プリフェッチ」発言でした。
先読みは大事ですね。

おわり。

今日から使える実践的Tokyo Tyrantのrpm講座

タイトルはまたもホッテントリメーカーから。

先日Tokyo Tyrantについていろいろ誤解して書いてしまったので罪滅ぼし的に、
「CentOS5.2でTokyo Tyrantのrpmを作ってインストールして運用できる状態にするまで」を書いてみる。
「rpmがないと使えない〜」というrpm厨の方もこれで安心。

今回は1サーバ1インスタンスでセットアップする想定です。
レプリケーションなどはまた別の機会に。

一応自分のとこでは動きましたが、エントリの内容は無保証です。自己責任でお願いします。

手順は大まかに言うと↓のような感じ。
  1. Tokyo CabinetとTokyo Tyrantのソースアーカイブを手に入れる
  2. rpmを作る
  3. Tokyo Tyrantが依存している別のパッケージをインストールする
  4. Tokyo Tyrantをインストールする
  5. Tokyo Tyrantをchkconfigに登録する
  6. logrotateに登録してログの肥大化を防ぐ

1.Tokyo CabinetとTokyo Tyrantのソースアーカイブを手に入れる

何はともあれTokyo Cabinetの公式サイトから
  • tokyocabinet-{version}.tar.gz
  • tokyotyrant-{version}.tar.gz
を手に入れてきます。
今回のエントリでは、Tokyo Cabinetは1.4.3、Tokyo Tyrantは1.1.11の両方とも最新版を利用しました。

2. rpmを作る

rpmを作るにはいくつか方法がありますが、今回はrpmbuildコマンドを使いますので事前にインストールしておいてください。
rpmを作るときは、できれば一般ユーザのhomeに領域を作った方がよいです。
なので、まずは一般ユーザで下記のようにrpmを作るための環境を準備します。


$ mkdir -p ~/rpm/{BUILD,SOURCES,SPECS,RPMS,SRPMS}
$ vi ~/.rpmmacros

%_topdir /home/hoge/rpm

ここまでできたら、次はrpmを作成するのに必要なSPECファイルを作ります。
おいらが作るときに使ったSPECファイルを公開しておきます、適当に参考にしてください。
まずはTokyo CabinetのSPECを書きます。


$ vi ~/rpm/SPECS/tokyocabinet.spec

Summary: A modern implementation of a DBM
Name: tokyocabinet
Version: 1.4.3
Release: 1
License: LGPLv2+
Group: Development/Libraries
URL: http://tokyocabinet.sourceforge.net/
Source: http://tokyocabinet.sourceforge.net/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: pkgconfig zlib-devel autoconf
BuildRequires: lua-devel

%description
Tokyo Cabinet is a library of routines for managing a database. It is the
successor of QDBM. Tokyo Cabinet runs very fast. For example, the time required
to store 1 million records is 1.5 seconds for a hash database and 2.2 seconds
for a B+ tree database. Moreover, the database size is very small and can be up
to 8EB. Furthermore, the scalability of Tokyo Cabinet is great.

%package devel
Summary: Headers for developing programs that will use %{name}
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: pkgconfig

%description devel
This package contains the libraries and header files needed for
developing with %{name}.

%prep
%setup -q

%build
autoconf
%configure CFLAGS="$CFLAGS" --enable-lua
make %{?_smp_mflags}

%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install

rm -rf %{buildroot}%{_datadir}/%{name}
rm -rf %{buildroot}%{_libdir}/lib%{name}.a

#%check
#make check

%clean
rm -rf %{buildroot}

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

%files
%defattr(-, root, root, -)
%doc ChangeLog COPYING README
%{_bindir}/tc*
%{_libdir}/libtokyocabinet.so.*
%{_mandir}/man1/tc*.gz
%{_libexecdir}/tcawmgr.cgi

%files devel
%defattr(-, root, root, -)
%{_includedir}/tc*.h
%{_libdir}/*.so
%{_libdir}/pkgconfig/%{name}.pc
%{_mandir}/man3/t*.gz
%doc doc/*

%changelog
* Thu Jan 29 2009 myfinder
- New Build

次にTokyo TyrantのSPECを作成します。


$ vi ~/rpm/SPECS/tokyotyrant.spec

Summary: Network Interface for TokyoCabinet
Name: tokyotyrant
Version: 1.1.11
Release: 1
License: LGPLv2+
Group: Development/Libraries
URL: http://tokyocabinet.sourceforge.net/tyrantdoc/
Source: http://tokyocabinet.sourceforge.net/tyrantpkg/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: pkgconfig zlib-devel autoconf
BuildRequires: lua-devel

%description
Tokyo Tyrant is a package of network interface to the DBM called Tokyo Cabinet.
Though the DBM has high performance, you might bother in case that multiple processes share the same database, or remote processes access the database.
Thus, Tokyo Tyrant is provided for concurrent and remote connections to Tokyo Cabinet.
It is composed of the server process managing a database and its access library for client applications.
The server can embed Lua, a lightweight script language so that you can define arbitrary operations of the database.

%package devel
Summary: Headers for developing programs that will use %{name}
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: pkgconfig

%description devel
This package contains the libraries and header files needed for
developing with %{name}.

%prep
%setup -q

%build
autoconf
%configure CFLAGS="$CFLAGS" --enable-lua
make %{?_smp_mflags}

%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install

rm -rf %{buildroot}%{_datadir}/%{name}
rm -rf %{buildroot}%{_libdir}/lib%{name}.a

#%check
#make check

%clean
rm -rf %{buildroot}

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

%files
%defattr(-, root, root, -)
%doc ChangeLog COPYING README
%{_bindir}/t*
%{_sbindir}/t*
%{_libdir}/libtokyotyrant.so.*
%{_mandir}/man1/t*.gz
%{_mandir}/man8/t*.gz

%files devel
%defattr(-, root, root, -)
%{_includedir}/*.h
%{_libdir}/*.so
%{_libdir}/pkgconfig/%{name}.pc
%{_mandir}/man3/t*.gz
%doc doc/*

%changelog
* Thu Jan 29 2009 myfinder
- New Build

ここまでできたら、入手したソースアーカイブを、~/rpm/SOURCES/に放り込みます。
放り込んだらrpmbuildコマンドでrpmを作りましょう。


$ rpmbuild -ba ~/rpm/SPECS/tokyocabinet.spec
$ rpmbuild -ba ~/rpm/SPECS/tokyotyrant.spec

RPMファイルは、" ~/rpm/RPMS/{architecture}/"以下に作成されます。

3. Tokyo Cabinet&Tokyo Tyrantが依存しているパッケージをインストールする

luaサポートをonにしたいので、lua-develをyumかなにかで導入しておきましょう。


$ sudo yum install lua-devel


4. Tokyo Tyrantをインストールする

~/rpm/RPMS/{architecture}/以下に出来上がっているrpmをインストールします。


$ sudo rpm -ivh ~/rpm/RPMS/{architecture}/tokyo*

インストールがウマいこといけば↓のファイルがインストールされます。
(manの表示はカットしました)


$ rpm -ql tokyotyrant
/usr/bin/tcrmgr
/usr/bin/tcrmttest
/usr/bin/tcrtest
/usr/bin/ttserver
/usr/bin/ttulmgr
/usr/bin/ttultest
/usr/lib/libtokyotyrant.so.2
/usr/lib/libtokyotyrant.so.2.3.0
/usr/sbin/ttservctl
/usr/share/doc/tokyotyrant-1.1.11
/usr/share/doc/tokyotyrant-1.1.11/COPYING
/usr/share/doc/tokyotyrant-1.1.11/ChangeLog
/usr/share/doc/tokyotyrant-1.1.11/README
$ rpm -ql tokyocabinet
/usr/bin/tcamgr
/usr/bin/tcatest
/usr/bin/tcbmgr
/usr/bin/tcbmttest
/usr/bin/tcbtest
/usr/bin/tcfmgr
/usr/bin/tcfmttest
/usr/bin/tcftest
/usr/bin/tchmgr
/usr/bin/tchmttest
/usr/bin/tchtest
/usr/bin/tctmgr
/usr/bin/tctmttest
/usr/bin/tcttest
/usr/bin/tcucodec
/usr/bin/tcumttest
/usr/bin/tcutest
/usr/lib/libtokyocabinet.so.7
/usr/lib/libtokyocabinet.so.7.6.0
/usr/libexec/tcawmgr.cgi
/usr/share/doc/tokyocabinet-1.4.3
/usr/share/doc/tokyocabinet-1.4.3/COPYING
/usr/share/doc/tokyocabinet-1.4.3/ChangeLog
/usr/share/doc/tokyocabinet-1.4.3/README

ここまでくればほぼ大丈夫ですが、動作確認はしときましょう。


# ttserver
2009-01-27T14:48:56+09:00 --------- logging started [23008] --------
2009-01-27T14:48:56+09:00 server configuration: host=(any) port=1978
2009-01-27T14:48:56+09:00 database configuration: name=*
2009-01-27T14:48:56+09:00 service started: 23008
2009-01-27T14:48:56+09:00 timer thread started
2009-01-27T14:48:56+09:00 worker thread 1 started
2009-01-27T14:48:56+09:00 worker thread 2 started
2009-01-27T14:48:56+09:00 worker thread 3 started
2009-01-27T14:48:56+09:00 worker thread 4 started
2009-01-27T14:48:56+09:00 worker thread 5 started
2009-01-27T14:48:56+09:00 worker thread 6 started
2009-01-27T14:48:56+09:00 worker thread 7 started
2009-01-27T14:48:56+09:00 worker thread 8 started
2009-01-27T14:48:56+09:00 listening started

こうなればOK、とりあえず「Ctrl+C」で切ってしまいましょう。

5. Tokyo Tyrantをchkconfigに登録する

Tokyo Tyrantをchkconfigに登録するのは簡単で、/usr/sbin/ttservctlに↓の数行追加するだけ。


# vi /usr/sbin/ttservctl

# chkconfig: 345 65 55
# description: Startup script for the server of Tokyo Tyrant
# processname: tokyotyrant

追記できたら/etc/init.dにリンクを作ってchkconfigに登録します。


# ln -s /usr/sbin/ttservctl /etc/init.d/
# chkconfig --add ttservctl
# chkconfig --list ttservctl
ttservctl 0:off 1:off 2:off 3:on 4:on 5:on 6:off

起動して確認しましょう


# /etc/init.d/ttservctl start
Starting the server of Tokyo Tyrant
Done

さらにtelnetでつないで確認します


# telnet localhost 1978
Trying 127.0.0.1...
Connected to hostname.localdomain (127.0.0.1).
Escape character is '^]'.
stats
STAT pid 23121
STAT uptime 18
STAT time 1233035968
STAT version 1.1.11
STAT rusage_user 0.000000
STAT rusage_system 0.018997
STAT curr_items 0
STAT bytes 4198720
END
quit

ここまで確認できれば、もうインストールは完了です。
が、運用を楽にするためにもうひと手間掛けましょう。

6. logrotateに登録する

/var/ttserver/logにTokyo Tyrantのログが書き出されるのですが、これを放置しておくと勝手に肥大化していって大変です。
こういうのはログをローテーションする仕組みに任せてしまうのが楽です。


# vi /etc/logrotate.d/tokyotyrant

/var/ttserver/log {
compress
missingok
notifempty
sharedscripts
postrotate
/sbin/service ttservctl hup > /dev/null 2>/dev/null || true
endscript
}


Tokyo Tyrantの起動停止スクリプトがHUPをフォローしてくれているので、これだけでOKというのが何とも楽でいい感じです。

ここまでやっておけば、永続化機能のついた、OSごと再起動が掛かっても勝手に復活するmemcachedサーバ的な使い方が出来るようになります。

今日はこんなもんで。

2009年1月28日水曜日

人生に役立つかもしれないTokyo Tyrantについての知識 続報

昨夜上げたエントリで、TTはFlagを無視する?という疑問とその状況について書いたのですが。
今朝改めてTTのドキュメントをさらったところ、下記のように書いてありました。

However, "flags", "exptime", and "cas unique" parameters are ignored.

つまり、flagsは無視されるようです。
ということなので、memcachedプロトコルを実直に実装したクライアントライブラリだと、昨日エントリしたような状況が発生する可能性があるという話でした。

ドキュメント仕様は真っ先に取りまとめて比較するようにしないと、思わぬところで足元をすくわれるので注意したいところです。

昨日のおいら、おつ。
TTの開発者様、失礼いたしました。

おわり。

2009年1月27日火曜日

人生に役立つかもしれないTokyo Tyrantについての知識

タイトルはホッテントリメーカーから頂戴しました。

お仕事でmemcachedとかその周辺プロダクトを利用することとなり、memcached、Tokyo Tyrant、Flareのパフォーマンスを測ってみたときに発覚したことを書いておきます。
(前提条件:memcached client for Javaからmemcachedとかその互換プロダクトを利用する場合)

まずはパフォーマンスの手っ取り早い指標として処理速度があげられるので、上記3プロダクトをセットアップして、下記のようなテストプログラムをそそくさとこさえました。


public static void main(String[] args) {

// memcacheのインスタンス取得
SockIOPool pool = SockIOPool.getInstance();
pool.setServers(new String[] {"hostname:port"});
pool.initialize();
MemCachedClient memcache = new MemCachedClient();

// 計測用
long start = 0;
long finish = 0;

// setのパフォーマンステスト
System.out.println("setのテスト開始...");
start = System.currentTimeMillis();
// setのテスト
for (Iterator<Map.Entry<String, String>> it = TEST_DATA_HASH.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, String> entry = it.next();
memcache.set(entry.getKey(), entry.getValue());
}
finish = System.currentTimeMillis();
System.out.println(TEST_DATA_HASH.size() + "件のsetにかかった時間 : " + (finish - start) + "ms");

// getのパフォーマンステスト
System.out.println("getのテスト開始...");
start = System.currentTimeMillis();
int count = 0;
for (Iterator<Map.Entry<String, String>> it = TEST_DATA_HASH.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, String> entry = it.next();
String value = "";
value = (String)memcache.get(entry.getKey());
// get1万件ごとにprintして確認
if ((count % 10000) == 0) {
System.out.println(value);
}
++count;
}
finish = System.currentTimeMillis();
System.out.println(TEST_DATA_HASH.size() + "件のgetにかかった時間 : " + (finish - start) + "ms");
}

データはおよそ10万件の固定長(32byte)のキーと、100-300byte程度の英数字記号のみの文字列。
テストに使ったマシンはP4 2.8GHzにRAM 3GBです。

プロダクトsetにかかった時間(ms)getにかかった時間(ms)
memcached3412658182
Tokyo Tyrant3617063023
Flare4267462938

値自体はおおよそ想定された内容だった。(TTのsetがこれほど速いとは思ってなかったけど)
のだが、Tokyo Tyrantのgetパフォーマンスを計測している時に異変が起こりました。
さっきsetした文字列データをgetするのだから、文字列がprintされるはずなのに、「null」と出力されてしまっているのです。
(つまりnullが返ってきている)

これはどうしたものかと思い、直接telnetしてmemcacheと対話してみました。

・memcached
user@host:$ telnet host 11211
Trying host...
Connected to host.
Escape character is '^]'.
get keykeykeykeykeykeykeykeykeykeyke
VALUE keykeykeykeykeykeykeykeykeykeyke 32 64
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
END
quit
Connection closed by foreign host.

・Tokyo Tyrant
user@host:$ telnet host 1978
Trying host...
Connected to host.
Escape character is '^]'.
get keykeykeykeykeykeykeykeykeykeyke
VALUE keykeykeykeykeykeykeykeykeykeyke 0 64
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
END
quit
Connection closed by foreign host.

・Flare
user@host:$ telnet host 12121
Trying host...
Connected to host.
Escape character is '^]'.
get keykeykeykeykeykeykeykeykeykeyke
VALUE keykeykeykeykeykeykeykeykeykeyke 32 64
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
END
Connection closed by foreign host.

結果、Tokyo Tyrantだけflagが0で返ってくる。
telnetで確認してみるとデータは返ってくるのに、nullになってしまうのはなぜかとmemcached client for javaのflag処理がどうなっているかを追っていき、そのflagの処理を見てみると

public static Object decode( byte[] b, int flag ) throws Exception {
if ( b.length < 1 )
return null;
if ( ( flag & MemCachedClient.MARKER_BYTE ) == MemCachedClient.MARKER_BYTE )
return decodeByte( b );
if ( ( flag & MemCachedClient.MARKER_BOOLEAN ) == MemCachedClient.MARKER_BOOLEAN )
return decodeBoolean( b );
if ( ( flag & MemCachedClient.MARKER_INTEGER ) == MemCachedClient.MARKER_INTEGER )
return decodeInteger( b );
if ( ( flag & MemCachedClient.MARKER_LONG ) == MemCachedClient.MARKER_LONG )
return decodeLong( b );
if ( ( flag & MemCachedClient.MARKER_CHARACTER ) == MemCachedClient.MARKER_CHARACTER )
return decodeCharacter( b );
if ( ( flag & MemCachedClient.MARKER_STRING ) == MemCachedClient.MARKER_STRING )
return decodeString( b );
if ( ( flag & MemCachedClient.MARKER_STRINGBUFFER ) == MemCachedClient.MARKER_STRINGBUFFER )
return decodeStringBuffer( b );
if ( ( flag & MemCachedClient.MARKER_FLOAT ) == MemCachedClient.MARKER_FLOAT )
return decodeFloat( b );
if ( ( flag & MemCachedClient.MARKER_SHORT ) == MemCachedClient.MARKER_SHORT )
return decodeShort( b );
if ( ( flag & MemCachedClient.MARKER_DOUBLE ) == MemCachedClient.MARKER_DOUBLE )
return decodeDouble( b );
if ( ( flag & MemCachedClient.MARKER_DATE ) == MemCachedClient.MARKER_DATE )
return decodeDate( b );
if ( ( flag & MemCachedClient.MARKER_STRINGBUILDER ) == MemCachedClient.MARKER_STRINGBUILDER )
return decodeStringBuilder( b );
if ( ( flag & MemCachedClient.MARKER_BYTEARR ) == MemCachedClient.MARKER_BYTEARR )
return decodeByteArr( b );
return null;
}

となっていました。
この処理では、受け取ったデータをどのクラスにキャストするかをflagsで判断しているようなのですが、flagsに0が返ってきてしまうTokyo Tyrantではどのflagにも該当しません。
よってreturn nullされて、データはgetできているにも関わらずnullとなってしまうという問題が起こっていたことが見て取れます。

これって大丈夫なのかな〜。
全部文字列(Stringなど)として受け取るという前提でTTは実装されているのかも。
(myfinderの認識が間違っていたら申し訳ないのですが)

型に緩いLLならそもそもキャストする処理が不要なのでそもそもクライアントライブラリがflagを見ていないのかもしれない。
(mixiはPerlから利用しているみたいだし)

というかクライアントライブラリも、あり得ないflagが返ってきたなら例外をスローしたほうがいいんじゃないかというツッコミを入れたいところ。

少なくともmemcached client for JavaからTokyo Tyrantを利用するときは、そういうことがあるということは覚えておかないと、setできるけどgetするとnullが返ってくるという、ブラックホール状態になってしまうので注意です。

結論としては、Tokyo Tyrantをmemcached client for Javaから使う場合、改修をする必要があり、それがいやならmemcachedクライアントを自作するなどの対策が必要ですよというオチでした。
パフォーマンス計測結果とその計測プログラムは参考程度にお使いください。

では。

2009年1月26日月曜日

プログラむ

ちょっと行列をやる必要があったので、簡単に書いたもの。


public class Matrix {
private String[][] matrix;
private int row;
private int column;

public Matrix(String[][] matrix) {
// 行列本体
this.matrix = matrix;
// 行数取得
this.row = this.matrix.length;
if (row == 0) {
this.column = 0;
}
else {
this.column = this.matrix[0].length;
}
}

public String[][] transport (){
String[][] transportedArray = new String[column][row];
for (int i = 0; i < column; ++i) {
for (int j = 0; j < row; ++j) {
transportedArray[i][j] = matrix[j][i];
}
}
return transportedArray;
}
}


だんだんメソッドとかフィールドが増えていく予感。

2009年1月21日水曜日

プログラミングの基礎体力その1「転置配列」

自分の能力レーダーチャートを作ってみるとすると、圧倒的に「プログラむ」力が不足しているのは前々から思っていて、どうにかしないといかんと考えていた。
なので、しばらくの間このシリーズをやってみるです。

今回実装したのは転置配列的な処理。
入力CSVを反転させるものです。

以下コード


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CSVReverse {

private static final String DELIMITER = ",";

/**
* main
* @param args
* @throws FileNotFoundException
* @throws IOException
*/
public static void main(String[] args) throws FileNotFoundException, IOException, IOException {

FileReader fileReader = new FileReader("sampleData/examination.csv");
BufferedReader bufferedReader = new BufferedReader(fileReader);
List splittedList = new ArrayList();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
splittedList.add(line.split(DELIMITER));

}

String[][] splittedArray = splittedList.toArray(new String[splittedList.size()][]);
int row = splittedArray.length;
int column = 0;
if (row != 0) {
column = splittedArray[0].length;
}

String[][] transportedArray = new String[column][row];
// 行と列を反転させる
for (int i = 0; i < column; ++i) {
for (int j = 0; j < row; ++j) {
/**
* こうすれば
* 元行列[0][0] 変換行列[0][0]
* 元行列[0][1] 変換行列[1][0]
* 元行列[0][2] 変換行列[2][0]
* 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
* という感じに置き換えができる
*/
transportedArray[i][j] = splittedArray[j][i];
}
}
StringBuilder transportedString = new StringBuilder();
for (String[] transportedLineArray : transportedArray) {
for (int i = 0; i < transportedLineArray.length; ++i) {
transportedString.append(transportedLineArray[i]);
if (i != transportedLineArray.length - 1) {
transportedString.append(DELIMITER);
}
}
transportedString.append(System.getProperty("line.separator"));
}

FileWriter fileWriter = new FileWriter("resultData/transported.csv");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(transportedString.toString());
bufferedWriter.close();
}
}


たったこれだけなのに時間掛かり過ぎ。
もっと書かないといかんです。

2009年1月11日日曜日

NetBeans6.5ビルトインのTomcat6のコンソール出力が文字化けする件

先日NetBeansのJavaコンソールが文字化けする件を書いた続報。
Servletアプリケーションを作り始めて、標準出力が化けることに気づいたので備忘録的に書いておきます。

NetBeans6.5からTomcatを起動する場合、Javaの起動引数設定を下の画像のようにしておくと、化けません。