手順

必要な gem を入れる

merb が動作している環境では、sqlite3-ruby, activerecord, activesupport, camping があれば良いらしい。

http://d.hatena.ne.jp/rabbit2go/20100427/1272376003 を参照して、必要な gem を install する。なお、markaby については、本来必要なバージョンは 0.5 であるが、依存関係の問題でより新しいバージョンがインストールされてしまう。これにより parkplace が起動しなくなってしまう。これは、0.5 以外のバージョンを削除して対応する。

Park Place のソースコード入手

git clone git://github.com/mattjamieson/parkplace.git にて入手

インストール

入手したソースの TOP に移動して、

$ ruby setup.rb config
$ ruby setup.rb setup
$ ruby setup.rb install

※ 最近のものは、最新の activerecord, activesupport で動作しなかったりするので、bin/parkplace でそれらを読み込んでいるところを編集して、バージョンに依存しないように変更する。

MacBook 再起動後に初期化するための設定

$ ln -s /tmp ~/.parkplace

Park Place の起動

$ parkplace

起動するときに初期ユーザー admin が自動作成される。

S3 クライアントの設定

  • ホスト: 127.0.0.1
  • ポート: 3002
  • Key: 44CF9590006BF252F707
  • Secret: OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV

Key と Secret については、最初に作成されるユーザーについては、どの環境であっても上記の値で固定されているらしいので、これを使わせてもらう。

実現方法

Park Place は DB(SQLite) にデータを保存している。
このデータを作成するディレクトリを /tmp にすることで、MacBook の再起動毎にデータを消すことを実現する。
データが毎回消えるため、自分で Park Place に登録したユーザーも削除されるが、代わりに最初から登録されている admin ユーザーを使用することで、この問題を回避する。

Park Place の使用上の問題を解決する

AMAZON S3 を使った開発をしているので、テスト用の S3 モドキとして Park Place を使っている。が、これには今 2 つの問題がある。

  • 遅い。特に spec が。
    • 動作しているマシンが遅いのかも?
    • データを一切消していないからかも?
  • 社内でしか動かない。
    • よって、MacBook単独でどこでも仕事をすることができない。

これを

  • MacBook に Parkplace を入れ、
  • MacBook の再起動時にデータを削除する

というようにして解決する。

さらに spec の実行を速くする

MySQL のデータを RAM Disk 上に置いて 3 倍の速度を達成したわけだが、さらなる高速化を考えた。

遅いところ

経験上、fixture を何度も読込んでいると遅いことがわかっている。fixture を before(:each) ではなく、before(:all) で読み込むようにすれば、回数が減るので速くなる。

ちなみに fixture は指定されたディレクトリ配下のファイル郡が
MySQL 上の一つの DB の各テーブルに対応させた状態にして管理している。
読込の単位は、このディレクトリ毎としている。

fixture の読込を減らす

同じ fixture を何度も読み込んでいることが問題なわけで、最初に一回読み込んだら、その snapshot を取って、再読み込みの際は snapshot まで戻せばよい。

MySQL に snapshot 機能は存在しない。
よって、 fixture を登録しているところで次のような処理を行うことで、これを実現した。

  1. 過去に fixture が読込済みで無い場合
    1. 通常の fixture の登録処理を行う
    2. mysqldump で DB 全体をバックアップする
  2. fixture が読込済みの場合
    1. mysql コマンドでバックアップからリストアする

速度

さらに 1.5 倍の速度が達成された。


Ram DISK : 366 sec
fixture を dump & restore : 232 sec
ちなみに mysql & mysqldump を TCP/IP 経由ではなく、UNIX DOMAIN Socket で接続すると 10 秒程度の向上がみられた(上記はこれを反映している)。

さらにさらに速くする

以下は未検証。

MySQL には snapshot 機能は無いわけだが、 Transaction は条件を限定すればそれっぽく使えるはず。


普通だったら処理の完了後は commit され、再度テストに使える状態ではなくなる。でも commit せずに rollback すれば、テストデータ投入時と同じ状態になるため、再度テストに使うことができるようになるはずである。


今作っているシステムは Transaction の「入り」、「出(commit)」を独自の Class によって管理しているので、「出(commit)」の部分では何も行わないようにして、fixture の再読込みで行うようにすれば、これは実現可能であると思う。


また、多分 MySQL の commit は「commit 後に実際に DB のデータを書き換える」構成のようなので、この方法によってかなりの速度向上が見込めるかと思う。

Mix-in の中で before :save を仕掛ける

Mix-in を include しても before :save などに、 Hook を仕掛けることができない。
before は module が定義される時に通常の method として実行されるが、そのモジュールには :save というメソッドは存在しないためである。


module が対象の model に include された後に、対象の model の instance 上で before :save を実行する必要がある。次のように記述すると、これを実現できる。

module TargetModule

  def self.included(base)
    base.before :save do
       :
       :       
    end
  end    

end


これで、 include しただけで Hook の設定が行われる。
以上は、 dm-optlock module のソースコードを読んでいて気がついた。
self.included 自体は ruby の機能の一つだ。