◆F99a.q8oVE::Blog
FreeBSD 7.2でHadoopのサンプルを動かしてみた
◆F99a.q8oVE: 2009/09/20 00:45:33

とりあえず、hadoop用のアカウントを作ってみた。

## __GooglePrettify__
% sudo adduser hadoop

このユーザー用に、パスワード無しのSSH鍵を作って、ログインできるようにしておく。

予めtarballを手動で/usr/ports/distfilesに入れておいて、

## __GooglePrettify__
% cd /usr/ports/java/diablo-jdk16
% sudo make config          # TZUPDATEは無効にしておく(手抜き)

で、JDKのインストール

## __GooglePrettify__
% sudo portinstall java/diablo-jdk16
% sudo portinstall shells/bash

JDKが入ったら、次はhadoopのインストール。http://hadoop.apache.org/common/releases.html#Downloadらへんからダウンロード。

## __GooglePrettify__
% tar zxvf hadoop-0.20.1.tar.gz
% cd hadoop-0.20.1/conf

hadoop-env.shのJAVA_HOMEを設定しておく。

## __GooglePrettify__
export JAVA_HOME=/usr/local/diablo-jdk1.6.0

docs/quickstart.htmlを見ながら

conf/core-site.xml

<!-- __GooglePrettify__ -->
<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>

conf/hdfs-site.xml

<!-- __GooglePrettify__ -->
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>

conf/mapred-site.xml

<!-- __GooglePrettify__ -->
<configuration>
  <property>
    <name>mapred.job.tracker</name>
    <value>localhost:9001</value>
  </property>
</configuration>

起動してみる。

## __GooglePrettify__
% cd ../bin
% ./hadoop namenode -format        # HDFSの初期化
% ./start-all.sh

エラーが出なければ成功。jpsで動作してるか確認できる。

## __GooglePrettify__
% mkdir ~/inputs
% cp CHANGES.txt ~/inputs            # 適当なファイルを入れて
% hadoop dfs -put ~/inputs inputs    # HDFSにコピー
% hadoop dfs -ls inputs              # コピーできたか確認

いよいよ、map, reduceを実行してみる。

## __GooglePrettify__
% hadoop jar hadoop-0.20.1-examples.jar wordcount inputs outputs

ほっとくと、なにやら出力が出て終了。

## __GooglePrettify__
% hadoop dfs -ls outputs
Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2009-09-19 22:58 /user/hadoop/outputs/_logs
-rw-r--r--   1 hadoop supergroup     126351 2009-09-19 22:59 /user/hadoop/outputs/part-r-00000
% hadoop dfs -cat outputs/part-r-00000      # に、単語をカウントした結果が出力される
C++ で学ぶ JavaScript の参照渡し (入門編)
◆F99a.q8oVE: 2009/05/10 18:38:56

発端は、2ch で見かけた、この発言 JavaScript.

まずは、こちらをご覧ください。
(注: 例示の JavaScript は SpiderMonkey や Rhino のインタプリターで実行するか、print を alert に読みかえてブラウザーで実行してください。)

// __GooglePrettify__
function func1(a) {
    a = {hoge: 2};
}
var b = {hoge: 1};
func1(b);
print(b.hoge); // => 1

実行すると、1 と表示されましたよね。「参照渡し(call by reference)なら、ここで 2 と表示されなければおかしい。これは、値渡し(call by value)じゃないの?」というのがリンク先で投げかけられていた疑問です。

ここで、次の関数を考えてみます。

// __GooglePrettify__
function func2(a) {
    a.hoge = 2;
}
var b = {hoge: 1};
func2(b);
print(b.hoge); // => 2

今度は 2 と表示されたと思います。この挙動を指して、参照渡しだと説明された場合は納得できると思います。

ここで、突然ですが、視点を変えて C++ で同様の関数をつくってみましょう。

// __GooglePrettify__
#include <iostream>

using namespace std;

class Hoge
{
public:
    int hoge;
    Hoge(int a) : hoge(a) {}
};

void func_v1(Hoge a)
{
    a = Hoge(2);
}

void func_v2(Hoge a)
{
    a.hoge = 2;
}

void func_r1(Hoge &a)
{
    a = Hoge(2);
}

void func_r2(Hoge &a)
{
    a.hoge = 2;
}

int main(void)
{
    {
        Hoge b(1);
        func_v1(b);
        cout << b.hoge << endl; // => 1
    }
    {
        Hoge b(1);
        func_v2(b);
        cout << b.hoge << endl; // => 1
        // まぁ、値渡しですから。
    }
    {
        Hoge b(1);
        func_r1(b);
        cout << b.hoge << endl; // => 2
        // おっ!?
    }
    {
        Hoge b(1);
        func_r2(b);
        cout << b.hoge << endl; // => 2
        // うんうん。これこそ、参照渡しです。
    }

    return 0;
}

同じような事をするのに、2 倍のパターンが出てきました。さてさて、JavaScript はどちらのパターンでしょう。 結論から言うと後者の _r 付きのパターンにあたります。これが参照渡し(call by refference)です。 _v 付きは、もちろん値渡し(call by value)です。

ここで、よ〜く見ると、func_r1 と func1 の挙動が異なりますね。 ここで更に C++ について学んで行きましょう。

// __GooglePrettify__
#include <iostream>

using namespace std;

class Hoge
{
public:
    int hoge;
    Hoge(int a) : hoge(a) {}
};

void func_p1(Hoge *a)
{
    a = new Hoge(2);
}

void func_p1_(Hoge *a)
{
    *a = Hoge(2);
}

void func_p2(Hoge *a)
{
    a->hoge = 2;
}

int main(void)
{
    {
        Hoge b(1);
        func_p1(&b);
        cout << b.hoge << endl; // => 1
        // あらあら (このままだとメモリーリークします)
    }
    {
        Hoge b(1);
        func_p1_(&b);
        cout << b.hoge << endl; // => 2
        // おぁ!?
    }
    {
        Hoge b(1);
        func_p2(&b);
        cout << b.hoge << endl; // => 2
        // うんうん
    }

    return 0;
}

またしても分裂してしまいました。ここで、func1 と同じものは func_p1 です。func_r1 と同じものは func_p1_ です。(本当は、参照は書き変え不可な所が違いますが。)
func_p1 と func_p1_ の違いのポイントは、代入時の左辺値が a か *a か、という点です。 これによって、処理の対象が "ポインタ" か "ポインタが指し示している先のオブジェクト" か、という違いが生じます。
C++ では参照を用いることで、"*" を使わずに "参照先のオブジェクト" に対して処理を実行することができます。

ところで、先程の C++ の関数はこうも書けます。

// __GooglePrettify__
#include <iostream>

using namespace std;

class Hoge
{
public:
    int hoge;
    Hoge(int a) : hoge(a) {}
};

void func_r1_(Hoge &a)
{
    a.operator=(Hoge(2));
}

int main(void)
{
    {
        Hoge b(1);
        func_r1_(b);
        cout << b.hoge << endl; // => 2
        // おおっ!?
    }

    return 0;
}

この書き方のほうが、参照先のオブジェクトの代入演算子を実行している...、参照先のオブジェクトのメンバ関数 operator= を実行しているということがわかりやすいと思います。
ポインタによる参照渡しの例 func_p1 に戻ると、こっちは参照先自体(ポインタ)を入れ替える処理が実行されます。そしてこれは、JavaScript での参照渡しと同様の動作です。

func_p1 と func_r1 の差はここです。

C++ での参照は、一貫して参照先のオブジェクトに○○を適用という感じです。 JavaScript でも、C++ のそれとだいたい同じなのですが、代入の時だけは参照を貼り替えるという動作になります。

なんとなくイメージはつかんでいただけたかなと思うのですが、いかがでしょう?

最後に、C++ では参照先のオブジェクトに対して代入演算子が呼ばれると言いましたが、この動作と同じようなことを JavaScript でやってみましょう。

// __GooglePrettify__
function assign(that){
    if (this === that) return this;

    for (var i in that) if (that.hasOwnProperty(i)) {
        this[i] = that[i];
    }
    return this;
}

function func1_(a) {
    a.assign = assign; // Assign method を生やして...
    a.assign({hoge: 2});
}
var b = {hoge: 1};
func1_(b);
print(b.hoge); // => 2

この様に、ちゃんと値が書き変わりました。

おわり。(続編は有りません。)

参考文献
GooglePrettify でシンタックスハイライトするようにしてみた
◆F99a.q8oVE: 2009/05/03 20:39:12

組み込むのは簡単だった。
steps to phantasien インスパイアで、__GooglePrettify__ を埋め込んだ <pre> 対象にしてみた。こうしておくと、FeedReader で読んでる人への目印(?)になる。

これら CSS と JavaScript をロードしておいて、

<!-- __GooglePrettify__ -->
<link rel="stylesheet" type="text/css" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" />

<script type="text/JavaScript" src="http://www.google.com/jsapi"></script>
<script type="text/JavaScript" src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script>
こんなのを実行するようにしておく。
// __GooglePrettify__
(function(){
        // jQuery をロードして…
        google.load("jquery", "1");

        // コールバックは google.setOnLoadCallback で指定
        google.setOnLoadCallback(function(){
            // __GooglePrettify__ を含む <pre> の class に prettyprint を指定して、__GooglePrettify__ の行を取り除く
            $("pre:contains('__GooglePrettify__')").addClass("prettyprint").each(function(i, elm){
                    elm.innerHTML = elm.innerHTML.replace(/^.*?__GooglePrettify__.*?\n/, "");
                    $(this).css("background-color", "white");
                });

            // prettyPrint!!
            prettyPrint();
        });
    })();
GooglePrettify のテスト
◆F99a.q8oVE: 2009/04/26 23:01:21
すいません。ちょっとテストしますよ。。。
/* __GooglePrettify__ */
#include <stdio.h>

int main(void) {
    printf("Hello world!\n");
    return 0;
}
ZFS で snapshot をローテーションしながら取得していく script
◆F99a.q8oVE: 2009/02/04 23:50:24

ZFS で、際限なく延々と snapshot をとるのではなく、古い snapshot は自動で消したいよね、というモチベーション。

そこで、こんな script を書いてみた。(自己の責任にてご利用ください。)

以下のように crontab に書いておくと…

@daily   /root/bin/zfs_snapshot.sh tank days_later   7  recursive
@weekly  /root/bin/zfs_snapshot.sh tank weeks_later  5  recursive
@monthly /root/bin/zfs_snapshot.sh tank months_later 12 recursive
@yearly  /root/bin/zfs_snapshot.sh tank years_later  10 recursive

このような感じで、今日 0days_later だった snapshot が明日には 1days_later ... というふうにローテーションしていきます。

tank/usr                                    5.23G   137G  2.64G  /usr
tank/usr@0weeks_later                           0      -  2.57G  -
tank/usr@0months_later                          0      -  2.57G  -
tank/usr@3days_later                        29.5K      -  2.57G  -
tank/usr@2days_later                        6.22M      -  2.59G  -
tank/usr@1days_later                        6.16M      -  2.59G  -
tank/usr@0days_later                        6.16M      -  2.59G  -

既知の問題

  • snapshot が規定数に達していない場合は、zfs destroy, zfs rename がエラーになる
  • コメントの英語が変
TypePad Connect でコメント欄をつけてみた
◆F99a.q8oVE: 2009/02/01 22:41:16

ということで、つけてみた。↓の方参照。

perl で seq を実装してみた
◆F99a.q8oVE: 2008/08/13 03:29:21

この前は mktemp を書いてましたが、今度は seq を書いてみました。 seq は、shell script でループを書く時によく使ってます。

勉強ということで、Test::Base を使ってみたり、コードは gist に貼ってみたり...。 しかし、これだと feed reader 上で直接コードが読めないところが難点かな。

(ref: Happy Testing Perl:第 2 回 Test::Base の紹介|gihyo.jp ... 技術評論社)

gist: 5103 — GitHub
perl で mktemp を実装してみた
◆F99a.q8oVE: 2008/08/03 20:44:40

最近、シェルスクリプトをいじってることが多いんだけど、シェルスクリプト中で使って便利なのが mktemp.

それで、乱用ぎみに使っていたのですが、とある環境で作業をしていて、mktemp を使おうと思ったら無かったんで perl で実装してみたり。

utils: perl/mktemp@09177d8ec349にあげておいた。 ライセンスはBoost Software License 1.0 (BSL1.0).

もっときれいに書けないかな〜。

#!/usr/bin/env perl
use strict;
use warnings;
use Fcntl;

# use Data::Dumper;

my $try_count = 10;

my %options = (
  t => 'using_tempdir',
  u => 'unsafe',
  d => 'dir',
);
my %mode = (
  using_tempdir => 0,
  unsafe => 0,
  dir => 0,
);
my $template;

foreach my $arg (@ARGV) {
  if ($arg =~ /^-(.*)$/) {
    foreach (split //, $1) {
      die "unknown option: $_" unless exists $options{$_};
      $mode{$options{$_}} = 1;
    }
  } else {
    $template ||= $arg;
  }
}

unless (defined $template) {
  $mode{using_tempdir} ||= 1;
  $template = 'tmp.XXXXXXXXXX';
}

# warn Dumper \%mode;
# warn $template;

my $temp_name;

while ($try_count) {
  $temp_name = $template;
  $temp_name =~ s/(X)/&rand_char($1)/eg;
  if ($mode{using_tempdir}) {
    $temp_name = ($ENV{TMPDIR} || '/tmp') . "/$temp_name";
  }
  # warn $temp_name;
  if ($mode{dir}) {
    last if mkdir $temp_name;
  } else {
    if (sysopen my $fh, $temp_name, O_WRONLY | O_CREAT | O_EXCL) {
      close $fh;
      last;
    }
  }
  $try_count--;
}

die "make temp failed: $temp_name" if $try_count == 0;

if ($mode{unsafe}) {
  if ($mode{dir}) {
    rmdir $temp_name or die $!;
  } else {
    unlink $temp_name or die $!;
  }
}

print "$temp_name\n";

sub rand_char() {
  my @chars = ('a'..'z', 'A'..'Z', 0..9);
  return $chars[rand(scalar @chars)];
}
TAP on C++
◆F99a.q8oVE: 2008/06/23 00:39:30

Test Anything Protocol - TAP ですが、なんとなく C++ で実装してみました。

tap.hpp

#ifndef TAP_HPP_526c07e9e0a11dc15e7838c85f7e46780782392d
#define TAP_HPP_526c07e9e0a11dc15e7838c85f7e46780782392d

#include <string>
#include <iostream>

namespace tap {
    size_t tests__ = 0;
    size_t numof_tested__ = 0;

    void tests(size_t n) {
        tests__ = n;
        std::cout << "1.." << n << std::endl;
    }

    void ok_notok__(bool is_ok, const std::string& name) {
        std::cout << (is_ok ? "ok " : "not ok ") << ++numof_tested__ << " - " << name << std::endl;
    }

    template <typename T, typename U> void is__(const std::string& file, size_t line,
            T got, U expected, const std::string& name = "") {
        if (got != expected) {
            ok_notok__(false, name);
            std::cerr
                << "#   Failed test '" << name << "'\n"
                << "#   at " << file << " line " << line << ".\n"
                << "#          got: '" << got << "'\n"
                << "#     expected: '" << expected << "'" << std::endl;
        } else {
            ok_notok__(true, name);
        }
    }

    template <typename T, typename U> void isnt__(const std::string& file, size_t line,
            T got, U expected, const std::string& name = "") {
        if (got == expected) {
            ok_notok__(false, name);
            std::cerr
                << "#   Failed test '" << name << "'\n"
                << "#   at " << file << " line " << line << ".\n"
                << "#     '" << got << "'\n"
                << "#         ne\n"
                << "#     '" << expected << "'" << std::endl;
        } else {
            ok_notok__(true, name);
        }
    }

    void fail__(const std::string& file, size_t line, const std::string& name) {
        ok_notok__(false, name);
        std::cerr
            << "#   Failed test '" << name << "'\n"
            << "#   at " << file << " line " << line << std::endl;
    }

    void diag__(const std::string& d) {
        std::cerr << "# " << d << std::endl;
    }
}

#define is(g, e, n) tap::is__(__FILE__, __LINE__, (g), (e), (n))
#define isnt(g, e, n) tap::isnt__(__FILE__, __LINE__, (g), (e), (n))
#define fail(n) tap::fail__(__FILE__, __LINE__, (n))
#define diag(d) tap::diag__((d))

#endif

こんな風に使います。

#include "tap.hpp"

#include <iostream>
#include <string>

using namespace std;

int main(void) {
    tap::tests(6);
    is(1, 3, "hoge");
    string hoge = "hoge";
    string geho = "hoge";
    isnt(hoge, geho, "hoge");
    isnt(0, 0, "hoge");
    fail("asdf");
    is(0, 0, "asf");
    diag("asdf");
    return 0;
}
実行すると...。
% g++ -Wall -Wextra test.cpp && ./a.out
1..6
not ok 1 - hoge
#   Failed test 'hoge'
#   at test.cpp line 10.
#          got: '1'
#     expected: '3'
not ok 2 - hoge
#   Failed test 'hoge'
#   at test.cpp line 13.
#     'hoge'
#         ne
#     'hoge'
not ok 3 - hoge
#   Failed test 'hoge'
#   at test.cpp line 14.
#     '0'
#         ne
#     '0'
not ok 4 - asdf
#   Failed test 'asdf'
#   at test.cpp line 15
ok 5 - asf
# asdf

a.t を用意して...。

#!/bin/sh
./a.out
% prove -v ./a.t
./a......
1..6
not ok 1 - hoge
not ok 2 - hoge
not ok 3 - hoge
not ok 4 - asdf
ok 5 - asf
#   Failed test 'hoge'
#   at test.cpp line 10.
#          got: '1'
#     expected: '3'
#   Failed test 'hoge'
#   at test.cpp line 13.
#     'hoge'
#         ne
#     'hoge'
#   Failed test 'hoge'
#   at test.cpp line 14.
#     '0'
#         ne
#     '0'
#   Failed test 'asdf'
#   at test.cpp line 15
# asdf
 Failed 5/6 subtests

Test Summary Report
-------------------
./a.t (Wstat: 0 Tests: 5 Failed: 4)
  Failed tests:  1-4
  Parse errors: Bad plan.  You planned 6 tests but ran 5.
Files=1, Tests=5,  0 wallclock secs ( 0.03 usr +  0.01 sys =  0.04 CPU)
Result: FAIL
[1]    3716 exit 1     prove -v ./a.t

こうなる。

freeHG にあげときました。BSL1.0 です。utils: Manifest

テストに失敗したときの戻り値を...には、まだ対応していません。

GNU/Linux で Expert Mouse を使うメモ
◆F99a.q8oVE: 2008/06/22 21:38:21

EM7 用 /etc/X11/xorg.conf 設定メモ

KENSINGTON 64325 EXPERT MOUSE OPTICALKENSINGTON 64325 EXPERT MOUSE OPTICAL

Section "InputDevice"
    Identifier     "em7"
    Driver         "mouse"
    Option         "CorePointer"
    Option         "Protocol" "auto"
    Option         "Device" "/dev/input/mice"
    Option         "Buttons" "9"
    Option         "Emulate3Buttons" "true"
    Option         "EmulateWheelButton" "8"
    Option         "EmulateWheel" "true"
    Option         "YAxisMapping" "4 5"
    Option         "XAxisMapping" "6 7"
  # Option    "DragLockButtons" "8"
EndSection

これで、右奥のボタンを押しながらボールを転がすことでスクロール可能に。

加えて Firefox の設定を以下にする(about:config で)と、横スクロールもできるようになる。Firerox 3 だと標準でこの設定になってるっぽい。

  • mousewheel.horizscroll.withnokey.action = 0
  • mousewheel.horizscroll.withnokey.numlines = 1
  • mousewheel.horizscroll.withnokey.sysnumlines = true
Powered by ◆F99a.q8oVE.