緑色備忘録


2009-12-23

スレッドプール

はてなブックマーク - スレッドプール - 緑色備忘録

gist: 262457 - thread pool- GitHub

TL上で「スレッドプール」という言葉を見かけて面白そうだなーと思ったから作ってみた.おわり.

2009-12-19

ETSテーブルに対する排他的制御

| 19:19 | はてなブックマーク - ETSテーブルに対する排他的制御 - 緑色備忘録

Erlang付属のデータベースシステムにMnesiaというものがあって,これを使えば排他的制御とか普通に可能なんだけど,使用方法が複雑で頭の悪い自分が使うには難しい(というか面倒くさい).だから,特にテーブルなどが必要の無いシステムを実装するのであれば,極力ETSを使うようにしてる.

ここで問題になるのが,ETSには排他的制御が存在しないということ.複数のプロセスが動作しているシステムの中で共通のデータベースを利用することにおいて,これは結構致命的だしバグの原因になると思う.Mnesia使えば済むことなのだが,前述の通り面倒だ.そこで,自分でロック機構を実装してみた.

多分車輪の再発明で,他にも良い手法があるのだろうけど,軽量プロセスの意外な利用方法とかを垣間見ることができたので自分的には満足.

start() ->
    %% hogehoge
    ets:new('Lock-Daemon', [set, public, named_table]).

lock(Table, Key, Func) ->
    Ref = make_ref(),
    case ets:lookup('Lock-Daemon', Key) of
        [] ->
            ets:insert('Lock-Daemon', {Key, spawn(fun lock_daemon/0)}),
            [{Key, Daemon}] = ets:lookup('Lock-Daemon', Key),
            Daemon ! {{self(), Ref}, {update, Table, {Key, Func}}};

        [{Key, Daemon}] ->
            Daemon ! {{self(), Ref}, {update, Table, {Key, Func}}}
    end,

    receive
        {Ref, ok} -> ok
    end.

lock_daemon() ->
    receive
        {{From, Ref}, {update, Table, {Key, Func}}} ->
            [Item] = ets:lookup(Table, Key),

            case Func(Item) of
                {ok, Result} ->
                    ets:insert(Table, Result);
                {error, _Reason} ->
                    pass
            end,
            From ! {Ref, ok}
    end,

    lock_daemon().

2009-12-06

gen_serverで例外が発生したら再起動させるメモ

| 16:09 | はてなブックマーク - gen_serverで例外が発生したら再起動させるメモ - 緑色備忘録

Erlang/OTPに含まれるgen_serverビヘイビアにおいて,例外が発生した際にサーバ再起動させるよう実装しようとして時間を無駄にしてしまったのでメモしておく.

まずgen_serverビヘイビアの動作について軽く説明すると,もし例外が発生したらterminate/2コールバック関数が呼び出されることになっている.で,その関数内でサーバ再起動するわけだけど,少し注意が必要.なぜなら大抵の場合,再起動ということでstart_linkに同じ名前を指定するのだけれど,terminateが呼び出された時点ではまだサーバが死んでなくて二重登録となるからなのか,思ったとおりに動いてくれなかった.

あと,理由は分からないけれど,別プロセス再起動してもらう必要があった.これは環境やタイミングによるのかもしれない.

terminate(Reason, State) ->
    io:format("terminate: ~p~n", [Reason]),
    spawn(fun() ->
        unregister(?MODULE),
        gen_server:start_link({local, ?MODULE}, ?MODULE, State, [{debug, [trace, log]}]),
        io:format("restart gen_server~n")
    end),
    ok.