libhdfsを使う(その0)

コンパイルから実行までに1時間くらいかかったわけですが、95%はCLASSPATHの効率的な指定方法を調査していた時間ですw 以下、pathは適当に自分の環境に合うように置き換えて読んでください。

libhdfsを使ったソースファイルは以下のようにコンパイルします。Linuxに詳しくないので、詳しい人はもっとちゃんとした方法を教えてください。まず、LD_LIBRARY_PATHをexportしておきます。

export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-sun/jre/lib/amd64/server/:$(HADOOP_HOME)/build/libhdfs/

次にlibhdfsをリンクしつつコンパイルします。

$ g++ -L$(HADOOP_HOME)/build/libhdfs -lhdfs その他のオプションなど

makeを使えば軽減されますがめんどくさす。

コンパイルしたものは以下のように実行します。LD_LIBRARY_PATHは前述のものをあらかじめexportしておくか、以下のように指定しつつ実行します。

$ LD_LIBRARY_PATH=/usr/lib/jvm/java-6-sun/jre/lib/amd64/server/:$(HADOOP_HOME)/build/libhdfs/ ./a.out

これで実行されれば良いのですが、libhdfsのためにhadoopの各種.jarを指定したCLASSPATHを与えなければ動きません(http://hadoop.apache.org/core/docs/r0.20.0/libhdfs.html:ここを参照)。そこでCLASSPATHを設定しなければならないわけですが…。

CLASSPATHに含めるものは良く分からなかったので、とりあえず$(HADOOP_HOME)と$(HADOOP_HOME)/libに含まれているjarファイルをすべてCLASSPATHに含めることにしました。lsしてみると分かりますが結構な数ですね非常に面倒くさいです。javaコマンドで起動する場合はワイルドカード指定が可能なようですが、環境変数として指定する場合はワイルドカードは使えないようです。Javaに詳しい方、なんか良い方法があったら教えて欲しいです(「eclipse使え」以外で)。

まあそんなわけで以下のようなものをexportしたら無事に動きました。

export CLASSPATH=$(HADOOP_HOME)/hadoop-0.18.3-core.jar:$(HADOOP_HOME)/hadoop-0.\
18.3-tools.jar:$(HADOOP_HOME)/lib/commons-cli-2.0-SNAPSHOT.jar:$(HADOOP_HOME)/l\
ib/commons-codec-1.3.jar:$(HADOOP_HOME)/lib/commons-httpclient-3.0.1.jar:$(HADO\
OP_HOME)/lib/commons-logging-1.0.4.jar:$(HADOOP_HOME)/lib/commons-logging-api-1\
.0.4.jar:$(HADOOP_HOME)/lib/commons-net-1.4.1.jar:$(HADOOP_HOME)/lib/jets3t-0.6\
.0.jar:$(HADOOP_HOME)/lib/jetty-5.1.4.jar:$(HADOOP_HOME)/lib/junit-3.8.1.jar:$(\
HADOOP_HOME)/lib/kfs-0.1.3.jar:$(HADOOP_HOME)/lib/log4j-1.2.15.jar:$(HADOOP_HOM\
E)/lib/oro-2.0.8.jar:$(HADOOP_HOME)/lib/servlet-api.jar:$(HADOOP_HOME)/lib/slf4\
j-api-1.4.3.jar:$(HADOOP_HOME)/lib/slf4j-log4j12-1.4.3.jar:$(HADOOP_HOME)/lib/x\
mlenc-0.52.jar

/(^o^)\

libhdfsのビルド仕方@64bit環境(hadoo-0.18.3)

libhdfsはC言語からHDFSへアクセスするためのライブラリです。が、ちょっとコンパイルでハマったのでメモしておきます。32bit環境だと問題なくビルドできるかも知れませんが、実験はしていません。また、これは0.18.3(現時点でのstable release)での話で、最新のバージョンでは直っていそうな雰囲気です(http://issues.apache.org/jira/browse/HADOOP-3344)。

libhdfsをビルドするための準備として環境変数JAVA_HOMEをexportしておく必要があります。これは$(HADOOP_HOME)/conf/hadoop-env.shに書かれているJAVA_HOMEと同一のもので大丈夫です。次にHADOOP_HOMEディレクトリで以下のコマンドを実行します。

$ ant compile-libhdfs -Dlibhdfs=1

本当はこれでビルドできるらしいのですが、以下のようなエラーがでました。

compile-libhdfs:
    [mkdir] Created dir: /home/nobu/hadoop-0.18.3/build/libhdfs
     [exec] gcc -g -Wall -O2 -fPIC -m32 -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -c hdfs.c -o /home/nobu/hadoop-0.18.3/build/libhdfs/hdfs.o
     [exec] In file included from /usr/include/features.h:354,
     [exec]                  from /usr/include/sys/types.h:27,
     [exec]                  from hdfs.h:22,
     [exec]                  from hdfs.c:19:
     [exec] /usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory
     [exec] make: *** [/home/nobu/hadoop-0.18.3/build/libhdfs/hdfs.o] Error 1

libhdfsはそのままだと-m32付きでビルドされてしまいます。なので、$(HADOOP_HOME)/src/c++/libhdfs/Makefile内の-m32を手動で-m64に置き換えます。そして、再度上記のantをHADOOP_HOMEにて実行します。警告が何個か出ますが一応ビルドに成功し、$(HADOOP_HOME)/build/libhdfsに.soなどが出力されます。

自分のアプリケーションでlibhdfsをリンクしたい場合は、LD_LIBRARY_PATHなどで

  • $(JAVA_HOME)/jre/lib/$(OS_ARCH)/server (OS_ARCHはamd64など)
  • $(HADOOP_HOME)/build/libhdfs

にパスを通しておき、"-lhdfs"をつけてコンパイルすればOKです。上のパスはlibjvm.so用です。

検索に苦労したので一応エラーメッセージなどをそのまま載せています。関係のない話でたどり着いてしまった人はごめんなしあ。


そしてantの使い方が良くわからんよ!!

$ ant compile-libhdfs -Dlibhdfs=1

なんでこのように二重にフラグを立てているような感じになっているのでしょうか(compile-libhdfsだけで良さそうな気がしてしまう)。教えて偉い人。

お手軽(?)かつ合法的にプログラムからglogの挙動を制御する

google-glogは便利なロギングライブラリです。便利なんですが、困った事に、ドキュメントを見る限りだとコマンドライン引数からしか挙動を制御する事ができません。例えばログの出力先を指定したい場合は、-log_dirというオプションを渡して起動する必要があります。ソースを覗くと怪しい関数は沢山あるのですが、ドキュメント化されていないので、いつ使えなくなるのか良く分からない状態です。なので、個人で適当に使う分には良いですが、突然コンパイルできなくなると困る場合は怖くて使えません。

そこで、最近よくやるのが、argcとargvをプログラムで加工し、gflagsとglogの初期化関数に渡すという行為です。例えば、デフォルトで/tmpにログを吐かれると、だんだん/tmpが酷い事になっていくので、デフォルトではログをstderrに吐くようにしたいとします。このためにはまず、argvに"log_dir"が含まれるかどうかをチェックします。argvに"log_dir"が含まれない場合は、argvをstrdupしてさらに"-logtostderr"と"-stderrthreshold", "0"(任意のレベル)を加えた新しいargvを作ります。それに合わせてargcの数も調整します。そして、この加工済みのargcとargvを使ってgflagsとglogを初期化します。

一応この方法は原理的に末永く使うことができるはずです。なんか悲しいですね。合法と言い切れるもっと良い方法があったら教えて欲しいです。

Transactional Information Systems 3章 3.1〜3.6まで

先週は全然読めなかった。。3章が長めで、3.7はちょっと重そうなので、前半をまとめてみる。

3章はPage model(read/write model)のトランザクションに対して、トランザクションを並列実行したときの「正しさ」を定義することを目標にしている。トランザクションが失敗するケースを考え始めると大変なので、まずは失敗がないことを前提に話を進めていく。失敗するケースはPart III、11章から扱い始める。

3.2では、lost-update,inconsistent-read,dirty-readという良くある問題を軽く説明。

3.3ではhistoryとscheduleを定義している。"A schedule is a prefix of a history"という記述があって良く意味がわからなかった。でも、とりあえず読み進めていったら後で分かった。厳密な定義を書き始めるときりがないので雰囲気で書いてみる。scheduleもhistoryも結局は複数のトランザクションが混ざったようなもの。ただし、historyには、abortかcommitで完了したトランザクションしか含まれていない。なのでhistoryはcomplete scheduleとも呼ばれるらしい。対して、scheduleは完了していないトランザクションも含む。scheduleの末尾に色々追加して全部のトランザクションが完了してしまえばhistoryになる。なので、prefixという事らしい。このあとはorderに関しての話題などを取り扱った。どんどん表現と説明が簡潔なのに分かりやすくなっていく様は格好良かった。

3.4は「正しさを定義するためにはこんな事が必要」という話と、今後の流れの説明。とりあえず、scheduleの等価性を定義する。その後、serial historyとの等価性を利用して、serializabilityというものを定義。

3.5は等価性を定義するために便利なHerbrand semanticsというものを定義。今まで、「w_i(x)の結果は、それまでトランザクションiが読み込んだすべての値に依存する」みたいに言葉で表現していたものを、全部数式っぽいもので表現できるようになった。

3.6はfinal state equivalenceというものを定義。2個のhistory(schedule)があったときに、データの流れ方が同じかどうかを判定しているのだと思う。それを厳密に説明するために、reads-from relationやaliveなどの関係・概念を定義した。その後、それを使ってfinal state serializabilityというものを定義。final state serializableなhistoryFSRというクラスに属する。

FSRは定義できたけど、あるhistoryFSRに含まれるかどうかはどうやったらチェックできるのか。3.7からはその話。定理ばっかりなので、ちょっと休憩してから読む。

iPod nano + Nikeplusの罠

Nikeの例の奴を使って初めてiTunesに接続したときにnikeplusのアカウントを登録するようなダイアログがでる「はず」だったらしいんだけど、出なかった。iTunesでは、iPod nanoの(nikeplus使用後の?)初回接続時にしかnikeplusのアカウント情報を登録できない。したがって、そのタイミングで登録ダイアログが出ないと、二度と登録できなくなる。iTunesにはなぜかnikeplusのアカウント情報を変更する手段がない。恐らくiTunesか最悪OSを再インストールするまでnikeplusにデータを送信できないことになる。残念。

レジストリにもそれっぽいキーがなかったのでどうしようもないなぁ。iTunesアンインストールしてダメだったらだるいので、もういいや。簡単に解決できる方法を知っている人がいたら是非教えて欲しいです…。金払ったのにこれはないよなぁ。iTunesからnikeplusのアカウントを再設定できるようにする変更なんて、まともな設計をしてたら10分でできると思うんだけど。ちょっとあり得ない。

g++ 4.2.3のバグ?std::mapやstd::pairをメンバ関数のデフォルト引数に書くと怒られる件

http://groups.google.co.jp/group/gnu.g++.bug/browse_thread/thread/09f52263bb8562a6
これと同じ。

#include <iostream>
#include <map>
using namespace std;

void f(const map<int, int>& m = map<int, int>())
{
}

class A {
public:
  A(const map<int, int>& m = map<int, int>()) {}
  void f(const map<int, int>& m = map<int, int>()) {}
};

int main()
{
}
test.cpp:11: error: expected ‘,’ or ‘...’ before ‘>’ token
test.cpp:12: error: expected ‘,’ or ‘...’ before ‘>’ token
test.cpp:11: error: wrong number of template arguments (1, should be 4)
/usr/include/c++/4.2/bits/stl_map.h:93: error: provided for ‘template<class _Key, class _Tp, class _Compare, class _Alloc> class std::map’
test.cpp:11: error: default argument missing for parameter 2 of ‘A::A(const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >&, int)’
test.cpp:12: error: wrong number of template arguments (1, should be 4)
/usr/include/c++/4.2/bits/stl_map.h:93: error: provided for ‘template<class _Key, class _Tp, class _Compare, class _Alloc> class std::map’
test.cpp:12: error: default argument missing for parameter 2 of ‘void A::f(const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >&, int)’

メンバ関数のデフォルト引数に2個以上のtemplate引数を取るものを書くと、","以降を別の引数だと解釈してしまっているのかな?マクロのように。よくわからん。仮にそうだったとしたら、

A(const map<int, int>& m = (map<int, int>())) {}

このようにデフォルト引数をカッコで囲んであげればOKだと思ったので、試してみたところコンパイルできた。うーむ。これはバグだよなぁさすがに・・・。Macのg++や、他のバージョンでは大丈夫だったりもする模様。謎す。

Transactional Information Systems 2章

現在読んでるところ。6月末に読み終わるのを目標に頑張ってます。2章はこれからの議論の基本となる2つのモデル、page modelとobject modelの説明。

Page modelではそれ以上分割できないreadとwriteのシーケンスを考える。この時、トランザクションはそれ以上分割できないread/writeの集合とread,readの順序を考慮しないpartial orderで定義される。これはreadとwrite、writeとwriteの順序関係さえ定義できれば結果に曖昧さが生じないから、partial orderで十分ということなんでしょうかね。

Object modelではもう少し複雑な操作が定義される。具体的には、トランザクションを木で表現する。トランザクション木は、何らかの処理を表すleafでないnodeと、read/writeの命令で構成される(page modelの)leaf nodeからなる。Object modelはpage modelを一般化したもので、複雑だけど色々表現できて便利らしい。

この2つをあっさり目に説明した後に、やっとこの本をどう進めていくのか書けるようになった、と言う事でようやくロードマップが登場。まず3〜5章はpage modelを使ってconcurrency controlを説明していくらしい。serializabilityというのが重要そう。あとscheduleとhistoryという概念が出てくる模様。6章からはobject modelを使って似たような話を繰り返し、11章からはrecovery。まだまだ先。

とりあえず、3〜5章で150ページくらいあるので、それ以上先の事は頭の隅に置いておこう…。先は長す。しかし、3章の話はThe Art of Multiprocessor Programmingの前半にも出てきた話。読んだのは丁度去年の今頃かな?あのときは全く分からなかった…。Transactional Information Systemsではページ数も多いので、頑張って理解する。5章まで読み終わったらTAMPの方も読み直してみよう。

しかし用語に対応する日本語が分からなすぎる。コンカレンシーコントロール(笑)とかヒストリー(笑)とか書いたら某○瀬翻訳とレベルが変わらないので嫌だ。トランザクション処理も平行して読んで、用語の言語間マップを作らないと、まともな文章も書けない。。