その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

ベンチマークを取り続ける為にやってる小技

たしか,実践ハイパフォーマンスMySQL に書いてたテクニックだと思うんですけど.

ベンチマークを取る時に同時に lock file を作っておいて,それが存在し続ける限りベンチを回し続ける,という風にすると何かと便利.

setvbuf(stdout, NULL, _IONBF, 0); // stdout のバッファリングを無効にしておく (しなくても良い)

char *bench_lock_file = "./bench.lock";
fopen(bench_lock_file, "w"); // ここでロックファイル作る

// lock ファイルが存在している間,処理を回し続ける
while (access(bench_lock_file, F_OK) != -1) {
    // ここで何らかのベンチマーク的な処理をさせる
    printf("Bench no Kekka Dayo!\n");
}


これをコンパイルして,

$ ./a.out > ./bench_result.log

という感じでやってやるとベンチの結果が延々延々取れる.
(なお,上のコードでバッファリングを無効にしたのは tail -f 等でログファイルを見たかったからです.)


「ベンチ回すのをやめる!!」という時は

$ rm bench.lock

という風に lock ファイルを消してやると,回っている最中のベンチが回り終わったらプログラムを終了させることが出来ます.


便利!


実践ハイパフォーマンスMySQLMySQL の話だけではなくてこういう技法についても言及されていて有益な感じでした.

実践ハイパフォーマンスMySQL 第3版

実践ハイパフォーマンスMySQL 第3版

Mac OS X で Eclipse を開くと環境変数を引き継がないので端末から起動するようにした

Mac OS X (手元の環境はバージョン10.10.1) で Eclipse (手元の環境はバージョンは Luna 4.4.1) を開くと環境変数を引き継がないので,IDE 上でプログラムを走らせたりテストを実行したりするとコケる場合があって厳しい気持ちになります.

端末上から Eclipse を開くと環境変数が引き継がれるようなので以下の様な alias を張り,端末上から Eclipse を起動することでこの問題を回避 (根本的未解決) しています.

alias eclipse='open /Applications/eclipse/Eclipse.app'


なんか他にもっと良いやり方知ってる方教えてください.

Git の Tag が打たれる毎に Travis CI を使って fat-jar を GitHub Releases にリリースする

Java で書かれた CLI ツールやアプリケーションを配布する時,依存するモジュールを全部まとめて1つの jar ファイルに固めて,単独で実行可能にしておくと何かと便利です.巷ではこうした jar ファイルを fat-jar と呼ぶようです.

この fat-jar ファイルをどこにホスティングしようかと考えた時,Perl だと fatpacked なスクリプト (fat-jar のように全部の依存を1つにまとめたスクリプト) をモジュールのコンポーネントに含めてそれごと CPAN にアップロードして CPAN 経由で配布するというのが一般的だったんですが,Maven Central ではどうやらそういう方法は人気が無いようなので,今回は GitHub Releases で配布することにしました.

今回は Git の Tag が切られて push された時 (つまりリリース処理がされた時) に自動的に fat-jar をビルドして GitHub Releases にリリースしたかったので,Travis CI の deploy 機能 (まじ便利!!) を利用して実現することにしました.


以下,その為に実行した手順です.
java-mysql-diff で同様のことを行っているので,適宜参照してもらうと良いと思います.

Releases · moznion/java-mysql-diff · GitHub

1. fat-jar な jar ファイルを maven でビルドする

Maven で fat-jar を生成する為に, pom.xml を以下のように記述しました.

...
<profiles>
  <profile>
    <id>fatjar</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.5.3</version>
          <configuration>
            <descriptorRefs>
              <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
          </configuration>
          <executions>
            <execution>
              <id>make-assembly</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>
...

maven-assembly-plugin を使い, jar-with-dependencies を有効にしておいて,package フェイズで走らせるようにする設定にしておくと,fat-jar を 生成する事が出来ます *1

以下のようにコマンドを走らせると fat-jar を生成することが出来ます.-P fatjar は profile の id です.

$ mvn -P fatjar package

参考: java - Building Maven fat jar conditionally - Stack Overflow

2. .travis.yml を編集して,tag が打たれて push される毎に GitHub Releases にリリースするようにする

手始めに travis コマンドをインストールします.travis コマンドは Ruby Gems で配布されているので適宜やっていきます.
travis | RubyGems.org | your community gem host

$ gem install travis

次に travis setup コマンドを実行して,リリースに必要な .travis.yml の内容を生成します.
今回は GitHub Releases にリリースするので,travis setup releases を実行します.

$ travis setup releases
Detected repository as your/repository, is this correct? |yes|
Username: foobar
Password for foobar: ******************************
File to Upload: target/fat.jar
Deploy only from your/repository? |yes|
Encrypt API key? |yes|

コマンドを実行すると色々訊かれるので適宜答えます.デフォルト値が yes になってるところは大体 yes で良いような気がしています.
正常に完了すると,以下の様な内容が .travis.yml に追加されると思います.

deploy:
  provider: releases
  api_key:
    secure: <SECRET KEY>
  file: target/$TRAVIS_TAG.jar
  on:
    repo: your/repository

これに色々足していきます.

deploy:
  provider: releases
  api_key:
    secure: <SECRET KEY>
  file: target/$TRAVIS_TAG.jar
  skip_cleanup: true
  on:
    repo: your/repository
    all_branches: true
    tags: true

all_branchestags が有効になってないと,tag を切った時にリリースというのが上手く動かなかったので追記しておきます.skip_cleanup: true はまあ適当にという感じ.


あとは .travis.yml に before_deploy のフェイズでデプロイ対象となる fat-jar (今回の場合は file: target/$TRAVIS_TAG.jar) を生成してやる設定を追記します.

before_deploy:
    - mvn -P fatjar clean package -DskipTests=true -Dproject.finalName=$TRAVIS_TAG

環境変数 $TRAVIS_TAG には git の tag 名が入っているので,それを上手いこと使ってやると mvn release:prepare のようなコマンドでリリース処理を行う時に,自動的に切られる tag 名と噛み合って便利だったりします.まあここらへんはお好みでという感じです.

3. tag を切って push

後は git の tag を切って push すると自動的にテスト・ビルドが走って自動的に GitHub Releases にリリースされます.




手順は以上です.

このように,リリースするたびに自動的に fat-jar をリリースするようにしておくと結構便利です.
今回は Travis CI を利用しましたが,wercker 等の他のサービスでも同様のことが出来ると思います *2

ぜひお試し下さい.

*1:build の設定で maven-jar-plugin を併せて利用する必要があると思います

*2:しかし wercker は tag が切られるタイミングでごにょごにょする,みたいなのをやるのがちょっと面倒くさくて見送ったという経緯が……

java-mysql-diff が出た

java-mysql-diff が出ました.Maven Central にもリリースしています.

http://search.maven.org/#artifactdetails|net.moznion|mysql-diff|1.0.0|


本パッケージは id:onishi さん作の mysqldiffJava 8 移植版です.
最近 Java の環境で作業することが多いので,なんだかんだで Java 版があると便利だよね〜ということで作成しました.

本家の Perl 版 mysqldiff と同じような感覚で利用したかったので,全部の依存パッケージを1つにまとめた fat-jar も用意してあります.
java -jar というコマンドを余分にタイプする必要はありますが,Perl 版と同じような感覚で利用することが出来ます.

https://github.com/moznion/java-mysql-diff/releases


さて,mysqldiff は大きく分けると以下の様な処理のステップで構成されています.

1. mysqldump を利用する事によって,ノーマライズしたスキーマ情報を吐き出す

  • SQL ファイルが与えられた場合は,実際に temp detabase を MySQL 上に作成して,そこに SQL の内容を流し込んでからその DB を mysqldump で dump する
  • ローカルの DB 名が与えられた場合はその DB を mysqldump で dump する
  • リモートの DB 名が与えられた場合,そのリモートの DB を mysqldump で dump して,その dump した内容をローカルの temp database に流し込んでから再度 mysqldump で dump する (dump する際に2段階の手順を踏んでいるのはローカルの MySQL と リモートの MySQL との差異を無くすためだと思う……)

2. ノーマライズしたスキーマ情報をパーズしてデータ構造に落とし込む
3. データ構造を比較して diff を取る

mysqldump を使って,入力をノーマライズして構文の揺れを無くしてパーズしやすくするという手法,マジで天才では……と移植中感心しきりでした.
上記のように実際に database を作成したり,mysqldump を実行したりするので,プログラムを走らせる際には mysqld が立ち上がっていて,なおかつ mysqldump コマンドが実行可能な状態になっている必要があります.


ぜひご利用下さいませ.

java-mysql-namelocker が出ていた

そういえば java-mysql-namelocker が出ていました.Maven Central にもリリースされています.

http://search.maven.org/#artifactdetails%7Cnet.moznion%7Cmysql-namelocker%7C1.0.0%7Cjar


Perlには Mysql::NameLocker というモジュールが古くからあり,このJavaのパッケージはその移植版になります.

何をするパッケージかと言うと,MySQLGET_LOCK() を用いてコネクションと紐付いた名前付きロックを取得し,try-with-resources のスコープを抜けた時に自動的に RELEASE_LOCK() を発行してロックを解除するというシンプルなパッケージとなっています.或るコネクションがロックを取得している間は,他のコネクションは同じ名前でそのロックを取得できない (AlreadyLockedException が返ってくる) ので,コネクションと名前に応じた排他処理をお手軽に実現することが可能となります.

AutoCloseable を implement すると try-with-resources 文を使ったリソースの自動リリースを簡単に実現できて最高ですね!

Have a nice lock!


さて一番難しかったのはJavaのコードでもなんでもなくて,pom.xml の記述と Maven Central へのアップロードでした……
が,これもtagomorisさんのブログ記事とtokuhiromさんのブログ記事を見ながら頑張ったら出来たので,まあなんとかなるな! という感じです.本当に助かりました.

maven central にリリースしてみた - blog.64p.org
はじめてのmaven central 公開 - たごもりすメモ


余談ですが,OS X環境でgpg鍵作る際は brew install gpg2 してから gpg2 --gen-key すると簡単で良かったです.

デプロイ考,あるいは仕組み化考

良い感じに酔っ払っているのでここ最近デプロイについて考えていることについて記す.


デプロイの仕組みが単純であれば単純であるほど良い,というのは総意だと思っている.
単純な仕組みによってデプロイされるのと,複雑な仕組みによってデプロイされるのとで比較した時,
互いの結果 (つまりユーザに提供できる機能) の差が有意でなければ,
単純な仕組みの方が総コストが低くて良い.


で,ここで出てくるのが「仕組み化」ってやつで,
仕組み化はそうした総コストを下げる為にやる,
つまり作業を楽ちんにするためにやると思うんだけど本当に楽ちんなのかどうかは
冷静に考える必要があると思っている.
(あるいは例えば,それオーバーエンジニアリングやん,とか)


最初のうちは仕組み化できて嬉しい,最高,これで平和が訪れた! みたいな感じになると思うんだけど,
ゆくゆくは色々な事情から変更変更そして怒涛の変更が訪れて,仕組みもありのままではいられないと思う.
ビジネスは素早い.


そういう感じで変更が生まれた時には仕組みに手を入れる必要が出てくると思うんだけど
そういう「仕組み」っていうのはたいていブラックボックス化されていて,
つまり表層の面倒臭さみたいなものを抑えこむ為に複雑怪奇なメカニズムになってる場合が多い気がする.
(あるいは何かPaaSを使ってるとしたら,なんらかのhackishなプロセスが要るとか)
「まあブラックボックスだからええやん?」みたいな感じでゴミ溜めのようになりがちというのもあると思う.
結局そこに手を入れる事で要らぬ苦労をし始めてしまって,楽をするための仕組みをいじるために異常に苦労するという
ケースが少なからずあってつらい.仕組みに囚われる.仕組みに殺される.


で,そういう地獄を避けるためには変更に強くする必要がある.
変更に強くするというのは重要で,我々はその点に心を強く持つ必要がある.
(あとはその副次的な要求で,構造をシンプルに保つというのもあると思う)


さて,その「変更に強い」というのは本当に変更に強いのだろうか?
ただ単純に「物を追加しやすい」だけではないのか?
「変更に強い!!!」とうそぶいて,アドホックに欲しい機能を追加しまくっていった結果
死んでしまった存在というのを我々はたくさん見てきたのではないのか?
「変更に強い」というのは,むしろ使わなくなった機能を抽出・検出しやすい,
そして取り替えやすいということではないのか? 機能の足しやすさとはまた違う概念なのではないのか?


まあ,とにかくそういう感じでデプロイのプロセスが複雑になっていくのは,
そもそもそういう複雑さをアプリケーションが要求しているからではないのか,
という事は心の隅に留めておくと良いのではないか,と思っていて,
「シンプルなデプロイでいける!」という構造を心がけるのは重要な気がしている.
例えばサーバサイドでステートを持つ必要が無いやつはjsオンリーで書いて,
GitHub Pagesにpushするだけで動く,みたいなのがシンプルで良い気がしている.
まあ,なんだかんだでFTPでファイルアップロードして一発で動く,みたいなのが理想なんじゃんすか?
というわけで,シンプルなデプロイにするためにはシンプルなアプリ構造を考える必要があると思った次第.


まあなんか話が逸れましたけれども,とにかく仕組み化して終了!!! みたいなものではない,
仕組み化はゴールではなくスタートだ,仕組み化したから最高のプロダクトが生み出されるわけではない,
仕組み化してからのプロジェクトの進行,運用,そして祈りが良いプロジェクトか否かを左右するのだなあ,
というのはここ最近強く思った次第です.


メリークリスマス!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
もうだめだ

Validation Nightやりました

色々あって報告が遅くなりましたが,去る12月4日にValidation Nightというイベントを催しました.

多岐にわたるValidation (或いはConstraint) の知見が惜しみなく披露された非常に良い会になったのでは無いかと思います.
発表内容に関しては以下が詳しいのではないかと思います.

Validation Night で話してきた - blog.64p.org

Validation NightでBean Validationについて発表してきた #v_night - コードつれづれ

漢(オトコ)のコンピュータ道: Validation nightで発表しました。

Validation Night で focuslight-validator の紹介をしてきたよ - Studio3104::BLOG.new

WebApplicationフロントエンドValidation

Rails Context Validation // Speaker Deck

Validation nightで発表しました。 #v_night - by shigemk2

発表者の皆さん,参加者の皆さん本当にありがとうございました.


さて最後になりますが,色々と不手際があり *1 参加者の皆さんにご不便おかけしたことをお詫び致します.次回はスムーズに開催できるように努力しますのでよろしくお願いします.


では皆さん,次回の「外部キーNight」でお待ちしましょう (マジか)

*1:初めてconnpass使ったりとか,初めてLINEのカフェを会場にしたりとか,そういうのが色々積み重なってですね……