◆F99a.q8oVE::Blog
nfs 越しに使っていた iTunes のライブラリーが Marvericks にしたら調子が悪かったのを直した
f99aq8ove: 2014/01/06 00:43:07

nfs 越しに使っていた iTunes のライブラリーが Marvericks にしたあたりから、Podcast をダウンロードしてくれなかったり、再生する端から曲が消えたり調子が悪かったのを直しました。

原因は、Mac のファイル名正規化方式と nfs サーバー側のファイル名正規化方式が異なっていたせいでした。Marvericks にしたら症状がひどくなっただけで、今まではなんとなく動いてただけっぽいです。

詳しく言うと、Mac のファイル名正規化方式は NFD だけど、nfs サーバー側は NFC を期待していたので濁点等が入った日本語ファイル名を Mac が見失ってしまっていたようです。(正規化方式については Unicode正規化 - Wikipedia 参照。)

ということで、こんなかんじに Mac 側も NFC で正規化するように変更して対策しました。

% sudo mount -o rw,nfc,nodev,nosuid 10.0.1.1:/safe_bucket /Volumes/safe_bucket

マウントオプションに nfc を付けただけです。(nfs サーバー、マウントポイントは環境によって異なります…。)

ただ、既に NFD で作られちゃったファイルはそのままなので、適当にスクリプト書いて rename する必要がありました。Rename NFD directory/file name to NFC directory/file name recursively.

あぁ、正月休みも終わりですねぇ…。

FreeBSDなファイルサーバーからexportしたドライブをiSCSIでマウントして、Time Machine用に使う
◆F99a.q8oVE: 2011/04/03 22:25:41

Macのバックアップ機能Time Machineは、直接USBで接続したHDDを使うのは簡単ですが、NASのようにネットワーク越しのドライブを使用するには小細工が必要なことで有名です。

本エントリでは、ネットワーク越しにFreeBSDなファイルサーバーをiSCSIでマウントできるようにして、これをTime Machineに使ってみます。

  • FreeBSD 8.2-RELEASE
  • istgt-20110223

Time Machine用にzfs領域(なんて言うんだっけ?)を確保しておきます。

## __GooglePrettify__
# zfs create -o mountpoint=/timemachine tank3/timemachine

ここで、zfsの設定からshareiscsi=onを設定してみても、FreeBSDではサポートされていなくて残念な思いをします。 なので、portsから以下をインストールします。

## __GooglePrettify__

# cd /usr/local/etc/istgt
# cp auth.conf.sample auth.conf
# cp istgt.conf.sample istgt.conf

istgt.conf を適宜修正。以下では、ファイルサーバーは10.0.1.1, マウントするマックは10.0.4.1です。

## __GooglePrettify__
--- istgt.conf.sample   2011-04-01 02:04:14.638057161 +0900
+++ istgt.conf  2011-04-02 17:14:28.031064416 +0900
@@ -17,7 +17,7 @@
 [Global]
   Comment "Global section"
   # node name (not include optional part)
-  NodeBase "iqn.2007-09.jp.ne.peach.istgt"
+  NodeBase "iqn.2007-09.net.f99aq8ove.istgt"

   # files
   PidFile /var/run/istgt.pid
@@ -83,7 +83,7 @@
   Comment "SINGLE PORT TEST"
   # Portal Label(not used) IP(IPv6 or IPv4):Port
   #Portal DA1 [2001:03e0:06cf:0003:021b:21ff:fe04:f405]:3260
-  Portal DA1 192.168.2.36:3260
+  Portal DA1 10.0.1.1:3260

 # wildcard address you may need if use DHCP
 # DO NOT USE WITH OTHER PORTALS
@@ -95,10 +95,10 @@

 [InitiatorGroup1]
   Comment "Initiator Group1"
-  InitiatorName "iqn.1991-05.com.microsoft:saturn"
+  # InitiatorName "iqn.1991-05.com.microsoft:saturn"
   # special word "ALL" match all of initiators
-  #InitiatorName "ALL"
-  Netmask 192.168.2.0/24
+  InitiatorName "ALL"
+  Netmask 10.0.4.0/24

 # TargetName, Mapping, UnitType, LUN0 are minimum required
 [LogicalUnit1]

@@ -106,13 +106,13 @@
   # full specified iqn (same as below)
   #TargetName iqn.2007-09.jp.ne.peach.istgt:disk1
   # short specified non iqn (will add NodeBase)
-  TargetName disk1
-  TargetAlias "Data Disk1"
+  TargetName timemachine
+  TargetAlias "Time machine"
   # use initiators in tag1 via portals in tag1
   Mapping PortalGroup1 InitiatorGroup1
   # accept both CHAP and None
-  AuthMethod Auto
-  AuthGroup AuthGroup1
+  AuthMethod None
+  #AuthGroup AuthGroup1
   #UseDigest Header Data
   UseDigest Auto
   UnitType Disk
@@ -136,7 +136,7 @@

   # LogicalVolume for this unit on LUN0
   # for file extent
-  LUN0 Storage /tank/iscsi/istgt-disk1 10GB
+  LUN0 Storage /timemachine/tm1 200GB
   # for raw device extent
   #LUN0 Storage /dev/ad4 Auto
   # for ZFS volume extent

また、ファイヤーウォールの 3260 tcp/udp を開けておきます。

## __GooglePrettify__
# echo istgt_enable="YES" >> /etc/rc.conf
# /usr/local/etc/rc.d/istgt start
# /usr/local/etc/rc.d/istgt start

これでサーバー側の設定は完了。次はマック側の設定です。 globalSAN iSCSI initiator for OS Xをインストールします。

環境設定でglobalSANの設定画面を開いてTargetの追加で
Target Name: iqn.2007-09.net.f99aq8ove.istgt:timemachine
でadd
iSCSI Options... -> Always send "SessionType" when connecting. をチェック
そのあとでIPaddrを登録してconnect

初期化するか聞いてくるので初期化して、このディスクをTimeMachineで使うようにして完成

適当 Net::Cassandra ラッパー
◆F99a.q8oVE: 2010/06/06 20:46:09

Twitter Streaming API で流れてくるユーザー情報を保存するのに、初めは MySQL を使っていました。でも、IO が重かった(自宅ファイルサーバ兼用なので……)ので、Cassandra に切り替えてみました。ちょうど、Key-value store っぽい使いかたしかしてなかったし。

もう少しちゃんと実装してテストも書いてから出そうかと思ってたけど、数ヶ月進展しないからとりあえず貼ってみます。

grub2 を入れてみた
◆F99a.q8oVE: 2010/05/09 16:32:00

最近、Ubuntu 10.04 (lucid) にアップグレードしたんだけど、grub2 が入ってなかったので、手動で grub2 を入れてみた。

実は、Ubuntu 9.10 から grub2 がデフォルトだったらしいけど、クリーンインストールはしてなかったので、自動では grub2 は入らなかったみたい。

% grub-install -v
したら、0.94だったかな?

grub2 をインストールする

% sudo aptitude install grub2
これで、インストールされる。表示されるデフォルトの選択子を選ぶと、grub2 は menu.lst からチェーンロードされる。この状態で grub2 がちゃんと動作することを確認して、
% sudo upgrade-from-grub-legacy
してやれば、直接 grub2 がロードされるようになる。

とまぁ、特に設定してないんで代わり映えはしないけど、とりあえず grub2 になった模様。

% grub-install -v
grub-install (GNU GRUB 1.98-1ubuntu6)

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

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

Powered by ◆F99a.q8oVE.