鱒身(Masu_mi)のブログ http://blog.masu-mi.me/ 知った事をメモする場所。 en-us Thu, 23 Mar 2017 00:00:00 +0900 http://blog.masu-mi.me/2017/03/23/tryout_gotty.html http://blog.masu-mi.me/2017/03/23/tryout_gotty.html <![CDATA[Gottyを使ってみた]]> Gottyを使ってみた

ttyをブラウザ経由で利用できるツールはいくつか存在する。 Go実装のyudai/gottyを試してみた。 とてもシンプルで簡易で何かするのに使うくらいだと思われる。

あとからfork版のyubo/gottyを見つけた。 こっちは機能が豊富でパッケージ化も進んでいて扱いやすそう。

Read more...

]]>
Thu, 23 Mar 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/03/20/golang_example_test.html http://blog.masu-mi.me/2017/03/20/golang_example_test.html <![CDATA[Golang:testing Example]]> Golang:testing Example

GoにExample functionテストがあるの知らなかった。

とりあえずExampleXXXX()って関数名で使える。 キーワードはOutput:, Unordered output:って2つのコメントになる。

ドキュメントによるとExampleテストの関数名で対応する関数やメソッドを解決してGodocのExampleに掲載してくれるらしい。

Read more...

]]>
Mon, 20 Mar 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/02/19/update_go1_8.html http://blog.masu-mi.me/2017/02/19/update_go1_8.html <![CDATA[Update to Go 1.8]]> Update to Go 1.8

先日Go1.8 がリリースされた。 ソースコードからビルドしたら失敗した。 調べてたらIssueが上がっていて対処が判明したのでメモしておく。 ついでなのでリリースノートについても目を通した。

Read more...

]]>
Sun, 19 Feb 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/02/17/make_signal_context.html http://blog.masu-mi.me/2017/02/17/make_signal_context.html <![CDATA[Golang: contextを使ってみる]]> Golang: contextを使ってみる

contextについて調べたので試しにos.Signal を受け取るとキャンセルを実行するcontext.WithCancelBySignal()を作った。

書いてから振り返るとcontextはトランザクション単位で用いるがos.Signalはプロセス全体に関わるため概念が一致しづらい。 exec.CommandContext()SIGKILLを飛ばしてしまうので子プロセスは直ちに死ぬ。そのままでは使えず相性が悪い。 ただ作ったのでとりあえず残す。

Read more...

]]>
Fri, 17 Feb 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/02/16/intro_golang_context.html http://blog.masu-mi.me/2017/02/16/intro_golang_context.html <![CDATA[Golang: contextを試す]]> Golang: contextを試す

勉強したことのメモ。

contextはv1.7から標準パッケージに含まれている。 関連処理をgoroutinによって非同期に実行する事が多いGo言語では対象トランザクションに関連した処理に対して横断的な制御をするのに苦労する。 contextパッケージがインタフェースを整えてくれる。

現在は主に2つの機能を提供している。

  • トランザクションの属性情報を共有
  • タスク間の依存関係をツリーを管理(キャンセル(完了)を下流に伝搬させる)

主に、キャンセル通知の伝搬経路としてcontextを捉えると考えやすい。 キャンセル対象は何でキャンセルされず実行するのは何かを分類するとcontextの親子関係のデザインが固まると思う。

またトランザクションは複数プロセス・ホストに関わることもある。 os/execCommandContext()net/httpRequest.WithContext()などがプロセスに閉じこもらないトランザクションの挙動やキャンセル処理に貢献している。 当然だけどプロセスが異なる場合はキャンセル処理を親側が実施する事で伝達されるがcontextのインタフェースとして伝達されるわけではない。

属性情報の共有の方針は賛否両論な2通り出てくると思っている。

  • HTTPリクエスト単位でrequest_idなどを横断的に共有する場合にcontextに含めて持ち回る
  • http.Requestをラップしたリクエスト構造体やインプット構造体を引数としてドメインレイヤーに渡す

ログ用の情報などアプリケーションと関連しない一般的な横断情報とは何かの合意が取れたり慣例が貯まれば、 ミドルウェやフレームワークの整合性を高められるためcontextに寄せた実装が増えていくと想像している。

気軽にアプリケーションに閉じ込める場合はcontextに入れてリフレクションするよりもリクエスト構造体を利用する方が簡潔で好まれると考えている。

どちらの方針を取るにしても、バックエンドへのクライアントなどサービス機能についてcontextとは役割が違うので入れるべきではない。

Read more...

]]>
Thu, 16 Feb 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/01/28/training_algorithm_chord.html http://blog.masu-mi.me/2017/01/28/training_algorithm_chord.html <![CDATA[アルゴリズム練習: Chord]]> アルゴリズム練習: Chord

分散システムを自分で設計・実装できるようになりたいので基本的な分散アルゴリズムを勉強したり実際に書いてみることにした。 教科書に従って書いていて、用語などの前提には触れずメモを残すだけなので読むの辛いと思う。

tl;dr

DHT(Distributed Hash Table)を実現する代表的なアルゴリズムであるChordを実装してみた。

DHTっていうのは構造化オーバーレイネットワークの1つで多数の分散したノード上にハッシュテーブル(set, get)を提供するシステムを指す。 Chordはそのようなサービスを提供するアルゴリズムの1つで、ノードのアドレスとデータのキーを同一のS1集合へ射影することで資源探索を行う。 またノード数Nに対してリソース提供ノードを確定するのに必要なノード数をO(logN)にするように経路表を維持している。

../../../_images/new_ring_completed.png

多数のノードがつながりリングが形成されている (ピンク: succ, 青: pred, 点線: fingers)

とりあえず実装したのはRendezvous, Location, Routingのロジック部分で実際の通信やKVSサービスは実装してない。 簡単なコードのテストは書いたが複雑な部分はシナリオを通過したノードがどのようにつながっているかdot形式で出力して可視化した。 論文の他に教科書(Distributed Computing)も参考にした。詳しい解説スライドも読みました。

Read more...

]]>
Sat, 28 Jan 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/01/20/technory_published_policy.html http://blog.masu-mi.me/2017/01/20/technory_published_policy.html <![CDATA[内製技術を公開するにあたって]]> 内製技術を公開するにあたって

主にソフトウェアについて社内の既存のソフトウェアに対する競合技術が社外に現れたと感じた時の判断する目安について妄想してみた。 関連して新たに社内で開発する前に検討する事も考えてみた。

ミドルウェア・プラットフォームを内製するか迷ってる

既に社外に類似サービス・ソフトウェアがあるか調査して存在しなければ内製すればいい。 要望・要件と目的を整理して検索して出てきたシステム・サービスを列挙する。 満たせている/満たせていない、をカタログ的に分類する。目的や要望・要件に変更を加えられないか検討する。 変更を加えた時のデメリットを検討する(一般化できずに社内で使いまわせないなど)。

要件や要望が類似している場合には内製根拠が必要になる。 利用に際してライセンス料・サービス利用料が大きい、検証によって要件を満たせない事を示すの2択が考えられる。 検証によって要件・要望を満たせない事が示されたら、更に提案や要望による貢献で解決できないかも確認する。 長期的にみて改善しそうでも期日に間に合わない場合で、更に内製で間に合うと判断できる場合はそれを採用する。

  • 最適化の方向が異なり改善提案は成立しない
  • アーキテクチャ的な問題により長期的に改善が見込めない
  • 要望をコントロールできない。

内製してみる

社外エコシステムを取り込みやすい様に開発する。

既に独自開発していて競合(ソフトウェア・サービス)が力を付けてきた

気づいたら早めに課題を指摘して社内技術を公開して共存できる様にする。 これがコミュニティを育てて社内技術のレガシー化を防ぎつつ開発リソースをアウトソースするのに繋がる。

公開する内容の選択肢

4つの選択肢をを考えてみた。2つ目以降は(少なくとも間接的に)インタフェース公開が含まれる。 インタフェースについてはエコシステムに貢献して強い立場を作ったり、社内技術がガラパゴス化しない様にできるかを左右するので慎重に扱いやすく外部との相性も良くなるように整理しておく必要がある。

  • 課題 + 方法(特許, 論文, 白書, 記事)
  • 課題 + 方法 + インタフェース
  • 課題 + サービス (+ インタフェース)
  • 課題 + ソフトウェア (+ インタフェース)

公開する前に、内製ソフト・プラットフォームで満たしていて社外で満たせていない要件や要望や課題について整理する。

下手なものを公開できないけど早めに貢献したい

関連する内製ソフトウェアの要望・要件から外部と共通の一般化できるばしょを確認する。 外部では満たせない項目は何に依存しているのか調査する。 一般化ができたり自然に辿り着く様な事であれば上述の4つの選択肢などを実践して貢献するのが良さそう。

どの選択肢でも、技術力や主導権を維持してエコシステムが滅びないようにコミュニケーションを測るのが大事になる。 特にソフトウェア公開ではコミュニティの運用や宣伝が必要になったりとマネジメントコストが増す可能性がある。 コアコミッタやってた経験がある人がいたら聴いてみたい、案外そんなことないのかも。

社内要件というかアプリケーション要件がべったりな場合は要件整理のチャンスと考える。 整理の後で一般化されうる部分は、外部に貢献する社外システムを取り込みメンテナンスコストを押さえるか再び検討する。

社内開発をしつつ社外に対して孤立しないための技術マネジメントってこんな感じなんだろうなって思ってる。

]]>
Fri, 20 Jan 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/01/15/memo_entrypoint_zeromq.html http://blog.masu-mi.me/2017/01/15/memo_entrypoint_zeromq.html <![CDATA[メモ: ZeroMQの入り口]]> メモ: ZeroMQの入り口

通信の基本的な意味でZeroMQ(v4)を勉強した。

通信状況を解析する

通信内容を解析したい

wiresharkで解析するDissectorを書いてる人がいたので利用する。

通信量を追いたい

トラフィック量だけでいいのであればやってみた的な記事がコミュニティ配下にあったので参考にする。

リーディング

ZeroMQのトランスポートプロトコル(QUIC,PCC,SCTP,...)を追加したくなったと仮定してコードを読んだ。

TL;DR

手始めにzmq_bindを起点にTCPに重点を置いてコードを追った。 bindを成功させるには下をすれば良いと思われる所までは読めた(はず)。

  • プロトコルに対応付けるオブジェクトをown_tを継承して作成する
  • zmq::socket_base_t::check_protocol, zmq::socket_base_t::bindを書き換えてプロトコルを許可する
  • zmq::socket_base_t::bindの追加したコードでzmq::socket_base_t::add_endpointを呼び出す

続けてconnect, recv, send系を読んで条件を確認すればZeroMQのトランスポートレイヤ追加も夢じゃない!(はず..) recvくらいは読むかもだけど本格的に追うかは迷い。 あとIPv6周辺のコードが未だに苦手だと感じたので勉強しておきたい。

Read more...

]]>
Sun, 15 Jan 2017 00:00:00 +0900
http://blog.masu-mi.me/2017/01/14/memo_nmap_script.html http://blog.masu-mi.me/2017/01/14/memo_nmap_script.html <![CDATA[Nmapでスクリプトが利用できる]]> Nmapでスクリプトが利用できる

機会があってNmapスクリプトを動かせることを知った。 しかもLuaなのでとてもカジュアル。 組み込み向けで可搬性を意識した設計のためかLuaはWiresharkなどでも使えるし良い言語だと思います。 (久しぶりに開発環境整備して遊びたい) それはさておき使ってみた。

スクリプトは–scriptオプションでスクリプトを指定して実行する。

スクリプトはLinuxであればおそらく以下に位置している。

/usr/share/nmap/nselib        # スクリプトに使われるライブラリが配置される
/usr/share/nmap/scripts       # スクリプトは${script_name}.nse として配置される
/usr/share/nmap/nse_main.lua  # スクリプトを読み込んだりするコードが書かれてる

スクリプト: broadcast-dropbox-listener

以前Wiresharkで見つけたプロトコルが飛んでいるか確認するbroadcast-dropbox-listener スクリプトがインストール済みだったため試してみた。

$ nmap --script broadcast-dropbox-listener
../../../_images/result-of-broadcast-dropbox-listener.png

他にもheartbleed(CVE-2014-0160)対策済みか確認するssl-heartbleed なども存在する。 監視とか安全性検証に使えるはず。スクリプトの書き方はNmap Scripting Engineのドキュメント を参考にする。

]]>
Sat, 14 Jan 2017 00:00:00 +0900
http://blog.masu-mi.me/2016/12/21/bench_cmp_string_in_golang.html http://blog.masu-mi.me/2016/12/21/bench_cmp_string_in_golang.html <![CDATA[Golang: 文字列比較]]> Golang: 文字列比較

今回の結論は文字列比較はシンプルなのが良い。

今はgo1.8beta2とかのタグが切られているけれど、今年(2016)の8月Go1.7がリリースされたこの時の改善項目にbounds check elimination(BCE)最適化が含まれている

bounds check elimination(BCE)は配列にインデックスを用いてアクセスする際に適切な範囲か確認する必要があるが、静的に判定する事で実行時の確認を極力減らす事を目的としているらしい。

サンプルコードを用いた解説記事があるので読むと分かりやすい。 同じ配列に対して同一スコープ内で以前利用した添え字以下の添え字でのアクセスが確定している時に範囲確認を省略できる(bounds check eliminatd)というもの。 で、同じ人がベンチマークを取っていた。記事内では[]intを対象にしていたけど個人的には文字列が気になった。 go test -benchの練習も兼ねて文字列でBCEのコードを試した。

繰り返すと、さほど真面目な検証はしてないけど今回の結論としては文字列比較はシンプルな比較が最速。

Read more...

]]>
Wed, 21 Dec 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/12/18/capture_zmtp_with_wireshark.html http://blog.masu-mi.me/2016/12/18/capture_zmtp_with_wireshark.html <![CDATA[Wireshark: ZeroMQを解析する]]> Wireshark: ZeroMQを解析する

今回はZeroMQを支えるZMTPプロトコルをWiresharkでみてみる。 前回のように仮想マシン2台を立ててTCP上で PUSH/PULL する。

Read more...

]]>
Sun, 18 Dec 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/12/17/notice_db_lsp_disc.html http://blog.masu-mi.me/2016/12/17/notice_db_lsp_disc.html <![CDATA[Wireshark: DB-LSP-DISCが飛んでいる]]> Wireshark: DB-LSP-DISCが飛んでいる

Wiresharkを使ってパケットを覗いていたらDB-LSP-DISC なるプロトコルがブロードキャストされていた。

../../../_images/wireshark-db-lsp-disc.png

調べたらDropboxLAN内同期を取るプロトコルだった。 LAN内同期が不要だったので切断しておいた。本当は家のWifi接続の時だけ有効にするとかが可能だと嬉しい。

../../../_images/dropbox-setting-lansync.png

ちなみにローカルネットワークへのブロードキャスト(255.255.255.255:17500)を利用してJSONを送っていた。 ペイロードの雰囲気は下(一部を書き換えている)。

User Datagram Protocol, Src Port: 17500, Dst Port: 17500
    Source Port: 17500
    Destination Port: 17500
    Length: 149
    Checksum: 0x278a [unverified]
    [Checksum Status: Unverified]
    [Stream index: 3]
Dropbox LAN sync Discovery Protocol
    JavaScript Object Notation
        Object
            Member Key: host_int
                Number value: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                Key: host_int
            Member Key: version
                Array
                    Number value: 2
                    Number value: 0
                Key: version
            Member Key: displayname
                String value:
                Key: displayname
            Member Key: port
                Number value: 17500
                Key: port
            Member Key: namespaces
                Array
                    Number value: xxxxxxxx
                    Number value: yyyyyyyy
                Key: namespaces

Dropboxの仕様や実装を調べている人はいるAPIも公開されているので何かしたくなった時にでも思い出してみる。

]]>
Sat, 17 Dec 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/12/11/couldnt_operate_zmq_over_epgm.html http://blog.masu-mi.me/2016/12/11/couldnt_operate_zmq_over_epgm.html <![CDATA[ZeroMQ: EPGMの利用失敗]]> ZeroMQ: EPGMの利用失敗

PGMやEPGM上でZeroMQを利用するためにVagrantをなんやかんや頑張っていた。 しかし(E)PGMの利用は以下の様に失敗した。EPGMでの実行内容をメモしているがPGMも同様に失敗した。 仕方ないけど、これまでに調べた事と実施した対応や検証をメモする。

Read more...

]]>
Sun, 11 Dec 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/12/10/copying_vm_and_setting_network_in_vagrant.html http://blog.masu-mi.me/2016/12/10/copying_vm_and_setting_network_in_vagrant.html <![CDATA[Vagrant: 仮想マシンのコピーとネットワーク]]> Vagrant: 仮想マシンのコピーとネットワーク

ZeroMQで遊んでいたらPub/Subに限りトランスポートプロトコルにPGM(RFC3208)を選択できる事を知った。 PGMUDPと同じトランスポートレイヤのプロトコルで動作するマルチキャストを提供する実験的なプロトコルで、実装にはOpenPGM がある。Blackduckをみると2011年頃には開発が止まっている。 EPGMはPGMUDP埋め込んだプロトコル

PGMの利用にはマルチキャストをサポートするデバイスを使って通信する必要がある。 だがループバックデバイスはマルチキャストをサポートしていない。

ifconfig で確認している図。マルチキャストはサポートされていなかった。

ifconfig によればloデバイスはMULTICASTをサポートしない

しかし他の仮想デバイス(enp0s9, ...)はサポートしていた。 そこで現在のVMをコピーして内部ネットワーク内に2台起動している状態を作る事にした。 今の設定の時点で“public_network”を使っているため単純に2台起動するだけで仮想マシン間で通信可能になるが、別の機会に活かすためプライベートネットワークの設定も調べた。

Read more...

]]>
Sat, 10 Dec 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/11/28/elasticsearch_getting_started.html http://blog.masu-mi.me/2016/11/28/elasticsearch_getting_started.html <![CDATA[Elasticsearch メモ]]> Elasticsearch メモ

Elasticsearchを利用するにあたり勉強したり復習した事のメモ。

HTTP, TCPで検索・分析を実施できる分散検索クラスタ:

Elasticsearchは、様々なユースケースを解決する、分散型RESTful検索/分析エンジンです。予期した結果や、そうでないものまで検索できるようにデータを格納するElastic Stackの中核です。

ElasticsearchはHTTPで操作できるLuceneクラスタみたいなもの。検索としては、構造・非構造型データ・地理情報・メトリックなどを扱える。 検索以外にもAggregation, Suggestionも提供されている。

今回は後で調べやすくなるように基本的な資料のリンクをまとめて概念を整理する。その後で他のエコシステムとの繋がりや周辺ツールについて紹介する。 最後に運用上の注意事項や実際の利用の参考資料を載せる。

Read more...

]]>
Mon, 28 Nov 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/11/12/embulk_memo.html http://blog.masu-mi.me/2016/11/12/embulk_memo.html <![CDATA[Embulkを使ったメモ]]> Embulkを使ったメモ

Embulkを使った。バルクデータ転送用だけあって目的通りに使うと便利そう。 プラグインが多いのとプラグインを一般な人には書きやすそうなのが良い。でもJava, Ruby経験が浅いので、まだ慣れないけど作ることは出来た。

Embulkはバルクデータローダ:

Embulk is a open-source bulk data loader that helps data transfer between various databases, storages, file formats, and cloud services.
Embulkイメージ

Read more...

]]>
Sat, 12 Nov 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/10/23/survey_saas_monitoring_and_alerting.html http://blog.masu-mi.me/2016/10/23/survey_saas_monitoring_and_alerting.html <![CDATA[ログ・メトリック・イベントの管理・利用目的について考えて関連するSaaSを調べた]]> ログ・メトリック・イベントの管理・利用目的について考えて関連するSaaSを調べた

今回やった事は以下の3つ。

  • ログ・メトリック・イベントの保管・監視をする目的と必要な機能を整理
  • 監視にまつわるSaaSを集めて眺めた
  • 機能を比較して面白そうな事や注意した方が良さそうな事を考えてみた

Read more...

]]>
Sun, 23 Oct 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/10/02/try_diamond_influxdb_grafana.html http://blog.masu-mi.me/2016/10/02/try_diamond_influxdb_grafana.html <![CDATA[メトリクス可視化をやってみた(Diamond + InfluxDB + Grafana)]]> メトリクス可視化をやってみた(Diamond + InfluxDB + Grafana)

Diamond + InfluxDB + Grafanaでメトリックス集計した。無理やり入れた感が否めない。

今日の方針

  • 収集にはDiamondを使う
  • Diamondはvirtualenvのpython27環境にpipでインストールする
  • NginxのメトリックスもDiamondで収集する
  • InfluxDBGraphite_インタフェースを利用する
  • 可視化はGrafanaを利用する
  • Grafanaのユーザー管理はGithub OAuthを利用する

Read more...

]]>
Sun, 02 Oct 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/09/19/install_cowrie_on_centos6.html http://blog.masu-mi.me/2016/09/19/install_cowrie_on_centos6.html <![CDATA[CowrieをCentOS6で動かしてみた]]> CowrieをCentOS6で動かしてみた

SSHのHoneypotであるCowrieをCentOS 6で動かしてログを確認するところまでやってみた。

ハニーポットは実際にサイバー攻撃を受けたり悪性サイトにアクセスして攻撃情報を収集する。

元々は前者を指す言葉だけど、最近は巡回型とかクライアント型とか呼ばれるタイプもあるみたい。とりあえず従来のハニーポットを試した。

Read more...

]]>
Mon, 19 Sep 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/09/15/rabbitmq_clustering_mirroring_config.html http://blog.masu-mi.me/2016/09/15/rabbitmq_clustering_mirroring_config.html <![CDATA[RabbitMQ設定 (クラスタリング, ミラーリング)]]> RabbitMQ設定 (クラスタリング, ミラーリング)

RabbitMQ では環境変数・設定ファイル・ランタイムパラメタとポリシーの3つの経路で設定される。 以下の2つについては設定ファイルと相性が悪い。

  • クラスタ内のノード全体で共有すべき事
  • 実行時に動的に変化しがちな内容

これらの項目をRabbitMQではパラメターと呼びrabbitmqctlコマンドやmanagement pluginのHTTP API経由で操作する

Read more...

]]>
Thu, 15 Sep 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/08/28/start_rabbitmq.html http://blog.masu-mi.me/2016/08/28/start_rabbitmq.html <![CDATA[RabbitMQ 利用開始]]> RabbitMQ 利用開始

RabbitMQを使う時にだいたい忘れてしまうので次こそはスムースに利用できるように再びメモを残す。

Read more...

]]>
Sun, 28 Aug 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/08/07/install_peda.html http://blog.masu-mi.me/2016/08/07/install_peda.html <![CDATA[pedaを導入した]]> pedaを導入した

タイトル通りにpedaを導入した。gdbが豪華になるって目的だ。

peda 導入時のgdb起動結果

Exploitの開発サポートも入るし色々と解析に便利なコマンドも追加される。 とりあえずbt(backtrace) でmainの外側も表示してくれる。 また今回導入するにあたり.gdbinitにgdb初期化処理を書ける事を知った。

gdb拡張はpythonで作れるのでELFの知識強化の材料として勉強するのが良い気がした。

]]>
Sun, 07 Aug 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/08/04/storage_applications.html http://blog.masu-mi.me/2016/08/04/storage_applications.html <![CDATA[ストレージ関係のツールとか眺めてた]]> ストレージ関係のツールとか眺めてた

最近はデータ保存の観点で調べてみたり考えてみたりする事が増えてきた。 Storage Weekly で出てきたデータ保持・配信系ミドルウェアやツールを中心に調べてみた。

ストレージ・データベース・オーケストレーション・コンフィギュレーションは網羅的に探したくなるので今度に回す。 BlockChain もストレージやコンテンツ配信系に意外と応用されていたけど、アルゴリズムから押さえたいので勉強してから別途まとめる。

ユーザーデータは、4K・全天球画像・3Dモデルみたいに巨大化する方向とセンシングデータみたいに大量な小さい時系列データの方向が特に増加すると思ってる。

システムデータは今まで通り、リポジトリ・ログ・メトリクス・コンテンツ配信・アーカイブが主軸だけれど、 リポジトリはマシンイメージ・Dockerイメージ・DCOSパッケージが増えていきそう。またコンテンツ配信で学習モデルも加わる気がする。

Read more...

]]>
Thu, 04 Aug 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/07/03/doclist_aftereffect.html http://blog.masu-mi.me/2016/07/03/doclist_aftereffect.html <![CDATA[AfterEffect 資料]]> AfterEffect 資料

最近は結婚式準備で時間がなかなか取れていない。

ELF・SQLite・AmbryHaystack ・カーネルソースへの興味を消化しきれないまま AfterEffect を使ってオープニングムービー、プロフィールムービーを作ってる。

AfterEffect はシーンを組み合わせてムービーを作るものではないし、動画形式を整えるものでもないし、まして物理メディアに焼き付けるものでもない。 動画や画像を組み合わせて特殊効果を実現したりするものだ。 なのでAfterEffect を結婚式ムービーに使うのはオーバースペックな上に目的を取り違えている。

ただ使ってみたら簡単にVFXを作れたりと趣味として楽しかった。わくわくする。 ただ顧客と締め切りがあると仕事感が出てきて単純に楽しむだけでは済まなくなってしまうのは悲しいものだ。(まだ全然、終わっていない)

とりあえず目を通すと良さそうな資料を記録しておく。

]]>
Sun, 03 Jul 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/06/04/desing_of_sqlite4.html http://blog.masu-mi.me/2016/06/04/desing_of_sqlite4.html <![CDATA[SQLite4が現れた!]]> SQLite4が現れた!

SQLite3の勉強を放置しているうちにSQLite4が出ていた。 なので今回はThe Design Of SQLite4の超訳(すっとばし)と補足を書く。

SQLite3を読んでSQLiteは標準のB-Treeを基盤に仮想テーブルを使って色々なデータ構造をSQLで糊付けする抽象化層ライブラリってイメージを持っていた。 SQLite4は各コンポーネントの責任範囲を明確にして全体を単純に扱えるようにしている印象を受けた。 例えば、 プラガブルなストレージエンジンは、データモデル(トランザクション・データ構造)をデータベース全体で統一させている。 これはテーブル単位でのデータ構造切り替え(仮想テーブル)よりも単純化されていて扱いやすそうに思えた。 また、実行環境オブジェクトは複数のDB接続をユーザー側で明示的に管理しないといけなくしている。

参考資料のリンクを残す

Read more...

]]>
Sat, 04 Jun 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/29/bad_const.html http://blog.masu-mi.me/2016/05/29/bad_const.html <![CDATA[ダメな定数]]> ダメな定数

恥を晒しておく。最近、馬鹿な定数を定義してしまった。

定数化によって、マジックナンバー・リテラルを減らすことの目的には、コード修正時の変更箇所を減らしたりコンパイラに検証を任せられる様にすることが含まれる。 またフォーマット文字列の場合は、書式指定子と後続の引数の間で意味的な関係があり切り離すと関連を追い辛く変更箇所が増えてしまう。

そのため、だいたいの場合でフォーマット文字列は定数にせずにプロシージャに閉じ込める方が良い。

良い歳して考えずに定数化した自分が恥ずかしい。。

const format = "%s/%s/%s/hoge"

func Main() {
  fmt.Sprintf(format, "name", "number", "book")
  // ...
  // ...
  fmt.Sprintf(format, "name2", "number2", "book2")
}
]]>
Sun, 29 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/14/nm_in_go.html http://blog.masu-mi.me/2016/05/14/nm_in_go.html <![CDATA[go tool nm vs nm]]> go tool nm vs nm

go tool にnmがある。 Linuxだとnmコマンドがあるからメリット薄いけどOSX,Win でも同様に機能して嬉しい。 OSXのotoolはいろいろな機能が統合されててオプション調べるのが辛い。

$ uname -a
Darwin protrout.local 14.5.0 Darwin Kernel Version 14.5.0: Mon Jan 11 18:48:35 PST 2016; root:xnu-2782.50.2~1/RELEASE_X86_64 x86_64
$ go tool nm `which ls`

EFLで使った感じでは基本機能は同じ。当たり前だけどnmコマンドの方がオプションが多くて柔軟に使える。

]]>
Sat, 14 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/10/review_of_investigate_pre_main.html http://blog.masu-mi.me/2016/05/10/review_of_investigate_pre_main.html <![CDATA[[復習]main にたどり着く前を追ってみた]]> [復習]main にたどり着く前を追ってみた

先日、mainに至るまで追ってみたが幾つか疑問を残していた。

  • mainからのバックトレースで外側が見えないのは何故か?
  • __libc_start_main のdisassembleとobjdumpの結果が異なる

詳細にmainまでの挙動を解説しているページがあった。 読んだり他を調べた中で印象に残った部分を記録する。資料も最後にまとめておく。

ただし依然mainからの復帰後にバックトレースが表示できる理由がわからないまま。

関心ごと

ELFのインタプリタはld-linux.so

man execveを読めってことでした。

実行ファイルが動的リンクされた a.out 実行形式で、共有ライブラリの スタブを含むものだった場合、実行の開始時に Linux の ダイナミックリンカー ld.so(8) が呼び出され、必要な共有ライブラリをメモリーに読み込んでリンクを行う。

実行ファイルがダイナミックリンクされた ELF 実行形式だった場合、 PT_INTERP セグメントに指定されたインタープリターが必要な 共有ライブラリ (shared library) を読み込むのに使用される。 通常、インタープリターは glibc をリンクしたバイナリでは /lib/ld-linux.so.2 である。

__libc_start_main は動的にロードされる

そのため開始前にはアドレスが決まらない。 言及しているエントリがあった。 そのまえに、nmでシンボルを確認しろよって話でした。

$ nm ./a.out  | grep __libc_start_main
                 U __libc_start_main@@GLIBC_2.2.5

main の呼び出し箇所の確認

解説記事と異なりx86_64環境だけど確認してみた。 __libc_start_mainの最初の引数が main へのポインタになってた。ただ pushじゃなくて%rdiを使っている。

(gdb) x/10i $rip
=> 0x400409 <_start+9>: and    $0xfffffffffffffff0,%rsp
   0x40040d <_start+13>:        push   %rax
   0x40040e <_start+14>:        push   %rsp
   0x40040f <_start+15>:        mov    $0x400570,%r8
   0x400416 <_start+22>:        mov    $0x400500,%rcx
   0x40041d <_start+29>:        mov    $0x4004f0,%rdi
   0x400424 <_start+36>:        callq  0x4003e0 <__libc_start_main@plt>
   0x400429 <_start+41>:        hlt
   0x40042a <_start+42>:        xchg   %ax,%ax
   0x40042c <_start+44>:        nopl   0x0(%rax)
(gdb) x/i 0x4004f0
   0x4004f0 <main>:     push   %rbp

main関数から外はバックトレースで見えない

この記事で main に入るときはフレームポインタ(%ebp)をスタックに積むなどの事前処理を行わないためmainの内外が分離されることが書かれてた。

スタックに呼び元の情報が記録されないのだとすると%rbp, %rspがどう修復されるのかわからない。 ちゃんとStack layoutやret命令がどう動くか確認する必要がありそう。

return address of mainmain呼び出し前の%ripに対応しret命令で復帰するので実行に問題はない。 だけどmainの外側に戻って即座にバックトレースが取得できることは解せない。

]]>
Tue, 10 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/09/go_build_tags.html http://blog.masu-mi.me/2016/05/09/go_build_tags.html <![CDATA[debug aid in Go]]> debug aid in Go

GoでアサーションやDebug aidを行いたい。

例えば開発時はアサート失敗でpanicさせ気付ける様にしておき、リリースは完全にコードが消えていて欲しい。 そういう時は、ビルドオプションtagsを使いビルドを分岐させる事になる。

マクロ・プリプロセスがあればリリースビルドからデバッグ用コードを簡単に消せるけど、Goにはその様な機能はない。 そのためソースコード上にデバッグ用コードが残る。これが最適化で消されるかを確認した。

tl;dr

以下が判明したためGo言語でも積極的に Assertion, debugaidを利用した開発ができる。 特に定数+条件分岐を使うとリリースビルドから痕跡を完全に消せる。 ただしコミュニティにベタープラクティスとして受け入れられているかは不明。

  • 空の関数は実行バイナリから消える(引数での式の評価は実行される)
  • 定数 + 条件分岐の判定部分は消える
$ uname -a
Linux pit 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
$ go version
go version go1.5.1 linux/amd64

Read more...

]]>
Mon, 09 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/08/entrypoint_of_go.html http://blog.masu-mi.me/2016/05/08/entrypoint_of_go.html <![CDATA[Goバイナリのエントリポイント]]> Goバイナリのエントリポイント

goでは_startではなく_rt0_amd64_linuxがエントリポイントになっていた。

詳細

試しに下のHelloworld(sample.go)を準備する。

package main

import "fmt"

func main() {
    fmt.Println("Hello world")
}

以下を実行して確認した。

$ go build ./sample.go

$ readelf -e ./sample| grep 'Entry point address'
  Entry point address:               0x456130

$ objdump -f ./sample
./sample:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000456130

$ nm ./sample| grep 0456130
0000000000456130 T _rt0_amd64_linux
]]>
Sun, 08 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/08/require_syscall_exit.html http://blog.masu-mi.me/2016/05/08/require_syscall_exit.html <![CDATA[システムコール(_exit(2))が要求される]]> システムコール(_exit(2))が要求される

main()を直接読んでもダメだった理由はシステムコール_exit()が呼ばれていないからとの事だった。 そこで上記ブログを参考にエントリポイントをmainにしたELFバイナリでセグフォらない用にした。 完全にコピペ記事である。

システムコール _exitを直接呼ぶ部分は最初のブログを真似して書いた。 自分の環境では/usr/include/asm/ 配下に_syscall1 なるマクロが存在しなかったため不安だったが普通に動いた。 システムコールを直接呼び出す方法やらは調べたほうがよさそう。

int errno;
void _exit(int status) {
  long __res;

  __asm__ volatile ("int $0x80" :  \
                    "=a" (__res) : \
                    "0" (1), "b" ((long)(status)) : \
                    "memory");
  do {
    if ((unsigned long) (__res) >= (unsigned long)(-(128 + 1))) {
      errno = -(__res); __res = -1;
   }
  return (void) (__res);
 } while (0);
}

int main() {
  _exit(100);
  return 123;
}

上記のコードを用いて以下を実行する事で目当ての実行バイナリで実行する。

$ gcc -Wall -fno-builtin -c ./sample.c
$ ld -e main -o main.sample ./sample.o
$ ./main.sample; echo $?
100
]]>
Sun, 08 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/05/07/investigate_pre_main.html http://blog.masu-mi.me/2016/05/07/investigate_pre_main.html <![CDATA[main にたどり着く前を追ってみた]]> main にたどり着く前を追ってみた

結婚式準備の気分転換とgdbの練習のために、mainにたどり着くまでの動きを追ってみた。

GCCでは以下の関数を設定するとmainに入る前に実行される。

__attribute__((constructor)) void constructor(){
  printf("constructor\n");
}

Linux環境のバイナリはELF形式が一般的で、ELFでは_startデフォルトのエントリポイントになる

今回の整理

だいたい下の事がわかったが、main の中でバックトレースを確認しても_start などが表示されない理由がわからなかった。

  • ELFファイルのデフォルトエントリポイントは _start
  • _start/usr/lib64/crt1.o 由来
  • OSX はELFファイルでなく _start がリンク時に衝突する事はない
  • GCC拡張のconstructor__libc_csu_init() からcallされる
  • main__libc_start_main() からcall される
  • ELFのエントリポイントは変更可能だが後処理の自作が必要になる

一応main 外部がバックトレースで表示されない理由は下が考えられる。

  • スタック積み上げ動作が異なり呼び元の情報が不完全になる
  • gdb が気を効かせてmain以降を遡らない

とりあえず切り分けるには手作業でESP, EBP を追いmainから__libc_csu_init, _startに辿り着けるか確認すれば良い。 そしてgdbの優しさの疑いが高まった場合に、ソースコードを読みに行けば解決しそう。 ヘタレとしては面倒くさくなりそうな気がする。

Read more...

]]>
Sat, 07 May 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/04/02/deal_with_demand.html http://blog.masu-mi.me/2016/04/02/deal_with_demand.html <![CDATA[要求に条件反射しない]]> 要求に条件反射しない

主に要求に関わる文章の批判が下手でコミュニケーションで不便を感じたので要求を批判するに気づく様に少し整理する。

もともと要求を批判対象として気付ければ問題ないので焦って考えられずにジャッジしないように手前に焦点をあてる。

文書の意図と位置づけを確認する

文章の意図を確認すると要求に対して動きやすくなる。また他の知識体系に関わる主張なども一般化に向けて開けているか確認しやすい。

意図は目的・背景・経緯とかで位置付けってのは、関連した他の文書や事実などを指す。

書かれている内容を批判する

文章の意図を確認すると要求に対して動きやすくなる。また他の知識体系に関わる主張なども一般化に向けて開けているか確認しやすい。

読む側としては何するかというと「しっくりくる」状態まで批判・認識の調整を繰り返す。 具体的には下の4つが思いついた。

  • 主張の分類
    だいたい次の4つに分けると対応の取り方が決まる

    知識・価値・規範・要求

  • 論理の確認
    だいたい下が使われる

    演繹・仮説検証・推測(演繹・アブダクション)

    用途や対象とする領域や要求される確度・精度を勘案して適切か判断する

  • 根拠の確認
    下のどれかを論理で組み合わせて主張にしている

    前提・事実・主張

    それぞれ受け入れられるか? 適切か? を確認する

  • 語彙の確認

    使われている語彙の意味定義がどうなっているか確認する 特に意味定義が提示される場合、社会と文書の関わり方に着目すると下の3つ

    確認・限定・提案

    意味定義の方式で分類すると素朴には下が思いつく

    内包・外延

書かれていない事との関係を考慮に入れる

他の事実や規範との整合性や意図が真っ当かなどの判断を行う。

要求・規範の主張時には、とりあえず何がどう変化するか?メリデメはどうなるか必ず検討する。 要求が選択式の提案の場合、各選択肢に加えて受け入れない事についても行う。また他の選択肢はないかも考える。

何がどう変化するか? の洗い方だけど一般的な事を雑に書くとしたみたいな感じ。 この辺は勘や経験を使って出して批判を通して磨くループを回すに限る。 ただカップ麺みたいに素早くしたい事もあるしでEvernoteとかにメモして時々見返して更新すると良さそう。

  1. 相手・自分を含むステークホルダを出す
  2. 責任を書き出す
  3. 今後の責任範囲を確認する
  4. 要求に支払うコストを出す
  5. 要求から得られるリターンを出す
  6. 見えているリスクを出す

最後に上記でできた意見を文書に起こして反論を受けられる形で伝える

普通に論理的な文章を書いたら挨拶と連絡先を付けて返信しましょう。 口頭でやるのも流れはだいたい同じ。

]]>
Sat, 02 Apr 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/04/02/reading_sqlite_binarycode.html http://blog.masu-mi.me/2016/04/02/reading_sqlite_binarycode.html <![CDATA[SQLiteバイトコードを追う]]> SQLiteバイトコードを追う

SQLiteではレジスタ型仮想マシンのバイト命令がBTreeを操作している。 またバイトコード生成はLALR(1)構文解析器の(cmd)非終端記号の還元時(reduce)に生成されていた。

仮想マシンは仮想データベースエンジン(VDBE)と呼ばれておりBTreeコンポーネントを操作する。 今回はバイトコード実行時のVDBEの挙動を調べる。

命令(OpCode)や変数が多くて辛いため、簡単なSQLを実際に追いながら命令や変数を説明する形で進める。

Read more...

]]>
Sat, 02 Apr 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/02/21/look_for_part_generating_opcode_in_sqlite.html http://blog.masu-mi.me/2016/02/21/look_for_part_generating_opcode_in_sqlite.html <![CDATA[SQLite コードジェネレート箇所を探した]]> SQLite コードジェネレート箇所を探した

sqlite3_prepare_v2 でプリペアドステートメント(バイトコード)が生成されている。 バイトコードの生成過程を調べた。

tl;dr

振り返ると普通のコード生成だった。

  • プリペアドステートメントはsqlite3_prepare_v2 で生成される
  • パースはLALR(1)構文解析器が利用される
  • 構文解析器ジェネレーターはLemonを用いている
  • 構文解析は sqlite3Parser にトークンを渡す形で実行される
  • cmd 非終端記号の還元時にバイトコードは生成される
  • 他の非終端記号の還元時は中間情報をノードに格納する
  • OpCodeはBTreeを操作する命令になっている

詳細

sqlite3_prepare_v2

sqlite3_prepare_v2sqlite3Prepare (in prepare.c)を呼びプリペアドステートメントを取得する。 その中ではsqlite3RunParser(in token.c) を通して構文解析器が呼ばれている。

sqlite3Prepareは大雑把に以下の様な流れでバイトコード格納場所(sqlite3_stmt* ppStmt)へ作成されたバイトコード(pParse->pVdbe)を代入している。 EXPLAIN 用の処理はバイトコードを表示しているのでsqlite3RunParserの中でバイトコード生成をしている事が予想される。

## いろいろな事前処理
sqlite3RunParser(pParse, zSql, &zErrMsg);
#ifdef SQLITE_OMIT_EXPLAIN
# ... なんかEXPLAINっぽい事
#endif
*ppStmt = (sqlite3_stmt*)pParse->pVdbe;

sqlite3RunParser

sqlite3RunParser は構文解析器を駆動する。

lemen 構文解析器ジェネレータで生成されているのでサンプルと基本的な流れは同じsqlite3GetToken でトークンを取得しsqlite3Parser(in parse.c, sqliteInt.h)に渡している。

気になった事は

  • 最後に 0 でParserを呼び出す理由がわからない
  • パーサーに任さずにToken種別で分岐する理由がわからない
pEngine = sqlite3ParserAlloc(...)
while( !db->mallocFailed && zSql[i]!=0 ) {
    pParse->sLastToken.z = &zSql[i];
    pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
    switch (tokenType) {
    default:
        sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse)
    }
}
if( lastTokenParsed!=TK_SEMI ){
    sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
    pParse->zTail = &zSql[i];
} else {
    sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
sqlite3ParserFree(pEngine, sqlite3_free);

sqlite3GetTokenは典型的な字句解析器で特に変わったところはない。

sqlite3Parser はLR系のためシフト・還元の繰返しで実装されている。 yy_find_shift_actionで状態マシンが次に取るアクションナンバーが返却される。 アクションナンバーによりシフト(yy_shift)・還元(yy_reduce)を行う。

バイトコード生成箇所

yy_reducecmdに還元する際にアクションとしてバイトコードが生成される。 バイトコード生成関数はpVdbe を操作する事でコードを格納している。 この様な関数はbuild.c, select.cといったソース内に記述されている。 cmd以外の還元アクションで中間情報を記録している。parse.yでコード生成は理解できる。

  • ASTの各ノードは種別ごとに別の型を使う
  • cmd の還元時にコード生成を行う
  • 他の非終端記号の還元時には親ノードで利用する情報をノードに格納する

例えば、SQL関数の実行に関係しそうな部分(状態番号196, 197)では、sqlite3ExprFunctionが呼ばれてpExprに値が格納されたりしている。 OpCode はBTreeを操作する命令で構成されている。BTreeのインタフェースを確認してEXPLAINを使えば概要を掴める。

具体例) SELECT 文の場合

{
    SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
    sqlite3Select(pParse, yymsp[0].minor.yy3, &dest);
    sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
}
]]>
Sun, 21 Feb 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/02/09/create_sqlite3_ext_sample.html http://blog.masu-mi.me/2016/02/09/create_sqlite3_ext_sample.html <![CDATA[SQLiteを使ってみる]]> SQLiteを使ってみる

普通にDBの利用を行える様にする。拡張モジュールを作れるようになる。 拡張モジュールロード、ユーザーSQL関数の登録のコードを少し追う。

Read more...

]]>
Tue, 09 Feb 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/02/07/sqlite3_detail_reading.html http://blog.masu-mi.me/2016/02/07/sqlite3_detail_reading.html <![CDATA[SQLite を読んで再入門]]> SQLite を読んで再入門

前回、勢いでデバッガから入ったけど、このままでは整理されないので全体を把握したりインタフェースを確認したりした。

思ったのは提供されている以上、公式のIntroduction, Tutorial, Architecture, C/C++ Interfaceは最初に目を通した方が早い。 ちょっと無理やり進めた感が出てしまうし無駄が大幅に増えた。上を押さえてこそ解析する価値が出る。

アーキテクチャ要点メモ

アーキテクチャ の内容をメモする。

アーキテクチャ

Read more...

]]>
Sun, 07 Feb 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/02/05/order_of_evaluation_in_go.html http://blog.masu-mi.me/2016/02/05/order_of_evaluation_in_go.html <![CDATA[Golang の評価順序]]> Golang の評価順序

tl;dr

どんな言語でも評価順序は注意するべきだし評価順序が気になるコードは書かないように気をつけるべき。 golangの評価順序は定められていて、オペランド, 代入, 関数, メソッド, 通信は左から評価される。 変数の値は上記の評価とは別に評価される。 どのみち1行内で副作用を伴う関数・メソッドや通信は避けたほうが良い。

Read more...

]]>
Fri, 05 Feb 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/01/10/introduction_sqlite.html http://blog.masu-mi.me/2016/01/10/introduction_sqlite.html <![CDATA[Sqlite入門]]> Sqlite入門

SQLite 入門してみた。

気になった関数メモ

気になった主要な関数を羅列する。

sqlite3_exec
DBとSQL文を受け取って実行する。shell_exec も同様にDBに対してSQLを実行する。ただしcallback が異なるとコメントに書かれていた。
shell_callback
シェルに向けて表示している。p->modeで表示モードを切り分けている。 だいぶいろいろなモード(Line, Explain, Column, Semi, List, Html, Tcl, Csv, Insert, Ascii)が存在する。
sqlite3Prepare
UTF-8で書かれたSQL文を実行ハンドラにコンパイルしている。
process_input
コマンド群の入力を受け付けている。特にone_input_line が1行文のコマンド入力を受け取っている。 そのためprocess_input ではINTERACTIVEモードでプロンプトを出し分けたりエラーハンドリングを特別あつかいするための処理を行ったりしていた。
do_meta_command
”.load” など”.” で始まるコマンドの実行を担っていた。
sqlite3RegisterGlobalFunctions
SQLで使われる関数を登録する。 関数には色々(FUNCTION, FUNCTION2, VFUNCTION, DFUNCTION, AGGREGATE, ..)な種類が色々ある。 sqlite3.c:11947 から各種定義と説明を読める。

Read more...

]]>
Sun, 10 Jan 2016 00:00:00 +0900
http://blog.masu-mi.me/2016/01/03/approach_to_thinking.html http://blog.masu-mi.me/2016/01/03/approach_to_thinking.html <![CDATA[Approach to thinking!!]]> Approach to thinking!!

友人が論述試験が苦手だと話していたので、知的活動について言及しているような資料を紹介してみる事にした。 そして「こんな本あったなぁ。どんなだったか思い返したりしたいなぁ」って時に探しやすい様にする目的もある。 なので身につける程しっかり読み込んではいないので詳細は忘れてたりする。

注意としては、論理不備や誤植が多いかったと記憶している資料も載せているので、当然だけど鵜呑みにして良いわけではない。 また個人的な見解はあまり書かない様にしているが中途半端に漏れているところもあります。ゴメンなさい。

作図や可視化については漏れた。この辺は勉強が足りないので整った時にでもいずれ出来たらと思う。 また知の3部作(知の技法, 知の論理, 知のモラル)など重めのものや学問を中心に目を向けているものは外した(教養が足りず位置づけが上手く出来なかった)。

Read more...

]]>
Sun, 03 Jan 2016 00:00:00 +0900
http://blog.masu-mi.me/2015/12/31/survey_of_aws.html http://blog.masu-mi.me/2015/12/31/survey_of_aws.html <![CDATA[AWS プロダクトを眺めた]]> AWS プロダクトを眺めた

AWS を調べた。彼らがどうゆうアーキテクチャ設計・開発プロセスを提案しているか想像しておきたかった。 今回は試しに提供サービスを目的別に並べてみた。ただし上手く分類できなかったり調査が足りない事もあり先に全体の感想とメモを書く。試みた分類は最後に残しておく。

全体を通じての感想

Read more...

]]>
Thu, 31 Dec 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/12/12/cpu_status.html http://blog.masu-mi.me/2015/12/12/cpu_status.html <![CDATA[CPUスペック確認]]> CPUスペック確認

CPU を確認したかったのに方法を忘れてたのでメモする。

lscpu コマンドがある場合はそれが見易い。ない場合は下を/proc/cpuinfo を読んで判断する。

lscpu

[vagrant@pit(10.0.2.2) ~]$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 61
Model name:            Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz
Stepping:              4
CPU MHz:               3152.272
BogoMIPS:              6304.54
L1d cache:             32K
L1d cache:             32K
L2d cache:             6144K
NUMA node0 CPU(s):     0

cat /proc/cpuinfo

この方法だとL1d cache が読めなさそう。

processor OSから見えるCPUのid
siblings CPUの外から見えるコア数
core cores CPUの中にある物理的コア数(HTが有効だとsiblingと差が出る)
pysical id 物理的なCPUのID(マザーボード上にあるCPU毎に振られる)
model name CPUのモデル名
[vagrant@pit(10.0.2.2) ~]$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 61
model name      : Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz
stepping        : 4
microcode       : 0x19
cpu MHz         : 3152.272
cache size      : 6144 KB
physical id     : 0
siblings        : 1
core id         : 0
cpu cores       : 1
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc rep_good nopl pni monitor ssse3 lahf_lm
bogomips        : 6304.54
clflush size    : 64
cache_alignment : 64
address sizes   : 39 bits physical, 48 bits virtual
power management:
]]>
Sat, 12 Dec 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/11/24/read_introduction_thrift.html http://blog.masu-mi.me/2015/11/24/read_introduction_thrift.html <![CDATA[今更 Thrift を触ってみました]]> 今更 Thrift を触ってみました

GoでThrift を試した。Thrift 自体が初めてだったがチュートリアル・サンプルが準備されていて簡単に利用できた。

はじめに感想を述べる。その後に読んだ資料・チュートリアルに関するメモなどを載せる。 最後にチュートリアルとThrift Architecture の対応を確認する。

tl;dr

Thrift はRCPを提供するミドルウェア だ。 (複数言語間を繋げる目的があり複雑なデータ構造を渡す事は考えられていない。また参照渡しなどRPCの難しい問題は避けている感じがある。) Thfift で責任を持つのはISO参照モデルで捉えるとプレゼンテーション層・セッション層になる。 この2層はThrift Architecture ではTProtocol, TTransport に当てはまりコンポーネントを差し替えられる様になっている。

Thrift Architecture

気になった事

  • TTransport でフレーミング実装がありTCPハンドシェイクを減らせる

  • 公式Goライブラリでノンブロッキングサーバーがサポートされてない
    • 1コネクション内で処理を多重化するのは難しい
    • goroutine で対応できる可能性はある
  • 負荷分散してくれるクライアント実装を探す必要がある
    • VIPによる負荷分散はワークロードで分散できず、フレーミング利用時に注意が必要
  • 言語間の差異を吸収し辛い機能はサポートされていない
    • 構造体継承, ポリモーフィズム, オーバーロード, heterogeneous containers, Null return
    • 参照渡し, unsigned int

チュートリアルを試す

インストール

チュートリアルみたいにwget などソースからやるのが面倒なので linuxbrew のお世話になる。

$ brew install thrift
$ go get git.apache.org/thrift.git/lib/go/thrift

コードジェネレート

GOPATH 配下では相対パスを利用できない事と、tutorial, shared 間で相対パスを一律で与える事が難しいため以下の様に生成するコード配置を意識して pacakge_prefix を与える必要がある。

$ thrift -o ./pkg/ --gen go:package_prefix=github.com/masu-mi/test/pkg/gen-go/ shared.thrift
$ thrift -o ./pkg/ --gen go:package_prefix=github.com/masu-mi/test/pkg/gen-go/ tutorial.thrift

チュートリアルのコードを取ってくる

go サンプル から取ってこれる。

実際に走らせる

$ go build .
$ nohup ./test -server &
$ ./test

チュートリアルコードの説明

Thrift network stack がプロトコルスタックがわかる。 4レイヤーで構成される。

Server 下位コンポーネントの管理を行う
Processor 通信のInput/Outputのやりとりを担当する
Protocol データのシリアライズなどを行う
Transport 下位レイヤ通信(TCPなど) を隠蔽する

このうちProcessor 部分がIDLにより生成され、実処理を行うハンドラをプログラマーが実装する。 他のレイヤーはThfirt ライブラリに含まれているのを利用する。コンポーネントは差し替えられるようになっている。 同様の図はチュートリアルにもあったが少しイメージが違うので気にかかる。

Thrift Architecture

チュートリアルとの対応

server定義箇所

server.go にある。抜粋すると以下な感じのコードになっている。

func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error {
  transport, _ = thrift.NewTServerSocket(addr)
  handler := NewCalculatorHandler()
  processor := tutorial.NewCalculatorProcessor(handler)

  server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)
  server.Serve()
}

アドレスを元にソケットを作成している(NewTServerSocket)。 次にコードジェネレートしたNewCalculatorProcessor() に自作したハンドラを渡してプロセッサを完成させる。 最後にNewTSimpleServer4() に上記2つとtransportFactory, protocolFactory を渡しサーバーを完成させServe メソッドでホスティングを完了している。 transportFactory, protocolFactory はアーキテクチャで出てきた2レイヤに対応している。この部分は外部から与えているように差し替え可能。 チュートリアルのmain.go からどう使うかは判断できる。

Protocol, Transport の設定方法

チュートリアルではオプションによりProtocol が変えられるように書かれている同じくTransport も変えられる。 当然だけどClient, Serverの両方で同じProtocol, Transport を利用しないと上手く機能しない。

Transportにはフレーミングをサポートしたもの(TFramedTransport)が存在し別のTTransportFactory を受け取り機能するようになっている。 フレーミングでコネクションを使い回す実装はハンドシェイクを避けられるため効率良さそうに思える。

しかし負荷分散は考えにくくなる。L3DSRなどVIP構成を行うとコネクション単位で分散できるが実際のワークロードで分散が簡単には出来ない。 そのため複数サーバーに分散するクライアント実装があるかは調べたい。

またフレーミングをTransportで採用してもTNonblockingServer が公式(git.apache.org/thrift.git/lib/go/thrift)には見当たらない。 そのためgolanlg でサーバー実装するとフレーミングを活かせなさそう。 ただメンテされていない google code内のthrift-go には TNonblockingServer が存在する。 読んでみると以下の様にgoroutine を使うか否かの違いだけなので検証して問題がなければ公式にパッチを送るのを検討しても良さそう。

]]>
Tue, 24 Nov 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/11/07/my_first_pr_in_public.html http://blog.masu-mi.me/2015/11/07/my_first_pr_in_public.html <![CDATA[Minio にpull request を出してみた]]> Minio にpull request を出してみた

horie くんに煽られたのでMinioPRを出しました 。 URLルーティングでの trailing-slash の扱いをS3互換にした。

]]>
Sat, 07 Nov 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/11/01/find_minio_xl.html http://blog.masu-mi.me/2015/11/01/find_minio_xl.html <![CDATA[PB級なのはminio-xl だった]]> PB級なのはminio-xl だった

Minio にはDonutがないと書いたけど、どうやら Minio には2系統ありPetaByte級のスケールを目指しているのは Minio-XL の様子。 まだだいぶコードが相互に依存している状態で読みにくいが棲み分けがある事が分かったので記録しておく。 また、DonutというコンポーネントはすでにXLにrenameされていた

そんな訳で Minio-XL を読んでみようと思った。次に読みたい部分は主にストレージ管理を行うXL 周辺とV4署名の実装、そしてACL・Policyの実装あたり。

]]>
Sun, 01 Nov 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/29/go_url_escaped_path.html http://blog.masu-mi.me/2015/10/29/go_url_escaped_path.html <![CDATA[Go1.5.x から URL.RawPath が追加]]> Go1.5.x から URL.RawPath が追加

Goがv1.5(.1?) になりWebサーバーで undecodedなURLのpathを取得する定番の方法が決まったのでメモしておく。 解決策は URL.EscapedPath() を使う事。また確認した所ではURL.RequestURI() の挙動にも変更が加えられており、これでも解決してしまう。

背景

少し前はWebサーバーを書く時Undecodedなリクエストパスを取得したくなると少し困っていた。 以下の様にリクエストパスを得るがv1.4.3 以前では後述する問題があった。

func sampleHandler(w http.ResponseWriter, r * http.Request) {
  fmt.Fprintf(w, "r.RequestURI:%s\n", r.RequestURI)
  fmt.Fprintf(w, "r.URL.RequestURI():%s\n", r.URL.RequestURI())
  // fmt.Fprintf(w, "r.URL.RawPath:%s\n", r.URL.RawPath)
  // fmt.Fprintf(w, "r.URL.EscapedPath():%s\n", r.URL.EscapedPath())
}
func main() {
  http.HandleFunc("/", sampleHandler)
  http.ListenAndServe(":18080", nil)
}

v1.4.3の時の挙動

r.RequestURI はリクエスト内容が直接出力されるが、absolute-formrequest-target に使われているとスキーマなどが含まれて扱いにくい。 URL.RequestURI() はGoがエンコードした内容が含まれる。そのため%24 で転送された部分が$ として残る事になる。

$ export GOROOT=${HOME}/go1.4/
$ ~/go1.4/bin/go run ./main.go &
$ telnet localhost 18080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 13:46:11 GMT
Content-Length: 66
Content-Type: text/plain; charset=utf-8

r.RequestURI:/test_%24host%20$
r.URL.RequestURI():/test_$host%20$
GET http://localhost/test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 13:46:40 GMT
Content-Length: 82
Content-Type: text/plain; charset=utf-8

r.RequestURI:http://localhost/test_%24host%20$
r.URL.RequestURI():/test_$host%20$
^C
Connection closed by foreign host.

v1.5.1の時の挙動

r.RequestURI の挙動は変わらない。変わったのはURL.RequestURI() だ。

URL.RequestURI() はリクエストされたrequest-target が妥当な内容の場合、該当リクエストのパス部分を返す。 これはリクエストから取られGoが再エンコードする訳ではない。さらにabsolute-form であってもパス部分が取得できる。 ただし、この変更が正しいのかわからない。

困っていた内容を解決する意図のURL.EscapedPath() が追加されていた。 これを使うのが良さそう。

とにかく、これで解決した。やったぜ。

$ telnet localhost 18080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 14:18:40 GMT
Content-Length: 68
Content-Type: text/plain; charset=utf-8

r.RequestURI:/test_%24host%20$
r.URL.RequestURI():/test_%24host%20$
GET http://localhost/test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 14:19:03 GMT
Content-Length: 84
Content-Type: text/plain; charset=utf-8

r.RequestURI:http://localhost/test_%24host%20$
r.URL.RequestURI():/test_%24host%20$
^C
Connection closed by foreign host.
]]>
Thu, 29 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/28/minio_routers.html http://blog.masu-mi.me/2015/10/28/minio_routers.html <![CDATA[minioのroutersがtrailing-slash に厳しかった]]> minioのroutersがtrailing-slash に厳しかった

Minio のルーティングがtrailing-slash を受け付けてくれないので、S3cmd のPutBucketが上手く機能していなかった。 なので修正したGorilla を使ってた。 S3cmd がちゃんと使える様になるには、GetService など機能してないので他にも対応が必要そうだった。

小さい修正でS3cmdla などが機能してないなど、まだS3cmd が完全に機能するわけじゃない。 そのうえ英語が苦手なためPRするか躊躇っている。

]]>
Wed, 28 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/25/research_minio.html http://blog.masu-mi.me/2015/10/25/research_minio.html <![CDATA[minio周辺の調査]]> minio周辺の調査

minio は単なるS3互換ObjectStorageだと思っていたけどそうじゃないらしい。 モダンなクラウドシステムならSANやRAIDみたいな事を要請しないという事だった。 きっと彼らはクラウド上で上手く分散するオブジェクトストレージを目指している。 ただ詳細を追ったところ直近は追いかけないでいる事にした。

Minio 概要と期待したい事

minio はsimpleを心がけている。その1つとしてminio はImmutableデータを強調している。 “Delete, Updateなどの処理はトランザクションが必要となりアプリケーションで非常に多様なトランザクション単位が考えられるのでアプリケーションで行うべき” という立場だ。 そして管理が複雑になるためIAMも敢えて実装しない方針をとっている。 なので今後minio はコンテナやPaaS上で上手く協調するオブジェクトストレージに向かっていくのだろう。 (と思ってたら書いている記事を見つけた)

またインタフェースは単純なものだけを提供する方向にしている

参考にしたい事は、レプリケーション・データリペア・ディスク障害検知の実装と運用しやすい設計とコマンドラインインタフェースの3つ。

以下に詳細を追ってみて気になった箇所をメモする。

なんかDeleteが実装されてる

blogとかでDeleteとか、あえて実装していないって謳っているのに見つけてしまった。分散管理で不都合はないと思い返したのだろうか? 経緯が気になる。

このコードだと素朴な削除しているので、操作ログまたはメタ情報が管理されてないとレプリケーション・データリペア時に削除済みオブジェクトが復活しまう。 削除済み or 未作成を判断する仕組みは見つけられなかった。

なんかネットで見つかったコンポーネント概要が実装されていない

オブジェクトを保存するFS, ブロックデバイスはDonutと呼ばれるコンポーネントで抽象化・管理する らしいが詳細は不明。 ところが現状はDonutなどでgrepしても何も出てこない。

感想

コミュニティを少し眺めただけだとDelete機能が追加されている経緯がわからなかった。 またIAMを拒否しているけどIssueでIAM の一部機能の実装が提案されていた。本筋の分散管理は全体像が読めなかった。 6ヶ月から12ヶ月で大枠が決まるらしいし(リンク先ではコミュニティに参加するなら今だよって提案されてるけど)一旦は追わず全体像を待ってからで良いと思った。 分散管理部分をmc とかクライアント側でやる方針に転換したかも知れないので他リポジトリは眺めても良さそう。

補足だけど、入力に一致するサブコマンドがない場合に候補を表示する機能を実現するためにTrie木を使ってた

]]>
Sun, 25 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/25/handling_signal_in_go.html http://blog.masu-mi.me/2015/10/25/handling_signal_in_go.html <![CDATA[GoでSignalをハンドリングする]]> GoでSignalをハンドリングする

signal.Notify を使ったのでメモ。

package main

import (
      "fmt"
      "os"
      "os/signal"
      "syscall"
      "time"
)

func init() {
      var sc = make(chan os.Signal)
      signal.Notify(sc, syscall.SIGABRT, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
      go func() {
              for {
                      s := <-sc
                      fmt.Printf("IGNORE: %s\n", s)
              }
      }()
}
func main() {
      p, _ := os.FindProcess(os.Getpid())
      for _, s := range []os.Signal{syscall.SIGABRT, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP} {
              fmt.Printf("Signal: %s\n", s)
              p.Signal(s)
              time.Sleep(1 * time.Second)
      }
}

以下の様に自分で投げるとSignalが投げられて到達する前にほかのSignalが到達してしまい前のが見えなくなる場合もある様子。

$ go version
[No write since last change]
go version go1.5.1 darwin/amd64
$ go run ./sig_sample.go
Signal: abort trap
Signal: interrupt
IGNORE: interrupt
Signal: terminated
IGNORE: terminated
Signal: hangup
IGNORE: hangup
$ go run ./sig_sample.go
Signal: abort trap
IGNORE: abort trap
Signal: interrupt
IGNORE: interrupt
Signal: terminated
IGNORE: terminated
Signal: hangup
IGNORE: hangup
]]>
Sun, 25 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/17/trial_minio.html http://blog.masu-mi.me/2015/10/17/trial_minio.html <![CDATA[Minioを試した]]> Minioを試した

tl;dr

今回やったこと

Minio を立ち上げて色々なクライアントで叩いてみた。 MinioHaystack を参考にしたS3互換のObjectStorage で下のような特徴がある。

  • Minio はGoで書かれている
  • Haystack に影響を受けているらしい
  • 少なくともdefaultでは匿名ユーザーで利用可能(ObjectStorage界のSQLite っぽい)
  • 専用のライブラリが用意されている
  • S3互換なのでS3エコシステムを流用可能

今回知ったこと

  • s3fs ではマウント失敗, 何故かtcpdumpでパケット見つけられず要調査

  • Minio はURLのハンドリングが上手くない
    • S3cmd でPutBucket は機能しない
  • 匿名ユーザを受け付けるので単なるCurl で利用可能

  • s3curl にURL末尾が”/”のGetBucket でGetObject(Key名null)するバグあり

Read more...

]]>
Sat, 17 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/17/trial_s3fs.html http://blog.masu-mi.me/2015/10/17/trial_s3fs.html <![CDATA[s3fsを試した]]> s3fsを試した

FUSEを利用したs3fs というツールがありS3互換のオブジェクトストレージをマウントできるので試してみた。

tl;dr

以下のコピペで ${target_dir}${target_bucket} をマウントできる。 オプションを与えたいときは-o で与える。特にエンドポイントを与えたいときはurl で与えられる。 S3互換のオブジェクトストレージを利用する場合はこれが必要。

$ echo <<EOCONF > ~/.passwd-s3fs && chmod 600 ~/.passwd-s3fs
${ACCESS_KEY_ID}:${SECRET_KEY_ID}
EOCONF
$ s3fs ${target_bucket} ${target_dir} -o url=${endpoint_url}

インストール周辺

v1.74でコンパイルこけてgcc調べたり必要が出て面倒だったのでver.を下げました。

$ yum install fuse
$ modprobe fuse
$ yum install libxslt-devel
$ wget  http://s3fs.googlecode.com/files/s3fs-1.73.tar.gz
$ tar zxvf s3fs-1.73.tar.gz
$ cd s3fs-1.73
$ ./configure --prefix=/home/vagrant/local
$ make
$ make install

リージョン間速度比較

US, Tokyoのリージョンエンドポイントを指定してtimeで比較したけど大差なし(オブジェクト数:1)。 バケットないファイル数が多くTCPウィンドウサイズを越えたりすると急に劣化が起きるか比較したい。

$ s3fs sample.bucket ./test_s3fs/ -o url=http://s3.amazonaws.com
$ time ls ./test_s3fs
...
real    0m0.212s
...

$ s3fs sample.bucket ./test_s3fs/ -o url=http://s3-ap-northeast-1.amazonaws.com
$ time ls ./test_s3fs
...
real    0m0.225s
...
]]>
Sat, 17 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/14/golang_exit_and_defer.html http://blog.masu-mi.me/2015/10/14/golang_exit_and_defer.html <![CDATA[os.Exit() とdeferを両立する]]> os.Exit() とdeferを両立する

Qiitaでみんなが困ってたので比較的まっとうな解決策を書いてみる。

tl;dr

下のようにos.Exit() を無名関数に包んで先頭でdefer 実行する。

func TestMain(* testing.M) {
  var ret int
  defer func(){ os.Exit(ret) }()

  setup()
  defer teardown()
  if isComplexCondition {
    setupComplexCondition()
    defer teardownComplexCondition()
  }
  ret = m.Run()
}

詳細

  • main, TestMain の後処理なので対象関数内で実行すると分かりやすい
  • 確実に実行されてほしい後処理なのだからdefer
  • 最後に実行されたいのだから先頭のdefer
  • 受け取る値の評価は遅延したいので無名関数で囲う
]]>
Wed, 14 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/14/use_devicemapper.html http://blog.masu-mi.me/2015/10/14/use_devicemapper.html <![CDATA[device-mapper を使って途中からI/O Error を起こす]]> device-mapper を使って途中からI/O Error を起こす

device-mapper を使ってデバッグ用にエラーを返すファイルシステムを作ったので関連コマンドをメモしておく。

保存するファイルを準備する

ループバックデバイスへの書き込みを受け取るファイルを準備しておく。

$ dd if=/dev/zero of=./test.img bs=1024 count=20000
20000+0 records in
20000+0 records out
20480000 bytes (20 MB) copied, 0.0207247 s, 988 MB/s

ループバックデバイス作成

ループバックデバイスを使って最初のファイルに書き込み口を作る。 ループバックデバイスは /dev/loop<N> に作られる。

# 空いている最初ループバックデバイスを調べる
$ sudo losetup -f
/dev/loop0
$ sudo losetup $(sudo losetup -f) ./test.img
$ sudo losetup /dev/loop0
/dev/loop0: [fc01]:2237716 (/home/masumi...)

ループバックデバイス上にext4を初期化

ext4(ジャーナリング有効(デフォルトだけど))を作ってみる。

# ファイルシステム作成
$ sudo mkfs -t ext4 -O has_journal /dev/loop0

Errorを起こすデバイスを作る

$ tmp_index=$(expr $(sudo blockdev --getsize /dev/loop0) \- 300); cat <<EOMAP | sudo dmsetup create test_linear; unset tmp_index
0 ${tmp_index} linear /dev/loop0 0
${tmp_index} 300 error
EOMAP
$ ls /dev/mapper
centos-root  centos-swap  control      test_linear

マウントする

ここではtouchでサイズ0のファイルを作っている。デバイスイメージの後半300セクタがErrorデバイスとなりI/O Errorが生じるため、大き目なファイルを作ると失敗する可能性がある。 ただ手元ではext4でジャーナルをしているのに成功してしまう事が多発した。

$ sudo mount /dev/test_linear ./test.mount.point
$ touch ./test.mount.point/test.file

後処理をする

# アンマウント
$ sudo umount ./test.mount.point
# マップデバイスの削除
$ sudo dmsetup remove /dev/mapper/test_linear
# デバイスマップの存在確認
$ sudo dmsetup ls

# 使えるようになったループバックデバイスをマウント
$ sudo mount /dev/loop0 ./test.mount.point
$ ls ./test.mount.point
./test.file
# アンマウント
$ sudo umount ./test.mount.point
# ループバックデバイスの破棄
$ sudo losetup -d /dev/loop0
$ sudo losetup -f # 消えているか確認する
/dev/loop0

参考資料

他にもsnapshot デバイスなど面白そうなものもある。

]]>
Wed, 14 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/06/patch_to_runtime_gdb.html http://blog.masu-mi.me/2015/10/06/patch_to_runtime_gdb.html <![CDATA[Goのデバッグでgdbを使うための準備]]> Goのデバッグでgdbを使うための準備

tl;dr

Goの開発でデバッガが必要になりgdbを使った。goroutine の機能も提供されている らしく試したのだが上手くロードできなかった。 調べたらチケット切られ解決していたがコード修正が必要と書かれていた 。 特にpatchも見つからずmaster では未だ修正されていなかったためpatch化した。 ロードに関しては以下を実行すれば解決する。 しかし実際に使うには必要な修正は他にもあるらしく調べたり修正が未だ必要

$ git clone https://gist.github.com/5f1b8b08d9959b27c6dc.git
$ sudo patch -u /usr/local/go/src/runtime/runtime-gdb.py < ./5f1b8b08d9959b27c6dc/runtime-gdb.py.patch
patching file ${GOROOT}/src/runtime/runtime-gdb.py
修正されて goroutineを扱える状態のgdb

感想

goのgdb pluginはgoのバイナリをターゲットにした時にロード出来るようでターゲットが存在しない時にsource で読み込んでも失敗した。

何もターゲットプロセスが存在しないでloadしてみた

ここから広げて読んだ所goobjfile の書きかわるタイミングはロード時だけだった。goobjfiles が変更されたタイミングをフック出来れば柔軟になるかも知れない。 またgdb.Function, gdb.Command を継承したクラスのインスタンスを生成すればgdbに機能を追加できるみたいで遊べそうだと思った。

]]>
Tue, 06 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/10/04/create_playground_with_vagrant_and_ansible.html http://blog.masu-mi.me/2015/10/04/create_playground_with_vagrant_and_ansible.html <![CDATA[VagrantとAnsibleでPlayground環境を作った]]> VagrantとAnsibleでPlayground環境を作った

tl;dr

下のコマンドを叩けばCentOS7.0のplayground環境を作れる。

$ git clone https://github.com/masu-mi/create-env-playground.git
$ cd create-env-playground
$ vagrant up

CentOSのplayground環境を手で作るの辛かったので Vagrant + VirtualBox + Ansible一発で作れるようにした

provider VirtualBox
OS CentOS Linux release 7.1.1503
Network public, private:192.168.33.10
preinstall linuxbrew, go, gotools, mercurial, vim, vim-plugins, etc

所感

とりあえずPlayground構築が自動化され快適になった。ただ仮想マシン構築とプロビジョニングは時間が掛かるのが不満として残る。 やはり開発環境やPlaygroundもビルド環境・テスト環境みたいにコンテナイメージ利用する方が時間を掛けずに要件を満たせるのでベターな解答だと思う。 ただ業務で触れない(業務だとChef, Fabric が多い)Ansible でrole分けたりtemplate使ったりmeta記述したりと目的を持って触たのは良かった。

Fabric がタスクを単純に記述する方向でプロビジョニングを表現するのと異なり、AnsibleChef と同様に宣言的なアプローチを取っている。 特にplaybook・role間の依存関係やモジュール単体の意味は状態記述に対応している。一方playbook の中身(モジュールの使い方)は作業の記述という感じがあり気楽だった。 状態記述と作業記述の両方を自然に感じる所で採用している印象を受けた。

しかしChef でも感じたが目標となる状態を記述するアプローチで単純にプロビジョニングを捉えると、状態遷移の中間状態を簡単に扱えない様な気がした。 例えば、一時的にVIP から外す・プロセスを停止する・監視を外すなど、状態遷移に伴う一時的な状態とタスクってたくさんある。 選択肢としては、良い表現方法を探す・そもそも中間状態を不要とする様な仕組み(オーケストレーション利用?)を考える・プロビジョニングのベターな捉え方を作り直す、がありそう。 まずはChef, Ansible で良い表現を探すのが意義があると思った。今の捉え方の何が問題になっているのかをハッキリ捉えないと良い解答は出なそう。

またclient, soloが自らの状態を変更するChef に対し外部から指示するAnsible は比較的簡単に対象ホスト全体を扱え少し中間状態の管理が楽になると思った。 ただ、やはり冪等性や状態記述という枠組みから足が出ている感じは残る。

ただChef にしろAnsible にしろ状態変更の際の中間状態を定義したりするのが難しいためプロビジョニングって仕事の抽象化について足りない面があるんじゃないかって思った。 あと push-job があるのでChef でタスク実行したり色々と膨らんでるなぁって。

]]>
Sun, 04 Oct 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/09/13/mk_swap.html http://blog.masu-mi.me/2015/09/13/mk_swap.html <![CDATA[Swap領域を作る]]> Swap領域を作る

ずいぶん前にメモリ不足でミドルウェアが立たない事があった。 本番環境では使えないけど、とりあえずSWAP を追加して動くようにした。 環境はCentOS たぶんLinuxならOK。

# SWAP用ファイルの作成
$ dd if=/dev/zero of=/path/to/swapfile bs=1M count=2048
$ sudo mkswap /path/to/swapfile
# SWAPを有効にする
$ sudo swapon /path/to/swapfile
]]>
Sun, 13 Sep 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/08/24/use_tcpdump.html http://blog.masu-mi.me/2015/08/24/use_tcpdump.html <![CDATA[tcpdumpの使い方まとめ]]> tcpdumpの使い方まとめ

tcpdumpTCPUDP などに対応したパケットキャプチャツール。 詳細はマニュアル(man tcpdump)を読む。

tcpdump [options...] [ expression ]

上記expression はネットワークスニッフ用データ形式pcap のフィルターを記述する。 詳細はman pcap-filter で読む。

基本的な使い方をメモしておく。

Read more...

]]>
Mon, 24 Aug 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/07/20/make_face_detector.html http://blog.masu-mi.me/2015/07/20/make_face_detector.html <![CDATA[Gojiで顔認識ツールを作った]]> Gojiで顔認識ツールを作った

Go言語でWebアプリケーションを一通り実装してみたくなった。 試しにWebベースの顔認識ツール(face_detector)を作った。

実装した機能

  • アップロード用コンパネ
  • ファイルアップロード機能
  • 顔認識機能
  • システムテスト(net/http/httptest)
]]>
Mon, 20 Jul 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/07/12/overview_gae.html http://blog.masu-mi.me/2015/07/12/overview_gae.html <![CDATA[GAEを調べてみた]]> GAEを調べてみた

Google App Engine(GAE) をGoでいたくて公式ドキュメント を眺めてみた。

まずGAEではアプリケーションモジュールで組織する。各モジュールは更にバージョン管理される。特定バージョンモジュールに対応したインスタンスが立ち上がり機能を実現する。 そしてインスタンスの稼働で生じたリソース消費に応じて課金される。 なので下を整理しておけば大枠が掴めるって考えて良さそう。

なんにせよ先ずはチュートリアル が概要を掴むのに役立つうえお金も掛からないので試すのが吉。

モジュール・アプリケーションの定義

GoogleAppEngine ではアプリケーションはモジュールで組織され少なくとも一つのモジュール(defaultモジュール)が存在する。

Application hierarchy(公式)

その全体像はApp Engine Modules in Go を読むと感じが掴める。 アプリケーション・モジュールはapp.yaml と呼ばれるメタファイルに設定を記述する。 リファレンス(Configuring With app.yml) を眺めると色々な事を指定できる。下に主な項目を乗せておく。

下記のルーティング指定について補足すると、app.yaml ではモジュール内でハンドラへのルーティングを扱いアプリケーション全体はdispatch.yamlで行うらしい 。 また、アプリケーション・モジュールはドメインを持つがカスタムドメインを利用する事も出来る

モジュールの実装に使うコードはGo, Python,... がサポートされているがcustom を指定して自由に扱えるらしい。

Read more...

]]>
Sun, 12 Jul 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/06/14/start_go_coding.html http://blog.masu-mi.me/2015/06/14/start_go_coding.html <![CDATA[Go定石を身につける]]> Go定石を身につける

ここでは Go での定石を身につけて簡単なツール・Webアプリを作れるようになる所を目指す。

Read more...

]]>
Sun, 14 Jun 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/06/06/beginning_gorp.html http://blog.masu-mi.me/2015/06/06/beginning_gorp.html <![CDATA[gorp を使ってみた]]> gorp を使ってみた

GoでSQLを扱うのに gorp を試してみた。 Go でのDB(RDBMS)との話し方はgorp 含めQiita記事 にアプローチ毎に整理されて紹介されている。

coopernurse/gorp Package gorp provides a simple way to marshal Go structs to and from SQL databases.

特に公式mattnさんの記事 が参考になる。

使い方

大雑把に下の流れが必要。各種クエリにはトランザクションもサポートされている。

  1. *DbMap を取得する(DBを扱う準備をする)
  2. *TableMap を登録する(構造体をテーブルに紐付ける)
  3. 各種クエリを利用する

Webアプリなどでアクセスの度にDBをオープンしたり構造体とテーブルの紐付けしたりするのも馬鹿らしいので、 model用のパッケージなどで永続的に保持しておくのが良い。

Read more...

]]>
Sat, 06 Jun 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/05/29/habituation_board.html http://blog.masu-mi.me/2015/05/29/habituation_board.html <![CDATA[自分の習慣を改善する]]> 自分の習慣を改善する

習慣を作るには以下の3つを考慮した環境設計が重要という行動心理学の話を聞いた。

きっかけ 行動を起こす明示的なスイッチ
スキル 実際に行動可能か? 難易度や本人の負担など
モチベーション どれだけ習慣化したいと望んでいるか

スキルの内容はコスト・負担と表現したほうがしっくりきた。 モチベーションの内容は曖昧で、また3つの用語が基づく習慣・行動モデルが不明で雑談だったのだけど。 行動を習慣にする時、定期バッチよりイベントハンドラとして宣言した方が続くという趣旨は共感できた。 アラートで外部から通知されるよりも既存の習慣化した行動から続ける方が行動できる気がする。

しかし心理的な習慣など含めて全てにきっかけを作るのは難しい。そこで昔から言われている「モチベーション維持は記録を付けるのが効く」って話と組み合わせると良いらしい。

そんなわけで、毎日あるきっかけで前日の行動記録を取る様にして、望む行動の習慣化を図っている。

ちなみに自分が身についてないなぁって思った振り返りネタは下にした。 心理的な習慣が多くて意識高い感じするけど改善できると嬉しい。

  • 悩みについて当日中に手を打ったか?
  • アーキテクチャ・設計に関する本を読んだか?
  • 事前に目標を確認したか?
  • 目標の重要度・緊急度を確認したか?
  • 他の人の状況確認を自ら行ったか?
  • 他の人の愚痴・不満・困っている事をメモしたか?
  • 予定の内容をシミュレーションしたか?

行動・習慣をモデル化してデザインするって話は、サービスの普及とか困っている友人の行動を助けるとか応用が効くと思った。モデル化が曖昧だと辛く感じる性分で自分で納得いくまで言葉を整理する必要がある。

]]>
Fri, 29 May 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/05/10/ansible_docs.html http://blog.masu-mi.me/2015/05/10/ansible_docs.html <![CDATA[ansible-docs]]> ansible-docs

Ansible を使ってみて頭に入れておく場所のメモ。

次に読むもの幾つか

公式Docが充実している。

またansible-doc コマンドは便利なのでPlaybookを書いている時に使うと良い。

$ ansible-doc homebrew
]]>
Sun, 10 May 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/05/08/operation_at_starting_new_mbp.html http://blog.masu-mi.me/2015/05/08/operation_at_starting_new_mbp.html <![CDATA[新しいMBP を快適に使うための準備]]> 新しいMBP を快適に使うための準備

前に注文したMBP13 が届いた。基本的な設定をしたのでメモする。

目標はLinux, Darwin 環境の設定を素早く完了する。 そのためにまずMBPの環境設定・コマンド導入をAnsible で可能な範囲で自動化した。 Linuxの開発環境を自動構築するのは見送っている。

Read more...

]]>
Fri, 08 May 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/04/11/fabric_tips.html http://blog.masu-mi.me/2015/04/11/fabric_tips.html <![CDATA[Fabricを使う上で知ってると嬉しいN 個の事]]> Fabricを使う上で知ってると嬉しいN 個の事

Fabric を使っていて早めに知りたかった事をまとめた。

タスクに説明をつける

Fabricはタスクのドキュメンテーション文字列(docstring) をタスクの説明として利用する。 そのためfabfile.py を以下の様に定義するとfab –list の際に説明が表示される。

# coding: utf-8
from fabric.api import task, run

@task
def setup():
  """

  空行を除く最初の1行が表示される
  ここは表示されない
  """
  run("hostname")

このファイルでは以下の様になる。

$ fab --list
Available commands:

    setup  空行を除く最初の1行が表示される

タスクはモジュールを元に階層構造を取る

タスク#名前空間 に書かれているが。 まずタスクを定義したモジュールkusa を作成する。

$ mkdir kusa
$ vim ./kusa/__init__.py
# coding: utf-8
# __init__.py
from fabric.api import task, run

@task
def www():
  """ WWW """
  run("hostname")

以下の様に fabfile.py でタスクを定義したモジュールをロードするタスクが階層化される。

#...
import kusa

@task
def setup():
  """ 設定 """
  run("hostname")

実行結果は以下の様になる。

$ fab --list
Available commands:

    setup     設定
    kusa.www  WWW

タスクを複数指定したときの実行順序

基本的に、タスク・関数は以下の様に実行される。

  1. fab コマンドに与えたタスクを左から実行する

  2. 各タスクはホスト分繰り返し実行される
    • @parallel デコレータが使われている場合は並列実行される
  3. 各タスクが内部で実行する関数・タスクは関数として実行される
    • 呼ばれた関数に@serial デコレータが使われている場合 @parallelによって並列実行されている場合も同時に実行されない様になる
    • 呼ばれた関数に` @runs_once デコレータが使われている場合 実行中に始めて呼ばれた場合を除いて実行されない
    • 呼ばれた関数に@parallel デコレータが使われている場合 特に意味がない

試しに以下の様にfabfile.py を書いて実行する。

@task
def call_test():
    func_print()
    once_func_print()
    task_print()
    once_task_print()
    parallel_func_print()
    parallel_task_print()
@task
def task_print():
    print "IN TASK_LS"
@runs_once
@task
def once_task_print():
    print "IN ONCE_TASK_LS"
def func_print():
    print "IN FUNC_LS"
@runs_once
def once_func_print():
    print "IN ONCE_FUNC_LS"
@parallel
def parallel_func_print():
    print "IN PARALLEL_FUNC_LS: %s"%env.host
@task
@parallel
def parallel_task_print():
    print "IN PARALLEL_TASK_LS: %s"%env.host
    serial_task_print()
    func_print()
@task
@serial
def serial_task_print():
    print "IN SERIAL TASK_PRINT: %s"%env.host
$ fab call_test task_print call_test once_task_print parallel_task_print
[localhost] Executing task 'call_test'
IN FUNC_LS
IN ONCE_FUNC_LS
IN TASK_LS
IN ONCE_TASK_LS
IN PARALLEL_FUNC_LS: localhost
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS
[yazawa.niko] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: yazawa.niko
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
[localhost] Executing task 'task_print'
IN TASK_LS
[yazawa.niko] Executing task 'task_print'
IN TASK_LS
[localhost] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: localhost
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS
[yazawa.niko] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: yazawa.niko
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
[localhost] Executing task 'parallel_task_print'
[yazawa.niko] Executing task 'parallel_task_print'
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS

Done.

eagerly_disconnect でセッションを切る

以下を設定しておかないとfab コマンド全体が完了するまで各ホストへのセッションが切断されない。 そのためホストが多いとエフェメラルポートが足りなくなりタスクが完了しなかったりする。

from fabric.api import env
env.eagerly_disconnect = True

get/put のエラーハンドリング

get, put 関数を使いSFTPを利用しファイル・ディレクトリを転送する。 これは失敗する事もありえるので、ちゃんと確認したい。 以下みたいに検知する。

@task
def get_archive():
  r = get("archive", "$(path)s.$(host)s")
  if not r.succeded:
    for remote_path in r.failed:
      print "[ERROR]%s"%remote_path

必要ない事は出力しない

Fabricって何でもかんでも出力してとても見にくい。 peco 使ってフィルタリングしながら探したりするか逆に出力を抑えて欲しい物だけ明示的に出力するのも手段としては取り得る。 出力を抑える方法 は以下の様にする。

@task
def remote_ls():
  with hide("running", "stdout"):
    run("ls -la")

@task
def silent_pwd():
  import fabric.state.output
  output["running"] = False
  run("pwd")

password の処理

以下の様にpasswordを設定しておいて、入力を省く。

import getpass
env.password = getpass.getpass()
@task
def sudo_ls():
  sudo("ls -la")

インタラクティブな操作を行なう

以下の様にする事で特定ファイルを手作業で変更する等の作業を自動化されたタスクに埋込む事が可能になる。 ただしエラーハンドリングされないので扱い辛い。 引数を与えるとユーザが操作可能になる前に実行される。だから以下の様にすると編集完了後に強制ログアウトさせられる。

from fabric.operations import open_shell
@task
def edit():
    open_shell("vim ~/.bashrc && exit")

sshで鍵ファイルを利用する

sshの鍵ファイルはenv で設定する。ForwardAgent しているときは邪魔になるので注意が必要。

env.key_filename = "~/.ssh/id_rsa"
@task
def hostname():
  run("hostname")
]]>
Sat, 11 Apr 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/04/01/start_oz.html http://blog.masu-mi.me/2015/04/01/start_oz.html <![CDATA[Oz環境を作る]]> Oz環境を作る

Oz環境を簡単に作れなかったので無理矢理動く状態にしたのでメモしておく。 開発言語の環境作りのメモばかりしてる気がする。

Oz環境が欲しくなった経緯はコンピュータプログラミングの概念・技法・モデル を読みたかったから。 実験が出来た方が良いのでOz の環境を作る事にした。

SICP , ラビ・セシィ, TAPL 以来のプログラミング言語な勉強の再会だ。

環境作成

とりあえずインストールする。

$ export HOMEBREW_CASK_OPTS="--appdir=/Applications"
$ brew install caskroom/cask/brew-cask
$ brew tap caskroom/versions
$ brew cask install mozart2

パス追加する。

export PATH=/Applications/Mozart2.app/Contents/Resources/bin/oz:${PATH}

Mozart2 システムがemacsなので...

まともに使った事が無いemacsで上手く思った様に動かなかったのでメモしておく。 転がってた情報だと <C-.>e でカーソル行を実行するって書かれていたけど、 手元のMorzart2 ではbindingが異なった。更にCUI版(ozコマンド)では<C-.> が無効になっていた。 そのため、以下のバインディングで実行する。

<C-c>.e エミュレータペイン?を起動する
<C-c>.<C-b> カーソルのある行を実行する

Mozart2 に頼らないozcの実行

下な感じのコードを準備しておく。

{Show 'Hello'}

下な感じで実行する。出来ればvim + quickrun とかで環境作りたいね。

$ ozc ./hello.oz
]]>
Wed, 01 Apr 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/03/29/setup_haskell.html http://blog.masu-mi.me/2015/03/29/setup_haskell.html <![CDATA[Haskell開発環境を作る]]> Haskell開発環境を作る

Haskell動作環境を作ったのでメモとして残しておく。

Haskell環境を準備する

homebrew でghc, cabal-install を導入する。

$ brew install ghc cabal-install
$ cabal install cabal-install
$ cabal install happy
$ cabal install ghc-mod —dry-run
$ cabal install ghc-mod
$ cat ~/.bashrc
function add_path {
  if test -d $1 && test `echo ${PATH} | /usr/bin/env grep -v $1` ; then
    export PATH="$1:${PATH}"
  fi
}
add_path "${HOME}/.cabal/bin"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/local/lib:/usr/lib"

Vim にプラグインを導入する

とりあえずQiita を真似て導入した。

NeoBundle 'dag/vim2hs'
NeoBundle 'eagletmt/ghcmod-vim'
NeoBundle 'eagletmt/neco-ghc'

使ってみる

ghc, ghci を使ってみる。

ghci: REPL環境を試す

REPL環境は大事だ。

$ ghci
GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> 10 ** 5
100000.0
<C-d>

ghc コンパイラを試す

Hello Worldを書いて実施する。

main = putStrLn "hello, world"
$ ghc ./hello.hs
$ ./hello
hello, world
]]>
Sun, 29 Mar 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/03/08/fabrinc_in_python.html http://blog.masu-mi.me/2015/03/08/fabrinc_in_python.html <![CDATA[Fabric をPythonから呼び出す]]> Fabric をPythonから呼び出す

Fabric をライブラリとして使う例をメモしておく。 理由はネットで引くと大抵、ツールとして使われていて公式ドキュメントを読まないと誤解しがちなため。

fabfile.py を書いてfab コマンドとして使う場合が多いけれどfab コマンドだとトップレベルがタスクのため対象ホストの数だけ実行されてしまう。 例えばシステムの負荷検証を考えてみると、全体のタスクは1回だが一部に複数ホストに横断したタスクがある。 このような状況ではPythonで全体タスクを記述し複数ホストに横断する共通作業をFabric に任せるという使い方が便利です。

Fabric
システム管理・デプロイタスクの効率化の為のPythonライブラリおよびツール

サンプルコード

試しに以下のプログラムを書いてみる。

#!/usr/bin/env python

from fabric.api import run,local,execute
def test():
  run("hostname")
  local("ls")
execute(test, hosts=["host.name.jp"])

上記の実行結果は下の様になる。

$ ./test.py
[host.name.jp] Executing task 'test'
[host.name.jp] run: hostname
[host.name.jp] out: host.name.jp.
[host.name.jp] out:

[localhost] local: ls
test.py

タスクを表現した実行可能オブジェクトをfabric.tasks.execute に渡せばFabric のタスクとして実行される。 Fabric のタスクはホスト毎に1回実行されるため、上記の様に引き数で渡したりまたはwith settings(): などコンテキストの指定を行なう事で env.hosts, env.roles, env.exculude_hosts の値が定まっている必要がある。

]]>
Sun, 08 Mar 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/03/01/dstat_plugin.html http://blog.masu-mi.me/2015/03/01/dstat_plugin.html <![CDATA[dstat プラグインの書き方]]> dstat プラグインの書き方

監視したい項目をdstat pluginにしておけば、fluent-plugin-dstat でどこにでも飛ばせるしdstatでCLIも存在するしcsvにも吐き出せるしでとても便利な気がした。 だけど公式ドキュメント にもpluginの書き方が見当たらなかった。そのため、基本的な書き方をまとめておく事にする。

pluginの配置場所

dstatのpluginは以下のディレクトリに配置した。dstat_plugin_snake_case.py が読み込まれる。~/.dstat/ 配下に置くのが手軽で影響範囲も少なくて良さそう。

  1. ~/.dstat/
  2. which dstat/plugin/
  3. /usr/share/dstat/
  4. /usr/local/share/dstat

プラグインを書いてみる

以下のファイルを.dstat/dstat_hello.py に配置してdstat —hello を実行してみる。

class dstat_plugin(dstat):
  def __init__(self):
    self.type = 'd'
    self.width = 5
    self.scale = 1000
    self.vars = ['hello', 'world']
    self.nick = ('apple', 'orange')
    self.cols = 2
  def name(self):
    return self.vars
  def extract(self):
    self.val['hello'] = (100000, 100800)
    self.val['world'] = (10000, 100)
../../../_images/20150229-dstat-firstplugin.png

初めてのdstatプラグイン

プラグインの構成要素

soファイルでプラグインを作る事も可能だがここではpythonで書く事を想定する。 plugin内ではdstat_plugin クラスを作成する必要がある。最低限定義すべきメソッドは__init__, extract の2つ。

プラグインのイベントフック

各イベントの意味付けや仕様は後述する。

ロード時の実行内容

  1. dstat_plugin classのインスタンス生成
  2. prepare(): ユーザー定義しない
  1. discover(): データ取得可能か判断する(mysql用pluginなど)
  2. vars() or vars: 必須: 後述する
  3. name(): 必須: 後述する
  4. nick() or nick: ユーザー定義可能: 後述する

実行中のイベント

  1. extract()

プラグインの種類

プラグインの扱うデータの構造により大きく2つに別れる。

階層を持つもの
cpuやdiskの様に複数の出力元が存在しグループが複数存在する
階層を持たないもの
loadaverage の様に出力元が単一

各イベントフックの仕様

dstat_plugin pluginの読み込み開始にインスタンス生成される。check()で最低限の健全性を確認しprepare()メソッドで初期設定が行なわれる。 そのためインスタンス生成後に以下が定義されている必要がある。

name dstatのヘッダの一番上の行に当たるブロックの名前
vars: (項目名の一覧 or それを返却する関数)
nick 各項目の名前
type 出力される値のタイプ
width 出力されるカラムの幅
scale 値のスケールを入れる、まだ理解出来てない
cols nickの項目数、設定値による挙動を理解出来ていない

値の中身

type メンバ
s: 文字列, d: 整数, f: 浮動点数, p: 割合(パーセンテージ)
scale メンバ
値のスケールを設定する(デフォルトは1000) 1024だとByteで末尾にBが付いたりする 1000 or 1024だとk, Mなど接頭辞が付く

name, vars, nickは階層を<持つ/持たない>により内容が変わるため別説で記述する。

name, vars, nick の3項目とデータ構造の関係

name, vars, nickの3メンバはデータ構造に合わせて内容が変わる。これは実行中に呼ばれるextractメソッドの挙動と整合性を保たねばならない。 この3項目はメンバがデータ構造に合わせた値でも、そのような値を返す関数でも動く。

nameはプラグインの一番上のタイトル部分を担当

階層を持たない場合
タイトルに当たる文字列 or そのような文字列を返す関数
階層を持つ場合
タイトルを格納したリスト・タプル or そのようなリスト・タプルを返す関数

varsはプラグインの第1階層の属性名を担当

階層を持たない場合
項目名にあたるリスト or そのようなリストを返す関数
階層を持たない場合
サブグループ名にあたるリスト or そのようなリストを返す関数

nickは実際に表示される値の項目名を担当する

階層の有無にかかわらず
項目名にあたるリスト・タプル or そのようなリスト・タプルを返す関数

extract() の仕様

extract()は実行中に呼ばれ出力する値をメンバ変数valに辞書として格納する。 valが出力に用いられるが、中間値としてメンバset1, set2 を使って次回に値を引き継ぐ事も可能。

階層を持たない場合

辞書valにはvarsに含まれる名前をキーに値を格納する。

class dstat_plugin(dstat):
  def __init__(self):
    self.name = 'title'
    self.vars = ['apple', 'orange']
    self.nick = ('id')
  def extract(self):
    self.val['apple'] = 1
    self.val['orange'] = 2

階層を持つ場合

辞書にはvarsに含まれる名前をキーにnickと対応する様にリスト・タプルを格納する。

class dstat_plugin(dstat):
  def __init__(self):
    self.vars = ['apple', 'orange']
    self.name = self.vars
    self.nick = ('id', 'count', 'sale')
  def extract(self):
    self.val['apple'] = (0, 20, 200)
    self.val['orange'] = (1, 10, 200)

便利メソッド

open 複数のファイル名を渡すと登録されファイルハンドラを保持する
readlines 保持されているファイルハンドラを順々にreadlinesするgenerator
splitlines 保持されているファイルハンドラのreadlines結果をsplitして結果を返してくれる

他にもtitle, colwidthなど整形や出力に関わるメソッドが定義されていた。dstatのコード内のdstat_cpu などを読むと、使い方が分かる。 これでdstat のプラグインを簡単に作れる。めでたしめでたし。

]]>
Sun, 01 Mar 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/02/28/dstat_options.html http://blog.masu-mi.me/2015/02/28/dstat_options.html <![CDATA[勝手のいいdstatコマンドオプション]]> 勝手のいいdstatコマンドオプション

dstat のコマンドオプションが多くて便利なので定番の組み合わせを整理してまとめた。

使えるオプションの確認

以下のコマンドでdstat について調べられる。これによると機能拡張は/usr/share/dstat/ にモジュールを置けば良さそう。 ミドルウェア作ったらdstat 用のpluginを提供するの良さそう。

# ヘルプを表示する
$ dstat -h
# 使えるモジュールを一覧表示する
$ dstat --list
internal:
        aio, cpu, cpu24, disk, disk24, disk24old, epoch, fs, int, int24, io, ipc, load, lock, mem, net, page, page24, proc, raw, socket, swap, swapold, sys, tcp, time, udp, unix, vm
/usr/share/dstat:
        battery, battery-remain, cpufreq, dbus, disk-util, fan, freespace, gpfs, gpfs-ops, helloworld, innodb-buffer, innodb-io, innodb-ops, lustre, memcache-hits, mysql-io, mysql-keys,
        mysql5-cmds, mysql5-conn, mysql5-io, mysql5-keys, net-packets, nfs3, nfs3-ops, nfsd3, nfsd3-ops, ntp, postfix, power, proc-count, rpc, rpcd, sendmail, snooze, thermal, top-bio,
        top-cpu, top-cputime, top-cputime-avg, top-io, top-latency, top-latency-avg, top-mem, top-oom, utmp, vm-memctl, vmk-hba, vmk-int, vmk-nic, vz-cpu, vz-io, vz-ubc, wifi

基本的な確認

これで基本的な負荷を確認する。ロードアベレージが伸びていたら注意が必要。 使えているコア数より大きくならない様に考える。実際のコア数ではなくて、稼働システムのコア利用の偏りも考慮する必要がある。

$ dstat -tal
../../../_images/20150228-dstat_tal.png

dstat で基本情報を表示する

CPU状態を確認する

CPUの分散具合を確認する。systemの部分は割り込み・コンテキストスイッチの切り替えなどを表示してる。

$ dstat -taf --top-cpu
../../../_images/20150228-dstat_taf_top-cpu.png

dstat でCPU情報を表示する

I/O状況を確認する

どのプロセスがI/O, ブロックI/Oを使っているか確認したり、開かれてるファイル数を確認したり、またファイルロックの取得状態を確認したりする。

$ dstat -tdng --file --lock --top-io --top-bio
../../../_images/20150228-dstat_tdng_file.png

dstat でI/O情報を取得する

メモリの状況を確認する

メモリの使用状況を確認する、ページング・スワップ領域・メモリ・仮想メモリ・IPC・一番メモリを使っているプロセスを表示している。

$ dstat -t -gs --mem --vm --ipc --top-mem
../../../_images/20150228-dstat_tgs_mem.png

dstat でメモリ情報を取得する

ネットワーク状況を確認する

ソケットの利用状況を表示する。

$ dstat -tn --socket --tcp --udp --unix
../../../_images/20150228-dstat_tn_socket.png

dstat でソケットの情報を取得する

ロックにまつわる統計の表示

ファイルロックとかページフォルトとか割り込み量とかIPCとか詰まりそうな基本的なの一通り出してみる。

$ dstat -tspy --lock --vm --ipc --free
../../../_images/20150228-dstat-tspy.png

dstat でロック周辺の情報を取得する

]]>
Sat, 28 Feb 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/02/28/make_ioprobe.html http://blog.masu-mi.me/2015/02/28/make_ioprobe.html <![CDATA[/proc/[pid]/io でプロセス個別でI/O速度を測る]]> /proc/[pid]/io でプロセス個別でI/O速度を測る

サーバ全体のI/Oの使用状況を確認するのには幾つか方法がある。 個別のプロセスのI/O情報を稼働中のサービス内で追いたい場合、デバッガ・プロファイラを走らせる様な重そうな方法以外に手軽な方法が見つからなかった。 作った後にpidstat -d -p [pid] 1 で目的を果たせる事に気付いた。 pidstat は後で調べます。

もしかしたらstrace -c でシステムコールにかかった時間を追う方法は筋が良いかも知れない。 とりあえず/proc/[pid]/io が使えそうだったので整形する簡単なコマンドを作ってみた。

プロセス個別にI/O速度を測るコマンド

プロセス個別の情報を知りたいときは /proc/[pid/ 以下を確認すれば良い。 man 5 proc で調べられるが、環境のmanが古くて /proc/[pid]/io の節が存在しなかったので次のサイトを読んだ。 ref. http://linuxjm.sourceforge.jp/html/LDP_man-pages/man5/proc.5.html

これによると以下が書かれていた。

rchar 読み出し文字数(端末とかも含まれるのでディスクデバイスかは不明)
wchar 書き込み文字数(端末とかも含まれるのでディスクデバイスかは不明)
syscr 読み出しシステムコール数
syscw 書き込みシステムコール数
read_bytes 読み出しバイト数(ストレージ層から取得しようとしたバイト数)
write_bytes 書き込みバイト数(ストレージ層から転送しようとしたバイト数)
cancelled_write_bytes キャンセルされた書き込みバイト数(ページキャッシュのトランケートにより引き起こされる)

プロセスの総転送量ではなく速度が知りたかったので定期的に取得して差を計算するだけで欲しい値が取れる。 下みたいな簡易のコマンドで秒間の速度が測れる。今はもう少し書き換えてJSONでも吐ける様にした。 https://github.com/masu-mi/ioprobe

#!/usr/bin/env python2.7
# coding: utf-8
import os, time, subprocess, re, argparse

def main(pid):
  io_sum = fetch_io(pid)
  pre_val = dict(io_sum)
  order = convert_to_order(io_sum)
  print header(order)
  while True:
    time.sleep(1)
    cur_val = dict(fetch_io(pid))
    print delta(pre_val, cur_val, order)
    pre_val = cur_val

def header(order):
  return "\t".join([term+"/s" for term in order])
def delta(pre, cur, order):
  return "\t".join((str(cur[key] - pre[key]) for key in order))

def convert_to_order(io_sum):
  return [pair[0] for pair in io_sum]
def fetch_io(pid):
  with open(os.path.join("/", "proc", pid, "io")) as f:
    io_sum = [(pair[0], int(pair[1]))
      for pair in (line.rstrip().split(":")
      for line in f.readlines())]
  return io_sum

if __name__ == "__main__":
  parser = argparse.ArgumentParser(description='I/O probe for process.')
  parser.add_argument('pid', metavar='pid', type=int, help='target process\'s pid.')
  args = parser.parse_args()
  main(str(args.pid))

サーバ全体のI/Oを確認する方法

vmstatはサーバのプロセスの稼働状態全体の経過を追う

仮想メモリの情報としてブロックデバイスとのI/Oも含まれる。以下 man から転載。

$ vmstat -n 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0     68 599012 192496 954952    0    0     0     0    0    1  0  0 100  0  0
 0  0     68 599004 192496 954952    0    0     0     0   44   16  0  0 100  0  0
 0  0     68 599004 192496 954952    0    0     0     0   39   24  0  0 100  0  0
io.bo
ブロックデバイスから受け取ったブロック数[blocks/sec]
io.bo
ブロックデバイスに送ったブロック数[blocks/sec]

sar -d でディスク情報を詳細に出力する

sarはシステム情報の何でも屋で-d オプションでディスク情報を出してくれる。

$ sar -d 1
Linux 2.6.xx-xxx.xxx.xx (xxxx.xx.xx.)  2015年02月22日  _x86_64_        (3 CPU)

17:00:08          DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
17:00:09     dev252-0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

17:00:09          DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
17:00:10     dev252-0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
DEV ブロックデバイスを指していて devX-Y(X: メジャー番号, Y: マイナー番号)となる
tps 1秒間に実際にデバイスに発行される転送要求数(論理的に複数要求が1件にまとめられる場合もあり)
rd_sec/s 1秒間の読み込みセクタ数(1セクタ: 512Byte)
wr_sec/s 1秒間の読み込みセクタ数(1セクタ: 512Byte)
avgrq-sz デバイスに発行された要求の平均サイズ(セクタ数)
avgqu-sz 発行された転送要求のキュー長
await デバイスに発行された転送要求の完了までのレイテンシ(キューイングタイムも含む)
svctm 実際に転送に掛かった時間
%util 転送要求をデバイスに発行しているCPU時間の割合

他のサーバリソースを確認するコマンド

iostat, dstat, iotop がある。ちなみにdstat, iotop はPython製のツール。

iostat CPU, デバイス・パーティッション・NFSへのI/Oの統計情報を表示する
dstat サーバの統計情報をだいたい素敵に表示してくれる
iotop topコマンド風I/O監視ツール
]]>
Sat, 28 Feb 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/02/22/coding_perl.html http://blog.masu-mi.me/2015/02/22/coding_perl.html <![CDATA[初めてのPerlコーディング]]> 初めてのPerlコーディング

前に遊ぶ準備や環境準備を書いたので使ってみた時に覚えておこうって思った特徴・ライブラリ・ツールについてメモしておく。

データ型は3つ

公式ドキュメントのデータ型 を読んでおけば良い。 読んだら下の使い方があって興味を持った。

@days[3,4,5] # as ($days[3], $days[4], $days[5])

外部モジュールを読み込む

use, require 命令の2つが存在する。

use, require を比較する

命令 評価タイミング 使えるサブルーチン バージョン
use コンパイル時評価 BEGIN, CHECK, INIT >= 5系
reuqire 実行時評価 BEGIN 全バージョン

use はコンパイル時評価であり特別なコードブロックを定義可能で、これらはモジュール読み込み時等に実行可能。

BEGIN 出来るだけ早く実行される(パース直後など)
END 出来るだけ遅く実行される(プログラム終了時など, シグナルで撃沈されたりevalだと実行されない, LIFO実行)
UNITCHECK 対象コンパイル単位のコンパイル直後に実行される
CHECK 最初のコンパイルフェーズ終了後に実行開始(LIFO)
INIT ランタイム実行直前(FIFO)

ref. Perlのモジュール

PATHを追加する

相対パスで読み込み先を指定したくなる。そういう時はFile, lib モジュールを使う。 以下を読み込む前に追加しておけば../lib/ 配下を探索する様になる。

use File::Basename;
use lib dirname(__FILE__). "/../lib/";

ファイルを行単位で処理する

行単位で処理するには以下のスニペットが綺麗な感じがする。行入力演算子<> を利用してファイルハンドラから受け取る。 標準入力は特別なファイルハンドラSTDIN から受け取る。 行末のEnter も入力に含まれる。chomp 関数で行末Enter を削除するのが良い。

open (IN, $file_name) or die "$!";
my $line;
while (<IN>) {
  $line = $_;
  chomp($line);
  print $line;
}

ガード節

異常な入力値を弾くためガード節を使うが、Perlでは後置を使う事がある。

$v = "apple"
print "v is apple." if $v eq "apple"
print "v is not orange." unless $v eq "orange"

定義済み変数

perlvar を参考にすると良い。以下抜粋。

$_ デフォルト入力などのスペース
@_ , @ARG サブルーチンの引き数が入っている・配列演算子のデフォルト引き数
%SIG シグナルハンドラを持つハッシュ
$PID , $$ プログラムのPID
$BASETIME , $^T ブログラムが起動したUnixTime

定番の正規表現処理

置換、存在の判別は以下の様にする。デフォルトでは$_ が対象になる。() を使ってキャプチャを行なう。

if (/pattern/) {
  print '$_ にpatternが含まれる';
}
if (!/pattern/) {
  print '$_ にpatternが含まれない';
}
if ($word =~ /pat(tern)/) {
  print '$word にpatternが含まれる';
  print $1; # ternが含まれる
}
if ($word !~ /pattern/) {
  print '$word にpatternが含まれない';
}
if (m|pattern|) {
  print 'm でパターン文字を変更する';
}

die, exit関数

異常系の処理には2つの方法がある。 1つめはdie 関数で例外を発生させる方法。 2つめはexec 関数でプロセス終了させる方法。

die 関数

詳細はリンク先を読めば良い。die 関数は例外を発生させるのでeval ブロックに囲まれてない場合、プログラムを終了させる。 eval に囲まれている場合はdie に渡した値が$@ に格納されるので以下の様に使う事になる。 サブルーチン外部でエラーを捕捉しようとしてる可能性がある場合はこれをつかう。

eval {
  die "in eval";
}
if $@ {
  print "error処理". $@;
}

これを応用したError <http://search.cpan.org/~shlomif/Error-0.17022/lib/Error.pm> モジュールが存在する。これを使うとtry, catch, except, throw などが使える様になる。

exit 関数

evalで捕捉されずプログラムを終了させる。各モジュールのEND サブルーチンを実行してから終了する。 引き数には終了コードを渡す。

サブルーチンの宣言・定義

組み込み関数一覧 を参考にする。 全ての引き数・返り値はスカラのリストに潰される。リスト・ハッシュともに潰されて渡される。 サブルーチン内部では@_ として見える。リスト・ハッシュの構造を失わずに渡すには参照渡しを行なう必要がある。

プロトタイプ宣言

& を使わない呼び出しで組み込み関数の様に振る舞わせる事が可能で、その受け取り方を定める。 下みたいな感じでブロックを受け取るサブルーチンを作ったり出来る。

sub safe(&@) {
  my $code = shift;
  start()
  eval {
    $code->();
  }
  if $@ {
    print "error"
  }
  end()
}

カリー化とか関数中心な書き方をするためのモジュールも存在するから、その辺を参考に使い方を覚えるとよさそう。 functionals

bless 使ってクラスを定義する

Perlでオブジェクト を参考に書けばだいたいOK。 メソッド、継承、委譲、オーバーライドとか出来る。 肝はbless を使いオブジェクトを与えたパッケージ名と結びつけパッケージ内のサブルーチンをオブジェクト経由で呼べる様にする事。 これがメソッドになる。 そしてメソッドの呼び出しは第1引き数にインスタンスが入ってくる。 パッケージでの-> 呼び出しでは先頭にクラス名が入っているという事。

package ClassName;
sub new {
  my ($class, $arg) = @_;
  $self = {}
  bless $self, $class
  return $self
}
package main;
$a = Classname->new();

tie の使い方

オブジェクトをメソッド経由でアクセスさせる代わりにネイティブなデータ型としてアクセスさせる方法がある。 tie 関数はスカラ・配列・ハッシュ・ハンドラとしてオブジェクトを結びつけられる。 詳細はリンクから読めばよし。TIESCALAR, FETCH, STORE などを定義して使う。PHPでのArrayObjectインタフェースの実装を書くみたいな感じ。

local, my を使った変数の名前解決

localは動的スコープ, myは静的スコープで名前解決を行なう。

global変数は名前空間を明示して利用する

したみたいな感じ

$::val = "global variable";
sub hoge {
  print $::val;
}
hoge;
# $VAR1 = 'global variable';

コマンドオプション解析の方法

Getopt::Long モジュールが定番でバッドノウハウが溜まっているらしい。 バッドノウハウと注意点はこの記事 がまとまっているらしい。

テストコードの書き方

Test::More パッケージが単体テストが気楽な定番っぽい。 マニュアル読めば直ぐに使える。perlのテストコードの拡張子はt が使われる。

Data::Dumper でプリントでバッグ

ここ を参考にすると良いです。 http://bayashi.net/diary/2013/0415

他の言語を利用したい

使わなかったけれど選択肢は以下があるみたい。

Inline::C 他のプログラム言語で直接Perlサブモジュールを作る
XS 外部のCコード, Cライブラリを利用する
Swig 級言語でC/C++を使うためのツール(perlも可能 )
]]>
Sun, 22 Feb 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/11/setup_perl.html http://blog.masu-mi.me/2015/01/11/setup_perl.html <![CDATA[Perl の開発環境の準備]]> Perl の開発環境の準備

依存管理

plenv + cpanm + carton でPerlの開発環境を構築する を真似る。

plenv perl のVersion切り替えを行なう
cpanm plenvでインストールしたperlにversion毎にモジュールをインストールする
carton モジュールの依存関係をローカル毎に管理する

OSXは以下を簡単に実施した。

brew install plenv
brew install perl-build
cat ~/.bashrc
if which plenv > /dev/null; then eval$(plenv init -); fi
plenv install-cpanm
plenv exec cpanm Module::Install
plenv exec cpanm Carton

スケルトン生成の準備

Perl ではh2xs, Module::Setup モジュールでスケルトンを生成するらしい。(FWでスケルトン生成があればそっちを使う(amon2など)) Module::Setup は以下でインストール出来た。(h2xs は最初から使用可能だった)

$ plenv exec cpanm JSON # JSON に依存しているため
$ plenv exec cpanm Module::Setup

スケルトン生成してみる

h2xs を試す

$ h2xs -AX --skip-exporter -n Foo::Bar
$ tree Foo-Bar/
Foo-Bar/
├── Changes
├── MANIFEST
├── Makefile.PL
├── README
├── lib
│   └── Foo
│       └── Bar.pm
└── t
    └── Foo-Bar.t

module-setup を試す

フレーバーを使って柔軟にスケルトンを生成出来るらしい。

# まずmodule-setup の初期化を行なう
$ plenv exec module-setup --init
Creating directory /Users/masumi/.module-setup
....
Creating directory /Users/masumi/.module-setup/flavors/default/template
# 色々生成された後に使うバージョン管理を聴かれる
Do you use SVN? [yN] [n] y
You chose version control system: SVN
Do you use SVK? [yN] [n] n
Do you use Git? [yN] [n] y
You chose version control system: Git
Your name:  [Default Name] Masumi Kanai
Your email:  [default {at} example.com] masumi.net@gmail.com
Dump config /Users/masumi/.module-setup/flavors/default/config.yaml

# 生成してみる
$ plenv exec module-setup MyModule
$ initial commit
12 files changed, 137 insertions(+)
create mode 100644 .gitignore
create mode 100644 .shipit
create mode 100644 Changes
create mode 100644 MANIFEST.SKIP
create mode 100644 Makefile.PL
create mode 100644 README
create mode 100644 lib/MyModule.pm
create mode 100644 t/00_compile.t
create mode 100644 xt/01_podspell.t
create mode 100644 xt/02_perlcritic.t
create mode 100644 xt/03_pod.t
create mode 100644 xt/perlcriticrc

# パッケージを作ってみる
perl Makefile.PL
# Makfileが生成される
make
make test
make dist
....
Created MyModule-0.01.tar.gz

2つのスケルトン共にデフォルトではCartonが利用するcpanfileを吐かないので対応が必要になる。 module-setupの場合はフレーバーを作れば良さそう。 Makefile.PLと記法が異なるので注意。

]]>
Sun, 11 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/11/start_perl.html http://blog.masu-mi.me/2015/01/11/start_perl.html <![CDATA[初めてのPerl]]> 初めてのPerl

だいぶ前に業務でPerl を触れた。 とりあえず遊ぶ準備が出来る所まで記録した。 近いうちに言語の特徴と便利そうなライブラリの記録も残しておく。

関連情報の調べ方

とりあえず下を知っていれば気楽になれる。

構文チェック・Perlデバッガはとても助かる。 他にも便利なモジュールがあるのでこれ を参考にした。

はじめてのPerlコード

さっそくPerlコードを書いてみる。

#!/usr/bin/env perl

# シンタックスエラー
sub add_10 {
  my ($v) = @_
  for (my $count = 0; $count < 10; $count++) {
    $v += 1
  }
  return $v
}

print "Hello World ";
print increment(2005)

シンタックスチェック

上記を以下の様にするとシンタックスチェックが動く。

$ perl -c ./test.pl
syntax error at ./test.pl line 5, near "0;"
syntax error at ./test.pl line 5, near "++) "
syntax error at ./test.pl line 9, near "$v
}"
./test.pl had compilation errors.

行末の”;” はコードブロックの終わりを除いて必要なので追記する。 そうして実行すると以下の様になる。

$ perl ./test.pl
Undefined subroutine &main::increment called at ./test.pl line 12.
Hello World

未定義な関数があるよって言われてからHello World って表示される。 ブロック内の名前解決は評価前に一括で実行される様な挙動をしている。 素直に関数名も修正して実行する。

$ perl ./test.pl
Hello World 2015

ちゃんと動く様で嬉しい。

解析ツール

プログラムの解析が必要な事は結構あって、Perlランタイムがどう呼ばれているか知りたいって事はあるので調べておいた。

プロファイラ dprofpp
デバッガ -d オプションを付けて実行すれば良いみたい(perldoc)

デバッガを使ってみる

試しに動かしたので解析する方法も知っておきたい。 最初に書いた様に-d オプションで起動するとデバッガが動くので試してみる。

$ perl -d ./test.pl
....
main::(./test.pl:11):   print "Hello World ";
  DB<1> h
List/search source lines:               Control script execution:
  l [ln|sub]  List source code            T           Stack trace
  - or .      List previous/current line  s [expr]    Single step [in expr]
  v [line]    View around line            n [expr]    Next, steps over subs
......
  DB<1> v
  9       }
  10
  11==>   print "Hello World ";
  12:     print add_10(2005)

よく使うのをメモしておくと以下になる。

コマンド 内容
h ヘルプ
cmd
ベージャを利用する
q デバッガ終了
直前(実行済み)の行を表示する。
. 現在(実行前)の行を表示する。
v[line] 指定した行周辺を表示
p expr perl式を評価する
M 読み込んでいるモジュールを表示する
T スタックトレースを表示する
b [ln|event|sub] [cnd] ブレークポイントを指定
w expr 式にwatchを設定
W expr|* 式のwatchを除去
s expr Step In 実行
n expr Next Step 実行
r リターン(現在のサブルーチンから脱出)
]]>
Sun, 11 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/10/use_firefox.html http://blog.masu-mi.me/2015/01/10/use_firefox.html <![CDATA[X11経由でFirefoxを使ってみた]]> X11経由でFirefoxを使ってみた

Linux上でFirefoxを動かしたかったのでなれないX Window を使った。

サーバサイドではxauth が動く状態にしてアプリケーションが動けば良い。VirtualBox上のUbuntuはxauth が既に入っていたから問題なく動かせた。 クライアントサイドからは`-XY` オプション付けるか設定ファイルでForwardX11 を有効にしてssh でつないでアプリケーションを実行すれば良い。

サーバサイドでの準備

CentOS

$ yum install firefox
$ yum install xorg-x11-xauth
$ cat /etc/ssh/sshd_config
X11Forwarding yes
X11UseLocalhost no
$ service sshd reload

Ubuntu

$ apt-get install firefox
$ finger xauth
/usr/bin/xauth

クライアント準備

下の設定を書いてssh して fire

tail ~/.ssh/config
ForwardX11 yes

実行してみる

上記の様にクライアント側で設定しなかった場合は-XY オプションを追加する。

$ ssh $hostname
[hostname] $ firefox &
../../../_images/firefox_via_x11.png

X Window経由でFirefoxを表示

]]>
Sat, 10 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/10/ethtool.html http://blog.masu-mi.me/2015/01/10/ethtool.html <![CDATA[ethtoolを知りました]]> ethtoolを知りました
ethtool - Display or change ethernet card settings

ifconfigで表示されたネットワークデバイスethX の詳細を表示したり値を設定(-s)出来る。 以下がVirtualBox上のUbuntuで実行した結果。この環境では設定に失敗した。

$ sudo ethtool eth1
Settings for eth1:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: No
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  Not reported
        Link partner advertised pause frame use: No
        Link partner advertised auto-negotiation: No
        Speed: 1000Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: Unknown
        Supports Wake-on: umbg
        Wake-on: d
        Current message level: 0x00000007 (7)
        Link detected: yes
$ sudo ethtool -s eth1 speed 100

設定ファイル

Cent系

ls
/etc/sysconfig/network-scripts/ifcfg-eth0

Ubuntu

ls
/etc/network/interfaces
]]>
Sat, 10 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/04/start_zookeeper.html http://blog.masu-mi.me/2015/01/04/start_zookeeper.html <![CDATA[ZooKeeper入門を読んだ]]> ZooKeeper入門を読んだ

ZooKeeperは糞だって言われるけどわからなかったから、ZooKeeperによる分散システム管理 読んだ。 ZooKeeperはコーディネーションサービスに位置づけられている。詳細は以下を読むと良さそう。

読んで感じたZooKeeperの不便な点

  • JavaAPIで、Watch, 非同期ハンドラがオブジェクトで記述が長い

  • 非同期APIでのリトライは別スレッド実行
    • リトライ前に別の更新があると意図せず上書きしてしまう
    • リトライ前に整合性の確認が必要
  • トランザクションはZnode単位
    • znode間に依存関係が存在する場合、整合性を保つのが難しい
  • ACLがZnode単位で子ノードに継承されない
    • マルチテナントのACL管理の責任がクライアント側になる
  • 外部資源がある時にZooKeeperの値と整合性を保つのが難しい
    • フェンシングで解決する
  • ZooKeeper各サーバで提供する時点が異なる可能性がある
    • ZooKeeperの変更通知などはZooKeeperからのみ取得する
      • クライアント(A)が変更通知を受け取る(Watch)
      • Aが別のクライアント(B)に変更通知
      • Bから見たZooKeeperがAの受け取った変更通知前の可能性がある
    • syncを実行して最新の状態にする

  • クラスタ再構成時アンサンブル内のズレにより歴史が逆戻る可能性がある
    • 起動順序に注意する
    • ズレを解消してから再構成を行なう
  • 更新は同期実行され、その際に参照もロックされる

  • 誤ったリーダを認識する時間が短期間存在しうる

  • 新リーダ選出時に大幅に歴史が遅れているとSnapshotコピーが発生する
    • リーダからコピーされネットワークの最適化はない
  • DC, 電源系統毎の最低ノード数などの設定が難しい
    • 障害を見越したクラスタが作りづらい
    • group, weight で似た事が可能だが複雑な事は出来ない
  • クライアントは起動時に識別子解決する
    • サーバを再構成したらクライアントの再起動が必要
  • ZooKeeperアンサンブル自体は静的に構成する必要がある
    • 動的再構成は3.5系
    • 動的構成する場合は事前に設定が必要
  • 専用hostsを推奨しているがネットワーク冗長化のコストが高くなりそう

じゃあ別のオプションはって話だけど、わかってない。以下を読んで勉強しながら情報整理する。

]]>
Sun, 04 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/04/zab.html http://blog.masu-mi.me/2015/01/04/zab.html <![CDATA[Zabの概要]]> Zabの概要

ZooKeeperは同意アルゴリズムにPaxos派生のZabを用いている。 簡易資料は以下が良さそうなので後で読みます。

アンサンブルを構成する各ノードは以下に分類される。

Leader(L)
  • リーダーは、マスタデータを持つ
  • リーダー選出・変更投票に参加する(PARTICIPANTサーバ)
  • リーダーから外れたらフォロワーとなる
Follower(F)
  • フォロワーはリーダーの状態を持つ(Learner)
  • リーダー選出・変更投票に参加する(PARTICIPANTサーバ)
Observer(O)
  • オブザーバーはリーダーの状態を持つ(Learner)
  • リーダー選出・変更投票に参加しない

Zabでは過半数のアンサンブル(Quorum)に支持されているLeaderが存在している前提で動くらしい。 リーダーは多数決で行う。Zabでは、この状態で以下のように行う。

  1. L->F: PROPOSAL(トランザクションログを同期書き込み)
  2. F->L: ACK(書き込み成功したら返信を行う)
  3. L->F: COMMIT(変更操作を有効にする), L->O: INFOM(Observerに通知)

オブザーバは更新合意の投票に参加せずリーダーに選出されることもない。 これは更新のオーバヘッドを抑えつつ読み込みスケールさせるため。

トランザクションログ書き込みメモ

  • 事前に大きめなファイルを確保して、読み込みアクセスをシーケンシャルにする

  • 変更保証のために同期書き込みがクリティカルパス上で発生する
    • 専用デバイスにする事が推奨される
]]>
Sun, 04 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2015/01/03/start_zookeeper.html http://blog.masu-mi.me/2015/01/03/start_zookeeper.html <![CDATA[ZooKeeper 起動]]> ZooKeeper 起動

ZooKeeper を試してみた。

試してみる(スタンドアロン)

OSXで試すだけ試すには以下を実行する。

インストールして、フォアグラウンドで動かす。別ターミナルからクライアントとしてアクセスもしてみる。

brew install zoookeeper
brew link zookeeper
zkServer
# 特に指定せずに実行すればサブコマンド・デフォルト設定ファイルが確認出来る
JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}

zkServer start-foreground # フォアグラウンドで実行
zkServer start            # 通常の実行(tmux上だと無理め)
# 別ターミナル
zkCli
> ls /
[zookeeper]
> help # zkCliで使用可能なコマンドを確認する

クォラムモードで動かす

以下を実行して設定ファイルなどを整えて実行する。 3.5系から動的構成が出来るようなので試したいけど、インストールが上手く行かないから後回し。

ZooKeeperの静的構成は設定ファイルにアンサンブルを構成するホスト全体の情報を記述する。 フォーマットは server.x=host:quorum_port:leader_selection_port[:observer] になる。

for d in `echo `1 2 3`
do
  mkdir -p host$d/data
  cat /usr/local/etc/zookeeper/zoo.cfg | \
  perl -e '$_ =~ s/^dataDir=.*$/dataDir=\.\/data/' -np > ./host$d/zoo.cfg
  echo $1 > ./host$d/
  # 設定ファイル末尾にZooKeeperのクォラムを構成するhostsの設定を追記する
  echo """
  server.1=127.0.0.1:2222:2223
  server.2=127.0.0.1:3332:3333
  server.3=127.0.0.1:4442:4443
  """ >> ./host$d/zoo.cfg
done
# 同hostで実行するのでportが衝突しないように clientPort を書き換える
vim ./host1/zoo.cfg ./host2/zoo.cfg ./host3/zoo.cfg

# 実行する
for dir in ls ./host*
do
  (cd $dir && \
  /usr/local/Cellar/zookeeper/3.4.6/libexec/bin/zkServer.sh start ./zoo.cfg)
done

# clientを実行する
zkCli -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
Connecting to 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
Welcome to ZooKeeper!
JLine support is enabled

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 0] quit
Quitting...
]]>
Sat, 03 Jan 2015 00:00:00 +0900
http://blog.masu-mi.me/2014/12/14/admin_user.html http://blog.masu-mi.me/2014/12/14/admin_user.html <![CDATA[ユーザー管理]]> ユーザー管理

user, group関係のファイル

user, groupの情報が保存されてたり対応するpassが保存されているファイル達は下の4つ。

# user
/etc/passwd
/etc/shadow
# group
/etc/group
/etc/gshadow

コマンド(低レイヤ)

ファイルの形式チェック排他で編集可能

# user
pwck
vipw (-s)
# group
grpck
vigr (-s)

コマンド(高レイヤ)

設定ファイルに触れずに設定を変更するための高レイヤコマンド

adduser, passwd
newusers, schpasswd
addgroup
chsh, chfn
usermod, adduser
]]>
Sun, 14 Dec 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/11/23/hosts_and_resolv.html http://blog.masu-mi.me/2014/11/23/hosts_and_resolv.html <![CDATA[hosts, resolvファイル]]> hosts, resolvファイル

最近Linuxシステム[実践]入門を読んでいる。 その中でドメイン名解決の設定ファイルで知らなかったことがあったので記録する。

ファイル達

/etc/hosts, /etc/host.conf, /etc/resolv.conf が解決の設定に関係している。 ちゃんとman を読まないと駄目だなぁって思った。

/etc/hosts
IPアドレス ドメイン の形式で名前を解決するためのファイル
/etc/resolv.conf
DNSの向き先を設定したりする
/etc/host.conf
DNSで解決するかhostsファイルで解決するかの順序を決めるなど、名前解決全体の設定を行う。

わかってなかったresolv.confの設定項目

項目 内容
resolv.conf: domain 省略したドメイン名を補完する名前を追加する
resolv.conf: search 省略したドメイン名を補完する候補を記述する

search, domain 共にドメイン名解決時の保管に使われる。

`` sourcecode:: bash

$ nslookup www # ... ** server can’t find www: NXDOMAIN $ sudo vim /etc/resolv.conf $ tail /etc/resolv.conf domain yahoo.co.jp $ nslookup www # ... www.yahoo.co.jp canonical name = www.g.yahoo.co.jp. Name: www.g.yahoo.co.jp Address: 183.79.196.239 $ tail /etc/resolv.conf search yahoo.co.jp $ nslookup www # ... 同上

何が異なるかというと、search はサブドメインの補完候補を複数指定できる。 1つしか保管しないのであればdomain が良さそう。 また search で指定した場合は、補完リストの左から検証されて見つかったものに決まるようだ。

]]>
Sun, 23 Nov 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/11/17/memo_network_commands.html http://blog.masu-mi.me/2014/11/17/memo_network_commands.html <![CDATA[最近使ったネットワークコマンド]]> 最近使ったネットワークコマンド

最近、ATSを導入した。その際にネットワークコマンドを色々と触ったので忘れない様にメモをする。 やりたい事から対応するコマンド・オプションが判断できれば良い。

使ったコマンドは以下。ip コマンドが推奨されているので本当はそっちの方が良い場合もありそう。

TCP パケットを確認したい

-wpcap savefile として保存できる。

tcpdump -Z${USER} -i eth1 -A port 80 and host
tcpdump -Z${USER} -i eth1 -A port 80 and host -w apache.80.pcap

検証のためにSSH トンネルを掘ってアクセスする

sshでwell-known port のトンネルを掘る。 ssh-agent を使っているとsudoの際にSSH_AUTH_SOCK がなくなってしまうので以下みたいにした。

# こんなかんじでssh-agent 使っている
ssh-add $HOME/.ssh/id_rsa
sudo SSH_AUTH_SOCK=$SSH_AUTH_SOCK ssh -Lg 80:${target_host}:80 ${USER}@${step_host}

対象ドメインの証明書情報を確認する

以下みたいな感じでクライアント(s_client)として証明書を表示して確認する。

echo ''| openssl s_client -connect ${target_domain_name}:443 -showcerts | grep "/[C1]"

開いているポートの確認する

ポートの状態を確認する。

$ sudo lsof -Pi
...
$ # ポート番号を指定する
$ sudo lsof -Pi:80
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
apache2 1861     root    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)
apache2 1864 www-data    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)
apache2 1865 www-data    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)

ネットワークのコネクション情報を確認する

TCP限定でネットワークコネクションを表示するには-t を用いる。(UDPは-u)

$ netstat -ntop
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 10.0.2.15:22            10.0.2.2:53046          ESTABLISHED 1172/sshd: vagrant  keepalive (2678.84/0/0)
]]>
Mon, 17 Nov 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/11/15/commands_concerned_with_man.html http://blog.masu-mi.me/2014/11/15/commands_concerned_with_man.html <![CDATA[commands-concerned-with-man]]> commands-concerned-with-man

初歩的なことはman が頼りになる。調べ方のメモを残す。

man にちなむコマンド達

-bash-4.1$ apropos whatis
apropos              (1)  - search the whatis database for strings
makewhatis           (8)  - Create the whatis database
whatis               (1)  - search the whatis database for complete words

aproposman -k の違いは複数キーワードを検索条件にした時に現れる。

apropos:
複数キーワードで検索すると1つの結果として提示される
man -k:
複数キーワードで検索するとそれぞれの結果が別々に表示される
]]>
Sat, 15 Nov 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/11/15/install_apache_httpd.html http://blog.masu-mi.me/2014/11/15/install_apache_httpd.html <![CDATA[apache httpd をインストールした]]> apache httpd をインストールした

記録: Ubuntu にApache httpd を入れた。

$ sudo apt-get update
$ sudo aptitude search apache | less
$ sudo aptitude install apache2
$ apache2 -V
$ sudo lsof -Pi:80
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
apache2 1861     root    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)
apache2 1864 www-data    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)
apache2 1865 www-data    3u  IPv4   8384      0t0  TCP *:80 (LISTEN)
$ sudo ps aux | grep apache
root      1861  0.0  0.6   5428  2580 ?        Ss   08:14   0:00 /usr/sbin/apache2 -k start
www-data  1863  0.0  0.4   5200  1756 ?        S    08:14   0:00 /usr/sbin/apache2 -k start
www-data  1864  0.0  0.7 226948  2704 ?        Sl   08:14   0:00 /usr/sbin/apache2 -k start
www-data  1865  0.0  0.7 226948  2708 ?        Sl   08:14   0:00 /usr/sbin/apache2 -k start
vagrant   1952  0.0  0.1   2136   744 pts/0    S+   08:32   0:00 grep --color=auto apache
$ ifconfig |grep inet
inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feb5:756c/64 Scope:Link
inet addr:192.168.33.10  Bcast:192.168.33.255  Mask:255.255.255.0
inet addr:127.0.0.1  Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host

init.dに追加されているのでコマンドの確認をした。 serviceの方が良いらしい のでserviceでも確認。 ラップされているだけの様で同じ結果になる。

$ egrep -e '^[ | sa-zA-Z-]+\)$' /etc/init.d/apache2
      start)
      stop)
      graceful | reload | force-reload)
      restart)
      start-htcacheclean)
      stop-htcacheclean)
      status)
 $ service apache2
  * Usage: /etc/init.d/apache2 {start|stop|restart|reload|force-reload|start-htcacheclean|stop-htcacheclean|status}
]]>
Sat, 15 Nov 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/10/03/test_json_schema.html http://blog.masu-mi.me/2014/10/03/test_json_schema.html <![CDATA[JSON Schema の感じをつかむ]]> JSON Schema の感じをつかむ

JSON Schema を使ってみた。今回の内容は2つ。

  • JSON Schema への参考資料のリンクを整理する
  • PHPでバリデーションのサンプルをメモする

JSON Schema について

JSON はJavaScript のオブジェクト表現をベースにしたデータ記述言語で様々なデータ構造を記述できる。 データがあると型・メタ情報を扱いたくなる。JSON データに対するスキーマ定義の仕様が幾つかある。その有力候補の1つがJSON Schema だ。

JSON Schema 資料集

公式ドキュメント は以下のdraftへのリンクを掲載している。

また、JSON Schema では以下の形式を利用している。

以下に JSON Schema: core definitions and terminology のアブストを翻訳する。

JSON Schema は、メディアタイプ”application/schema+json”・JSON データの構造を定義するJSON に基づいた形式を定義する。 JSON Schema は、どのようなJSON データが与えられたアプリケーションに要求され、またどのように作用するのか、について契約する。 JSON Schema は、JSON データに関するバリデーション・ドキュメンテーション・ハイパーリンクナビゲーション・相互作用制御を定義する様に意図している。

JSON Schema defines the media type “application/schema+json”, a JSON based format for defining the structure of JSON data. JSON Schema provides a contract for what JSON data is required for a given application and how to interact with it. JSON Schema is intended to define validation, documentation, hyperlink navigation, and interaction control of JSON data.

PHP で使ってみる

以下のJSON Schema を準備してPHPでバリデーションを試してみた。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://masu-mi.me/url/of/this/schema.json",
  "title": "サンプル用スキーマ",
  "description":"長めの説明",
  "type": "object",
  "properties": {
    "id": {
      "description": "リソースのID。システム中一貫して用いられる。",
      "type": "string",
      "maxLength": 40
    }
  },
  "required": [
    "id"
  ]
}

PHP実装をインストールする

定番っぽいjustinrainbow/json-schemacomposer でインストールする。

composer init
composer require justinrainbow/json-schema ~1.3
composer install

PHP でバリデーションのコードを書く

書いたコードは以下の通り。

<?php
require 'vendor/autoload.php';

$json = '{"a":1, "b":2}';
// JSON Schems を"schema.json"に記述しておく
$schema = file_get_contents('./schema.json');
$v = new JsonSchema\Validator;
$v->check(json_decode($json), json_decode($schema));

実行結果を見る

実行結果は以下。結果を見るとrequiredid が必須って怒られているのでうまく行っていそう。

$ php -d open_basedir=/ ./test.php
array(1) {
  [0] =>
  array(2) {
    'property' =>
    string(0) ""
    'message' =>
    string(27) "the property id is required"
  }
}
]]>
Fri, 03 Oct 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/09/30/use_tmpfs.html http://blog.masu-mi.me/2014/09/30/use_tmpfs.html <![CDATA[tmpfs を使ってみた]]> tmpfs を使ってみた

ファイルシステムのマウントとかした事がなかったので練習。tmpfs をマウントして外すだけ。 消して良い様な事でI/Oが邪魔になっている箇所に使ったり(ex. varnish )。

マウントする

$ mkdir ~/tmpdisk
$ sudo mount -t tmpfs memdisk ~/tmpdisk

マウント箇所を確認する

$ mount -l
...
memdisk on /home/masumi/tmpdisk type tmpfs (rw)
$ cat /proc/mounts
...
memdisk /home/masumi/tmpdisk tmpfs rw,relatime 0 0

アンマウントする

$ sudo umount ~/tmpdisk
$ rmdir ~/tmpdisk
]]>
Tue, 30 Sep 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/09/23/the_art_of_concurrency_6-section.html http://blog.masu-mi.me/2014/09/23/the_art_of_concurrency_6-section.html <![CDATA[並行コンピューティング技法<6章>: 並列和・プリフィックススキャン]]> 並行コンピューティング技法<6章>: 並列和・プリフィックススキャン

並行コンピューティング を読んでいる。 6章では並列和、プリフィックス・スキャンを通して並列計算について議論している。 この2つは単純で理解しやすく分析される機会も多いため、この2つは並列アルゴリズムの1つの指標にもなっているらしい。

何千ものプロセッサを保持するPRAM(Parallel Random Access Machine) に適した並列アルゴリズムとしてデータ分解のスタイルを紹介している。 またプレフィックス・スキャン が抽象度が高いため、応用的なアルゴリズム(セレクション・配列のパッキング)を紹介している。

流れとしてはData Parallel Algorithms(Communications of the ACM, 1986) の議論を下地にしている様子。

この論文では並列和・プリフィックススキャンを議論し、何千ものプロセッサが存在するPRAM(Parallel Random Access Machine) で適切な並列アルゴリズムスタイルを提示しようとしている。 アブストは以下。

マルチプロセッシングで使われる操作並列スタイル(タスク分解, task decomposition) とは対照的に、何千ものプロセッサを使った並列計算では、概してデータ並列スタイル(データ分解, data decomposition) でプログラムされる。一見本質的に連続する様に思える問題においてもデータ並列スタイルは成功しており、このスタイルが以前から考えられていたよりも遥かに広い適応性があることを示している。

Parallel computers with tens of thousands of processors are typically programmed in a data parallel style, as opposed to the control parallel style used in multiprocessing. The success of data parallel algorithms-even on problems that at first glance seem inherently serial-suggests that this style of programming has much wider applicability than was previously thought.

PRAM(Parallel Random Access Machine)
1章で出てきたが並列アルゴリズムを議論する時に使われる抽象機械 の1つ
並列和
ベクトル(1次元配列)の全要素を合計する問題(アウトプットは1つの値)
プレフィックス・スキャン

ベクトル(1次元配列)の全ての部分和を求める問題(アウトプットは1次元配列)

  • 包含的プレフィックススキャン: n番目以前の全ての値の演算結果が各要素に格納される
  • 排他的プレフィックススキャン: (n-1)番目以前の全ての値の演算結果が各要素に格納される
]]>
Tue, 23 Sep 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/09/12/display-collapse.html http://blog.masu-mi.me/2014/09/12/display-collapse.html <![CDATA[iPhone, MBPでの表示崩れ対策]]> iPhone, MBPでの表示崩れ対策

昔からiPhoneで見ると崩れる事には気づいていた。会社のMBPで見ても崩れることに気がついた。 対応することにした。

現象は2つあった。

MBP, iPhoneで表示すると文字が巨大化する

tinkererの標準テンプレート: minimal5 を使っていたのだけど、そのcssで以下が指定されていた。 このメディアクエリを削除したら問題がなくなった。

@media screen and (-webkit-min-device-pixel-ratio: 2)
{
    body {
        font-size: 200%;
    }
}

参考

メディアクエリについて書かれていた。

iPhoneで左に寄って表示される

tinkererのテンプレートの大元にあるboilerplate/layout.html で指定されているviewport の設定がうまくなかった様でした。 なので以下を追記して、元のviewport設定を削除した。

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

追記して多重定義するとiPhoneのChromeでは解決した。しかしSafariでは解決ならず。 そのため、ちゃんと削除した。元のboilerplate/layout.html に直接書かれていたので、該当要素は継承しても変更できなかった。 そのため読まれないように、プロジェクトディレクトリに同じ名前で配置して要素部分だけ上書いた。

vimshell% tree _themes
_themes
├── boilerplate
│       └── layout.html
└── orig-minimal5
           ├── layout.html
           ├── social.html
           ├── static
           │       └── minimal5.css_t
           └── theme.conf

参考

今回はやっつけ対応だけど、ちゃんとやるには下が参考になりそう。

  • viewportの解説 <http://ipn3g.com/web/study3.html>
  • なんか綺麗にまとまっているスマホ対応 <http://tech.nitoyon.com/ja/blog/2013/02/15/viewport/>
]]>
Fri, 12 Sep 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/09/09/explore-internal-git.html http://blog.masu-mi.me/2014/09/09/explore-internal-git.html <![CDATA[GitのオブジェクトDBと索引]]> GitのオブジェクトDBと索引

Gitの内部構造の概略と調べるのに必要な箇所を整理する。 なおソースへのリンクはv2.1.0-rc2 を参照している。 Git について勉強した事がなかったので調べた。

Gitの概要

Git は分散型バージョン管理システムと呼ばれている。

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

ref. http://git-scm.com/

2層のアーキテクチャ

Git は次の2層アーキテクチャで実現されている。

  1. 連想記憶ファイルシステム(content-addressable filesystem)

    Git は対象をオブジェクトの集まりとして捉え管理している。

  2. VCS ユーザ・インタフェース(VCS user interface)

    参照・シンボリック参照と呼ばれる要素を用いてbranch, tag などを表現している

これらは、プロジェクトルート[1] に存在する.git ディレクトリの中に収まっている。

コアファイルの構成(.git/)

.git ディレクトリは以下の様になっている。 行った操作履歴により存在するファイルは異なる[#other_files]_が基本的な構造は変わらない。 自分の環境を例に出す。

$ (cd path/to/proj_root  && tree -L 1 .git)
.git
├── COMMIT_EDITMSG
├── HEAD
├── ORIG_HEAD
├── branches
├── config
├── description
├── hooks
├── index
├── info
├── logs
├── objects
└── refs

上記のファイル・ディレクトリが<連想記憶ファイルシステム(CAF)/VCS ユーザ・インタフェース(VCSUI)>に関係が強いか? ファイル、ディレクトリなら格納されるファイルの種類、目的などの概要を整理すると以下にになる。

名前 関連 ファイルタイプ 概要
HEAD VCSUI file: ref|sym_ref ブランチ・コミットなど今のHEADの位置を指す
index CAF file: index stage に対応するcacheされているblobへの参照が保持されている
logs VCSUI dir : log commit が作成された時の変化(前後のcommit)を記録している
objects CAF dir : object オブジェクトを保持する
refs VCSUI dir : ref commit, tag への参照を保持する
ORIG_HEAD VCSUI file: ref(only?) マージなど危険な操作の直前のコミットを指す
COMMIT_EDITMSG VCSUI file: text 前回のコミットメッセージが含まれている
hooks VCSUI dir : scripts gitにhookする実行ファイルを配置
branches ? dir : ? 調べてない
description ? file: ? 調べてない
info ? dir : ? 調べてない

システムの骨格を理解するのが目的なので触れるのは ORIG_HEAD より上に並べたファイル群に絞る。

Git システムを構成するファイルの種類

前節でファイルタイプとして書いたように、Git システムは幾つかの種類のファイルで作られている。 ここでは、ファイル・タイプを2層のアーキテクチャで区分けして説明する。

content-addressable filesystem を支えるファイル

Content-Addressable Filesystem は、作業ディレクトリのツリー情報(ファイル内容・メタ情報・ディレクトリの格納関係)・変更履歴(コミット)・タグ、を全て格納しており、 格納しているデータベース部分・次に格納する情報をまとめたインデックス、の2つで構成されている。

  • Git Objects 管理対象になっているファイル・ディレクトリ・コミット・タグなど全てを表現する
  • Index git 運用でのstage に対応するObjectの一覧を保持する

Git Objects

Gitプロジェクトの歴史を4種類のオブジェクトの組み合わせで表現している 。 各構造体の定義を見るとstruct object を最初のメンバに含んだ形になっている。

タイプ名 表現対象 関連ソース
blob ファイルの内容 https://github.com/git/git/blob/v2.1.0-rc2/blob.h#L8-L10
tree ディレクトリが保持するファイル名とファイルのメタデータ https://github.com/git/git/blob/v2.1.0-rc2/tree.h#L8-L12
comit コミット https://github.com/git/git/blob/v2.1.0-rc2/commit.h#L16-L23
tag タグ(オブジェクトに対するコメント付きの参照) https://github.com/git/git/blob/v2.1.0-rc2/tag.h#L8-L13

Objectタイプ名と表現対象を連結しzlibで圧縮した内容を持つファイルになる。

そのファイルの置かれる場所はファイルの内容をsha1 を取ることで名前が一意に決まる。 具体的にはハッシュ値の上位2桁が.git/objects 以下のディレクトリ名に対応し残りの38桁がファイル名になる。 tree .git/objects とかするとハッシュに対応するようにファイルが置かれている事がわかる。 この “ディレクトリ名+ファイル名” をgit-cat-file [3] すると中身を読むことが出来る。

$ (cd path/to/proj_root && tree .git/objects)
# とてもたくさんのファイルが流れてく
$ git cat-file -p ${SHA1_FILE_NAME}

ファイルの内容はblobが保持する。blob 以外のオブジェクトは他のオブジェクトのハッシュ値を経由し関係を保持する。

作業ディレクトリのツリー構造はtree オブジェクトが保持するが以下の様にリンクで実現されている。

http://git-scm.com/figures/18333fig0901-tn.png

コミット履歴についても同様でcommit オブジェクトの持つリンクで実現される。

http://git-scm.com/figures/18333fig0903-tn.png

ref. http://git-scm.com/book/en/Git-Internals-Git-Objects

tag オブジェクトの役割はgit-tag で作られるタグと即座には対応しない。 公式資料 にある通り実態は2種類ある。

タグは後述する参照がオブジェクトのハッシュ値をrefs/tags 以下に保持することで実現される。 この時どのようなオブジェクトでもタグ付けが可能だが、タグを生成するときにコメントを記述した場合には、対象オブジェクトを指すtag オブジェクトが生成される。 この時、タグに対応した参照はtag オブジェクトを指している。

Index

stage に対応するblob オブジェクトへの一覧が格納されている。 サブディレクトリが存在してもtree を介した表現にはならない。 登録されたファイルのプロジェクトルートからの相対パスとblob オブジェクトの名前(sha1) が格納されている。 このためGit では空ディレクトリをトラック出来ないという制約に繋がる。

git ls-files –stage で内容を確認できる。

$ git ls-files --stage

VCS User Interface を支えるファイル

  • 参照(Git References) Commitオブジェクトの名前を含むテキストファイルになっている
  • シンボリック参照 参照ファイルのファイルパスを含む
  • ログ Commitの変更を記録しているテキストファイル

参照

オブジェクトの名前に対応するハッシュ値を保持したテキストファイル

オブジェクトは名前がハッシュ値になってしまうので人間から指定が識別しづらい。 そこで、重要なオブジェクトを人間が扱えるように保持するファイルが役に立つ。 後述するシンボリック参照と共にVCS ユーザ・インタフェースを支えている。

主に .git/refs 以下に配置される。

$ find .git/refs -type f
.git/refs/heads/master
.git/refs/remotes/origin/master
.git/refs/tags/test
$ git cat-file -p `cat .git/refs/heads/master`
http://git-scm.com/figures/18333fig0904-tn.png

ref. http://git-scm.com/book/en/Git-Internals-Git-References

シンボリック参照

参照に対するエイリアスとして働き“ref: “ を先頭に持つテキストファイル
$ cat .git/HEAD
ref: refs/heads/master

Log

特定のブランチ, HEADなどの指す先が変更された時の記録で、各変更前後のcommit を保持している。

脚注

[1]管理対象にしているトップディレクトリ(基本的には git init したディレクトリ)
[2]状況により packed-refs なども存在するなど以下と必ず一致するとは限らない。
[3]Git にはObject ファイルの中身を確認する低レイヤコマンド(配管(Plumbing)と呼ばれる)がある。
]]>
Tue, 09 Sep 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/07/21/__halt_compiler.html http://blog.masu-mi.me/2014/07/21/__halt_compiler.html <![CDATA[__halt_compiler の使い方]]> __halt_compiler の使い方

概要

PHP::__halt_compiler の挙動・使い方についてまとめる。

要点

__halt_compiler
  • PHPコンパイラを停止するコンパイル時命令
  • コンパイラ命令の1つ
  • 一番外側のスコープで実行可能
__COMPILER_HALT_OFFSET__
  • __halt_compiler が使われた翻訳単位で使用可能なマジック定数
  • コンパイル停止オフセット

サンプル

自分自身のコンパイル中止以後を出力する。

<?php
echo file_get_contents(__FILE__,false,null,__COMPILER_HALT_OFFSET__);
__halt_compiler();DATA PART

用途

例えばcomposer.phar などのインストーラの様に、1ファイルでデータ部実行部を持ちたい時に使う。 Phar が生成するアーカイブファイル内部で使われている。

]]>
Mon, 21 Jul 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/07/20/start_php_composer.html http://blog.masu-mi.me/2014/07/20/start_php_composer.html <![CDATA[OSXでComposerを導入した]]> OSXでComposerを導入した

OSXでcomposer 導入した際に引っかかった内容をメモしておく。composer はJSONでコンポーネントを管理するツール。

起きた事

  1. homebrewComposer をインストールしようとすると PHP53, PHP54 , PHP55 のどれかを brew でインストールする事を要求される。
  2. PHP55 のビルドで失敗

原因

Command Line Tools がOS Updateで無くなっていた。昔と違い Xcode からインストール出来なくなっていた。

解決した手順

以下を素直に叩く。 xcode-selectXcode のバージョンを切り替えるのに使うらしい。

$ # xcode-selec
$ xcode-select --install
$ brew install php55
$ brew install composer
]]>
Sun, 20 Jul 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/28/php_signal.html http://blog.masu-mi.me/2014/06/28/php_signal.html <![CDATA[PHPでシグナルを扱う]]> PHPでシグナルを扱う

PHP でシグナルを扱うには プロセス制御 を利用する。 その際に必要な ticks 関数の設定についてメモする。

その前に

pcntl が使えるか確認する。以下で実行可能か確認しておく。

$ php -i | awk /[p]cntl\ support/
pcntl support => enabled

OSXで標準で入っているのはコンパイルオプション –enable-pcntl が有効になってなかった。 公式に従ってインストールしてしまうphpenv で有効なバージョンを入れる。 phpenv でインストールした。

# phpenvでbuildする時のオプションの確認
$ awk /pcntl/ ~/.phpenv/plugins/php-build/share/php-build/default_configure_options
--enable-pcntl
$ phpenv intall 5.5.5

declare(ticks = 1)を有効にする

シグナルハンドラの登録は pcntl-signal を使う。 で 4.3.0以降は declare(ticks = 1); をコードブロックに記述しないと動かない。

これはシグナルのディスパッチを ticks 関数の pcntl_signal_dispatch が実行される事でシグナルハンドラが叩かれるのだけど、 ticks の仕組みは効率が悪いって事で、4.3.0以降では declare で明記が必要だから。 なのでこんな感じのコードにすると動く。

<?php
// test.php
declare(ticks = 1);
pcntl_signal(SIGHUP, handler);
function handler($signo) {
  echo 'in '. __FUNCTION__. PHP_EOL;
  exit(1);
}
while (true) {
  echo 'in loop. '. __FILE__. PHP_EOL;
  sleep(1);
}

動かした感じ。

$ php -d open_basedir=/ test.php
in loop test.php
in loop test.php
in loop test.php
...
# 別ターミナルで
$ kill -s 1 $PID
# 動いてた方が応えている
in handler

declareの位置を注意する

グローバル環境で declare 設定されると呼び出されたコードブロックの中でも設定は有効。 だけど呼び出された側のグローバル環境で設定しても呼び出し元には影響しない。 なので下のコードはSIGHUPを受け取ってくれない。

<?php
// test.php
pcntl_signal(SIGHUP, handler);
function handler($signo) {
  echo 'in '. __FUNCTION__. PHP_EOL;
  exit(1);
}
require 'required.php';
while (true) {
  echo 'in loop. '. __FILE__. PHP_EOL;
  sleep(1);
}
<?php
// required.php
declare(ticks = 1);
]]>
Sat, 28 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/27/otool_vim.html http://blog.masu-mi.me/2014/06/27/otool_vim.html <![CDATA[ruby のupdateをしたらvimが動かなくなった]]> ruby のupdateをしたらvimが動かなくなった

brewruby のバージョンを上げた。 何も考えずにコメントに出てきた通りに何かしてしまった。 でvim 開いたら下な感じ。

$ vim
dyld: Library not loaded: /usr/local/lib/libruby.2.0.0.dylib
  Referenced from: /usr/local/bin/vim
  Reason: image not found
Trace/BPT trap: 5
$ uname -a
Darwin air-trout.local 13.2.0 Darwin Kernel Version 13.2.0: Thu Apr 17 23:03:13 PDT 2014; root:xnu-2422.100.13~1/RELEASE_X86_64 x86_64
$ sw_vers
[No write since last change]
ProductName:    Mac OS X
ProductVersion: 10.9.3
BuildVersion:   13D65

メッセージ的に /usr/local/lib//libruby.2.0.0.dylib が無いだけ。 似たファイル見つけた結果、 brew にあるけどリンクが消えているだけと判断した。 バージョン変えてリンク切れってだけなので作り解決した。

$ ls -la /usr/local/lib/libruby.2.1.0.dylib
lrwxr-xr-x  1 masumi  admin  46 Jun 22 00:42 /usr/local/lib/libruby.2.1.0.dylib -> ../Cellar/ruby/2.1.2_1/lib/libruby.2.1.0.dylib
$ ln -s /usr/local/Cellar/ruby/2.0.0-p0/lib/*.dylib /usr/local/lib/
ln: /usr/local/lib//libruby.dylib: File exists

ついでな話しだけれど何か動かなくてリンクが駄目そうな時にOSXでは以下のコマンドが使える。

$ otool -L `which vim`
/usr/local/bin/vim:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
        /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
        /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 20.0.0)
        /usr/local/lib/libruby.2.0.0.dylib (compatibility version 2.0.0, current version 2.0.0)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
        /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.14.0)
        /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 59.0.0)
        /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.19.0)
        /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0)

ldd な感じで、ときどき頼る。 ottol はオプションでシンボリックテーブル見たりテキスト領域読めたりとバイナリ解析でお世話になるであろうツールです。

バイナリアンかっこいい!!

]]>
Fri, 27 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/23/update_pkgs_with_easy_install.html http://blog.masu-mi.me/2014/06/23/update_pkgs_with_easy_install.html <![CDATA[easy_installのpkgをまとめてupdateした]]> easy_installのpkgをまとめてupdateした

Marvericks にアップデートしたら virtualenv がエラーを吐くようになった。 とりあえずインストールしたのは easy_install だったので easy_install 経由で入れているパッケージ群を全てアップデートした。 そしたら解消された。ラッキーである。技術者としてはあまり勧められない態度だけど、どう解決していいかアプローチが見えなかった。

easy_install -U `python -c "for dist in __import__('pkg_resources').working_set: print dist.project_name"`

アプローチにちては今後考えるにして、これでMarvericksにアップデートした後の問題は gcc, ghcVirtualBox のバージョン確認機能に絞られた。

]]>
Mon, 23 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/22/update_to_marvericks_cause_delete_link_of_homebrew.html http://blog.masu-mi.me/2014/06/22/update_to_marvericks_cause_delete_link_of_homebrew.html <![CDATA[MarvericksにアップグレードしたらHomebrewのリンクが消えた]]> MarvericksにアップグレードしたらHomebrewのリンクが消えた

Marvericks にアップグレードしたら brew で入れたコマンドが使えなくなっていた。 brew ls の実行結果は以下で brew は消えてるコマンド達を認識している。

vimshell% brew ls
ack                   leiningen               ossp-uuid
antlr                 libevent                pcre
...
...

でどうなっているか知りたくて以下を見たら。 brew 以外がいなかった。

$ ls /usr/local/bin/
brew

link が消えているという事で以下を実行した。

$ brew list | xargs -I{} brew upgrade {}
$ brew list | xargs -I{} brew unlink {} --force
$ brew list | xargs -I{} brew link {} --force

これで殆どのコマンドが復活したけれど、いくつか unlink に失敗するパッケージがあった。 これは unlink するファイルを homebrew が解決出来にないことを示している。 理由は Qiitaに書かれていた

これらのパッケージは以下の様に一旦アンインストールして入れ直した。

$ brew unlink ${PACKAGE} --force
Error: ${PACKAGE} has multiple installed versions

$ brew uninstall ${PACKAGE}
$ brew install ${PACKAGE}

だけど ghc, gcc が上手く行かずに一度 uninstall したままビルド出来ていない。 ghcgcc 依存なので gcc が解決すれば良いのだけど解決出来ずにいったん放置になっている。

]]>
Sun, 22 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/07/try_boot2docker.html http://blog.masu-mi.me/2014/06/07/try_boot2docker.html <![CDATA[boot2docker を導入する時にNAT設定が必要だった]]> boot2docker を導入する時にNAT設定が必要だった

DockerをOSXから使える様にまとめてくれている エントリ があった。

以前 Docker に挑んで少し触ったくらいで追ってなかったのだけれど、 エントリによると最近は boot2docker なんてコマンドがあり Docker 用に色々やってくれるらしい。 dokku で個人 Heroku 作りたいのもあり試してみた。

エントリ通りにしたら2箇所で躓いたのでメモしておく。

トラブル

  1. OSX上で docker version が失敗した
  2. docker pull dockerfile/ghost が失敗した
$ docker version
Client version: 0.11.1
Client API version: 1.11
Go version (client): go1.2.1
Git commit (client): fb99f99
2014/06/07 13:41:59 Get http://localhost:4243/v1.11/version: EOF
$ docker pull dockerfile/ghost
...
... : dial tcp: lookup index.docker.io on 172.20.10.1:53: no answer from server

解決方法

OSX上で docker version が失敗した

VirtualBoxのネットワーク::NAT::ポートフォワーディング設定をする。

../../../_images/vm_nat_port_forwarding.png

以下みたいな事をVirtualBoxの管理のもと行なっている

$ssh -L 4243:local:2375 localhost -p 2022

docker pull dockerfile/ghost が失敗した

DNSの指定を修正して再起動した。

$ boot2docker ssh
docker@boot2docker:~$ vi /etc/resolv.conf
## 以下を追加
## nameserver 8.8.8.8
docker@boot2docker:~$ cat /etc/resolv.conf
nameserver 8.8.8.8
docker@boot2docker:~$ exit
$ boot2docker restart

調査内容

OSX上で docker version が失敗した

  1. telnet localhost 4243 が拒否される事を確認した
  2. boot2docker-vm にログインして docker version が成功する事を確認した
  3. docker が開いているポート一覧を確認した
$ telnet localhost 4243
[masumi(%3)@air-trout blog]$ telnet localhost 4243
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.
$ boot2docker ssh
docker@boot2docker:~$ docker version
..
docker@boot2docker:~$ ps aux | grep docker
624 root     /usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// -H tcp://0.0.0.0:2375

docker pull dockerfile/ghost が失敗した

エラーメッセージでググったら以下が見つかったので試してみた。

]]>
Sat, 07 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/06/06/update_openssl_for_ccs_injection.html http://blog.masu-mi.me/2014/06/06/update_openssl_for_ccs_injection.html <![CDATA[OpenSSLを1.0.1hにした(CCSインジェクション対策)]]> OpenSSLを1.0.1hにした(CCSインジェクション対策)

先日OpenSSLの致命的な脆弱性がまた見つかりました (CVE-2014-0224)Heart Bleed(CVE-2014-0160) から大して時間が経っていないのに立て続けですね。

アタック可能なパターンを調べている方がいました。

そして解説はこちら

個人のMBA, 個人のサーバで対策しました。

MBA(10.7.5)での対応。そろそろバージョン上げないとな… appleの対応までバイナリ置き換えてみた、でも curl とかは直接 /usr/lib/.. をロードするのでver. は上がらない。 今回の危険なver. から外れるらしいけどapple対応してくれないかな。

あとChrome とかはリンクしてバイナリに含まれちゃってるから対処しようがない。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.7.5
BuildVersion:   11G63
$ brew update
$ brew upgrade openssl
$ brew link --force openssl
$ sudo rm /usr/bin/openssl
$ ln -s /usr/local/bin/openssl /usr/bin/openssl

個人サーバ(CentOS release 6.4 (Final))では以下をした。

$ yum info openssl
$ sudo yum update -y openssl
$ yum info openssl
Installed Packages
Name        : openssl
Arch        : x86_64
Version     : 1.0.1e
Release     : 16.el6_5.14
Size        : 4.0 M
Repo        : installed
$ shutdown -r now

opensslの1.0.11h以上が安全だけど yumはバックポートされていて上記のバージョンで対応済みになっている

homebrew,yum に対応pkgが既にあって本当に良かったです。楽に対応出来ました。 SSLアクセラレータとかハードウェアを利用しているサービスや会社は多いし大変だなーって思います。

coqによって発見された様ですね。 定理証明系って憧れはあれど触れた事がなくて、こういう成果をみるとかっこいいって思いますね。

]]>
Fri, 06 Jun 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/04/11/slip_on_php.html http://blog.masu-mi.me/2014/04/11/slip_on_php.html <![CDATA[PHPの落とし穴]]> PHPの落とし穴

PHPで忘れがちな罠に引っかからない様に、躓いた所を思い出して並べておく。 でも「嫌い!」とかディスられるだけありPHP は躓き易いところが多い。 語彙にも微妙なものがある。

PHPマニュアル

構文

関数っぽく見えてしまう言語機能

次の識別子は関数ではない。 echo, empty, eval, exit, isset, list, print, array そのうちecho, eval, print は関数に分類して良いのにって思う。

switch文の比較

同値性は “==” 演算子と同等の緩い比較になる。(型変換して一致したらOK) JavaScriptは厳格な比較(“===”)をする。

<?php
switch ("a") {
case "0":
  var_dump("0");
  break;
case 0:
  var_dump(0);
  break;
default:
  echo "@default";
}
//int(0)

switch ("1") {
case "01":
  var_dump("01");
  break;
case "1":
  var_dump("1"); // 前で一致するので出力されない
  break;
case 1:
  var_dump(1);   // 前で一致するので出力されない
  break;
default:
  echo "@default";
}
// string(2) "01"

switch文のcontinue

continue の対象になるためループの中でswitchを使いcontinueを使ってもswitch文から抜けるだけになる。

<?php
$list = array("apple", "orange", "banana");
foreach ($list as $_val) {
  switch ($_val) {
  case "banana":
    continue;
  default:
    break;
  }
  // break, continue共にここに飛んでくる
  echo $_val. ',';
}
// apple,orange,banana

言語機能

PHPはテンプレートエンジン的なスタートから始まっているので高度なプログラミング概念を備えていない。 長く付き合う為にも、求め過ぎて重い彼女になってしまわぬように注意する。

  • DEFINEは配列が使えない
  • ジェネレータは5.5以降
  • 末尾最適化を望んではイケナイ
  • コルーチンを望んではイケナイ

マルチスレッドを望んではイケナイ

やるなら exec(‘php SCRIPT_NAME.php &’); みたいにコマンドライン経由になる。 ただ最近は、こんなモジュールある。

アクターとかチャンネルとか現代的なのは勿論の事、 平行処理・並列処理関係は期待しないってのが基本の様だ。

配列

配列インデックスは正規化される

配列のインデックスは基本的の文字列ただし‘1’の様な10進数表現は強制的に数値になる。

<?php
$test = array(
  '03' => 'apple',
  '1'  => 'orange',
  2    => 'banana'
);
var_dump($test);
//array(3) {
//  ["03"]=>
//  string(5) "apple"
//  [1]=>
//  string(6) "orange"
//  [2]=>
//  string(6) "banana"
//}

関数の返り値の配列は直接使えない

5.4以降は解決しているよ。だけど5.3以前は駄目なんだ。 ていうか最新版を使いましょうねって話でもある。

<?php
function test() {
  return array("apple" => 100);
}
test()["apple"];
// => PHP Parse error if php -v < 5.4.0

list表現による部分代入の評価は右から束縛される

<?php
function test_list() {
  return array(
    100,
    80,
    60
  );
}
list ($a, $b) = test_list();
var_dump($a);
var_dump($b);
//int(100)
//int(80)

$ar = array();
list($ar[0], $ar[1]) = test_list();
var_dump($ar);
//array(2) {
//  [1] =>
//  int(80)
//  [0] =>
//  int(100)
//}

$ar2 = array();
list($ar2[], $ar2[], $ar2[]) = test_list();
var_dump($ar2);
//array(3) {
//  [0] =>
//  int(60)
//  [1] =>
//  int(80)
//  [2] =>
//  int(100)
//}

名前空間

例を挙げるのも面倒な小さい事は、ここに書く。

  • PHP5.2以前は名前空間が使えない

クラス名・関数名は大文字小文字を区別しない

<?php
try {
  throw new ViewException();
} catch (viewException $e) {
  echo "catch される";
}

require, include された時のスコープは呼び出し個所と一致

  • 基本的に呼び出し箇所と一致

ver 5.2.17以上ではprivateプロパティでも問題がない事を確認したが、 だいぶ古い奴では駄目だった気がする(ver. 忘れてます)。

<?php
// cat callie.php
var_dump($local_var);
var_dump($this->public_var);
var_dump($this->private_var);

// cat caller.php

class RequireTestClass
{
  public $public_var;
  private $private_var;

  public function require()
  {
    $local_var = 100;
    $this->public_var = 200;
    $this->private_var = 300;
    require "./callie.php";
  }
}
$ob = new RequireTestClass();
$ob->require();
// int(100)
// int(200)
// int(300)

関数

関数の引数のデフォルト値は定数式

ちなみに変数やプロパティが可能だと、評価のタイミングが問題になる。 Pythonは定義時にRubyは呼び出し毎にでフォルト値が評価される。

<?php
function test($val = array(12, 13))
{
  return $val[1];
}
var_dump(test());
// int(12);

可変引数な関数も可能

ただビルトインの関数を使う必要があるので要注意というか少し面倒くさい。 Luaみたいに ... とかで扱えると簡単なのにって思ったり。

<?php
function variable_length($name, $volume)
{
  var_dump($name);
  var_dump($volume);

  var_dump(func_num_args());
  var_dump(func_get_args());
}
variable_length("test",100,40,53,3);
//string(4) "test"
//int(100)
//int(5)
//array(5) {
//  [0] =>
//  string(4) "test"
//  [1] =>
//  int(100)
//  [2] =>
//  int(40)
//  [3] =>
//  int(53)
//  [4] =>
//  int(3)
//}

PHP5.3より前は無名関数が無い

5.2系では使えない。本当に辛い。 というか、さっさとver.上げろよ。

無名関数で、親スコープから引き継ぎたい変数は明示する use

LuaとかSchemeとかRubyとかPythonとか静的スコープで自動的に変数が見えているよね。 PHPだと見えないんだ。だから use キーワードを使って欲しい。

<?php
function out($val)
{
  return function($operand) use($val) {
    return $operand + $val;
  };
}
$f = out(100);
var_dump($f(200));
// int(300);

無名関数のuse構文は関数の引数と同様に値渡し

無名関数で他の言語と似た挙動をしたかったら明示的に参照渡しにする必要がある

<?php
// 素直なuse節
function out($val)
{
  return function($operand) use($val) {
    $val = $operand + $val;
    return $val;
  };
}
$f = out(100);
var_dump($f(200));
// int(300);
var_dump($f(200));
// int(300);

// 他の言語の無名関数的な使い方をしたいuse節
function out($val)
{
  return function($operand) use(&$val) {
    $val = $operand + $val;
    return $val;
  };
}
$f = out(100);
var_dump($f(200));
// int(300);
var_dump($f(200));
// int(500);

タイプヒンティングで型チェックを行える(ただし動的型検査)

関数の引き数でクラス・インターフェース名を指定して置く事で関数内に入るオブジェクトに制約を加えられる。 だけど動的チェックなのですよ。

<?php
class A {};
class B {};
function test_type(A $e) {
  return true;
}
var_dump(test_type(new A()));
//bool(true)
var_dump(test_type(new B()));
//PHP Catchable fatal error:  Argument 1 passed to test_type() must be an instance of A, instance of B given, called in ...

呼び出し可能オブジェクトは色々ある

call_user_func$callable は色々あって雑。

無名関数

<?php
$hoge = function () {
  echo "lambda";
}
call_user_func($hoge);
//lambda

関数名

<?php
function function_name()
{
  echo "function_name";
}
call_user_func("function_name");
//function_name

配列

オブジェクト・クラス名とメソッド名を格納した配列

<?php
class CLASS_NAME
{
  public static function static_method()
  {
    echo "in static_method\n";
  }
  public function method()
  {
    echo "in method\n";
  }
}
call_user_func(array("CLASS_NAME", "static_method"));
//in static_method
$obj = new CLASS_NAME();
call_user_func(array($obj, "static_method"));
//in static_method
call_user_func(array($obj, "method"));
//in method

クラス

クラスのフィールド定義で式が使えない

クラス定義内で許可されるのはリテラルのみ。

<?php
class ClassName
{
  public $name = "First" + "," + "Second";
}
// PHP Parse error: ...

new 演算子でオブジェクト生成した直後はメソッドを直接呼べない。

<?php
class DirectCallie
  {
    public function test()
    {
      echo "in method";
    }
  }
$di = new DirectCallie()->test();
// PHP Parse error: ...

静的遅延束縛はstaticキーワードを使う

静的遅延束縛は 5.3 以降じゃないと使えない。

ArrayObjectは配列ではない

配列風オブジェクトなのに配列として判別はしてくれない.

<?php
$aob = new ArrayObject();
var_dump(is_array($aob)); // false

ReflectionMethodクラスを使うとアクセス制御を破れる

5.3.2以降で使えます、それ以前はテストでプライベートメソッドを扱うのは大変ですね。

<?php
class Foo
{
  private function _func()
  {
    echo 'test';
  }
}
$foo = new Foo();
$method = new Reflectionmethod(get_class($foo), '_func');
$method->setAccessible(true);
$method->invoke($foo);
// test

5.4からはTraitが使えるよ

RubyでモジュールをMixinする様にクラスに組み込める操作集合を作れる。 Traitのメソッド・プロパティの中身が特定クラス内にインライン展開される感じ。 なので多重継承の継承パスの問題とかは引き起こさない。

  • Traint内の識別子の衝突は静的に解析され、明示的な解決が必要
  • プロパティの上書き定義は不可能
  • 同名のプロパティは共有される
<?php
trait Hello {
  private $name = "apple";

  public function echoName() { echo $this->name; }
}
trait World {
  public function getName() { return $this->name; }
}
class First
{
  use Hello, World;
  public function testMethod($input)
  {
    $this->name = (string)$input;
  }
}
$obj = new First();
$obj->echoName();          // apple
$obj->testMethod("orange");
$obj->echoName();          // orange
var_dump($obj->getName()); // string(6)"orange"

ライブラリ類

なんか面倒になってきたので概要ふれるだけで、詳しく書きたくなったら今度書く。

バッファリングの操作

  • 出力バッファリングはスタック管理されている
  • ob_start のネストレベルが管理されている
  • ob_flush はスタックレベル = 1でのみ実行可能

HTTP, HTML, URL

parse_url, parse_str などのパース系関数は文字エンコードの変換も「おもてなし」の精神でやってくれちゃったりする

Iterator

Iteratorなオブジェクトを入れ子foreachすると各ループが独立にならない。挙動に注意 入れ子ループに対応したIteratorを作りたければIteratorAggregateを使いループ毎にインスタンス生成させる必要がある

]]>
Fri, 11 Apr 2014 00:00:00 +0900
http://blog.masu-mi.me/2014/02/06/tinkerer_endpoint.html http://blog.masu-mi.me/2014/02/06/tinkerer_endpoint.html <![CDATA[Tinkerer の動き方]]> Tinkerer の動き方

Tinkerer が動くための最初の流れをメモしておく。

このブログは Tinkerer で生成している。ようやくカスタマイズしたくなってきた。 だけど元々「reST形式で編集するブログ生成出来るらしい」って事しか知らずカスタマイズとか出来なかった。

概要

TinkererSphinx を使ってブログを生成する。Sphinx というreST形式から他の形式に変換するツールが存在する。 TinkererSphinx を呼ぶだけで実装は「 Sphinx 拡張 + コマンドラインフロントエンド」となっている。 Tinkerer 独自の処理はSphinx拡張で定義されており、 tinker -s で生成した設定ファイルでは最初から使う様に指定されている。

ちなみに Sphinx のマークアップは沢山ある。 Shinxの公式ドキュメント から ユーザードキュメント に辿り着ける。 ちゃんと調べてみるもんでマークアップが充実している。これから過去記事にタグ・カテゴリを振りながらマークアップも整理します。

設定ファイル

Sphinx はソースディレクトリ(Sphinxが処理する対象のトップレベルディレクトリ)に含まれる conf.py を設定ファイルとして使う。 extensionsに設定されている拡張が利用される。

extensions = ['tinkerer.ext.blog', 'tinkerer.ext.disqus']

上のはDisqus拡張も使う様に追加している。 モジュール tinkerer.ext.blog の挙動の説明は先に Sphinx 拡張の説明が必要なので別の機会に書く。

Sphinxが動くまで

コマンド tinker -b`Shpinx`_ を呼ぶまでを追う。 Sphinx が呼ばれるまでに解決される事が2つある。

  1. コマンド tinker の実行関数の特定
  2. tinkerのサブコマンド の識別

コマンド tinker の実行関数の特定

コマンドの実行コードの解決には pkg_resources/load_entry_point が使われていた。 実際に vim $(which tinker) してみたら以下の様に書かれていた。

# ...
from pkg_resources import load_entry_point
sys.exit(
  load_entry_point('Tinkerer==1.2.1', 'tinkerer')
)

上記は以下2つの事をしている。

  1. sys.exit はコマンドの実行ステータスを受け取り SystemExit を送出する。要するに明示的に終了している
  2. easy_install のサブモジュール pkg_resourcesload_entry_point でpkg情報とコマンド名からコマンドのエントリポイントを取得し実行する

load_entry_point で呼ばれる関数は PKGNAME-Ver-pyVer.egg-info/entry_points.txt ファイルに記述されいる。 自分の環境では以下となっている。

$ cat Tinkerer-1.2.1-py2.7.egg-info/entry_points.txt
...

[console_scripts]
tinker = tinkerer.cmdline:main

なのでコマンド tinkerer はlib内の tinkerer.cmdline:main を呼ぶ。 pkg_resources が 呼び出し可能オブジェクトを生成する部分は追っていない。

tinkerのサブコマンド の識別

tinker本体はディスパッチャで引数解析に`argparse`パッケージが使われている

ref. http://docs.python.jp/2/library/argparse.html

ビルド(“-b”)では tinkerer.cmdline:build が呼ばれる。 その中でフラグ類が設定されSphinxが呼ばれる。

]]>
Thu, 06 Feb 2014 00:00:00 +0900
http://blog.masu-mi.me/2013/12/18/php_parse_url.html http://blog.masu-mi.me/2013/12/18/php_parse_url.html <![CDATA[PHPのparse_urlは勝手にエンコード変換する]]> PHPのparse_urlは勝手にエンコード変換する

PHPはRFC定義に従う基礎的な関数が提供されていない。 しかたないのでURIを定義している RFC3986 に従って実装する。

PHPの parse_url() は勝手に文字コードを変換する。しかも自力で文字コードを判別する。 そのほか不完全なURLでも色々と頑張ってしまう。 そのためマルチバイト文字列が含まれるURLの場合は文字化けが起きてしまう。

<?php namespace Masumi\Plain

fuction parse_uri($uri)
{
  $uri_reg_exp = '(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)';

  preg_match($uri_reg_exp, $uri, $matches);
  return array(
      'scheme'    => empty($matches[2])?NULL:$matches[2],
      'authority' => empty($matches[4])?NULL:$matches[4],
      'path'      => $matches[5],
      'query'     => empty($matches[7])?NULL:$matches[7],
      'fragment'  => empty($matches[9])?NULL:$matches[9]
  );
}

user/passには対応していないけどRFC3986を素直にサポートした。 なんでPHPは第一義の(定義の存在する)機能が隠されているんだ。。

PSRの命名規則は大御所向け?

PSR 詳しくないのだけど PSR-0 によると名前空間の第一階層はベンダ名になっている。 FIG メンバーの様に大御所は問題ないけど 野良を個人で公開する時には、どうしたらいいんだろう。 Javaみたいにドメイン逆向きとか許して貰えるなら嬉しいな。

文字コード変換周りで出てきた事

  • php_build_query() はクエリを作成する際に勝手にエンコードする

    URLエンコードした文字列が値に含まれていると多重エンコードになる

  • JavaScriptでURLエンコードするときUTF-8 しか標準は存在しない

  • URLエスケープされた文字列が本文のエンコードが一致しないと文字化けする

]]>
Wed, 18 Dec 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/12/01/html5_conf_2013.html http://blog.masu-mi.me/2013/12/01/html5_conf_2013.html <![CDATA[HTML5カンファレンス]]> HTML5カンファレンス

HTML5カンファレンス 行ってきました。 ボランティアスタッフしました。設営なのでカンファレンスが開かれている間はフリーダムです。

単純にカンファレンスにスタッフ側で関わると楽しいので、手伝える事とか有ったら参加するの良いなーとか思いました。 あとLT出来る様な人間になりたい、とも。

ざっと感想をまとめます。

WebSocket, WebRTC, Socket API, ... 最新Webプロトコルの傾向と対策(小松 健作)

今回の話題のうちSPDYの話の準備で以下の流れを押さえておくと言い。

  1. 不満があるよ
    • HTTP遅いよね
    • リクエストをまとめたりするよね
    • CSS Spriteとか辛いよね
  2. TCPコネクション1つに複数HTTPSリクエストをまとめられれば自然だね これがSPDYだ!(上の方法のうちの1つだけどね)

  3. 単純にSPDYを使えば問題ない? <- これ!!

実例としてネットワーク遅延がある場合をエミュレートして確認していた。

  • 重い画像を大量(150枚くらいだったはず)にダウンロードする状況
  • ネットワークに50ms 遅延がある(OSXだとipfwでエミュレート)

結果はHTTPSが3[sec]に対してSPDYは14[sec]かかった。 SPDYの方が大分遅い。

理由は Long Fat Pipe での遅延らしい。 1つのTCPコネクション内で大量に通信するため、windowサイズを越えた通信ではACK待ちにより送信タイミングがコントロールされる。 そのため、ネットワーク遅延があると通信が大幅に遅れる場合があるというもの。

ref. レイヤ4 TCP ウィンド

ipfw, qdisc 便利だし通信系で簡易実験する時に使ってみようと思った。 あとSPDYでもウィンドウサイズ越える様な場合で海外にサーバー置く場合とかのケースだと検証が必要とか、世の中簡単に行かないねーって思った。

モバイルHTMLテクニック(紀平 拓男)

話のテーマは「いま出来るモバイルブラウザテクニック」でした。 だいぶ泥臭く実践的な話と現状、多くの愚痴を知れたw

モバイルHTML5
モバイル環境のオンブラウザなHTML5

現在は遺憾ながら、世の中HTML5は不況・ネイティブアプリ開発が活況。 海外はほぼアプリ1本だしモバイルHTMLは現状日本が先攻している。

でもブラウザだから出来るHTML5だから出来る形というのはある筈だ。 例えばMinecraftがHTML5・ネイティブそれぞれアプリが有ると仮定すると、 ネイティブアプリではSNSにシェアされた内容を遊ぶには一旦ダウンロードが発生する。 だけどブラウザアプリだったらいきなり参加出来る。 これは楽しいし少し遊んでみようと思える。とかが言われてた。

ユーザーのプレイまでのコストが小さくなる点を活かす事は出来る筈って無いようだった。 確かにほかのアプリやゲームを利用したりURLによるリソース読み込みを使うといったオンブラウザな特性を使ったゲームって あんまり無い印象がある。

とは言ってもHTMLでゲームを実装するとパフォーマンス・互換性などで不利だ。 パフォーマンスについては現状、HTML5は速度・互換性・3D/音楽の整理が進んでいる。 なので時間の問題っぽい。

テストするべき実行環境の互換性が酷い。 バグが多いよAndroid! 悲しいねって言われてた。「Androidの対応はIE6より大変だ」 これは、ハードウェアの性能を引き出すためにベンダーがブラウザのコードに手を加えているからベンチマークは良くなるのだけど、 バグが混入するという実態が引き起こしている。

さっさとChromeとか標準ブラウザじゃなくて落としてきたブラウザを使うのが普及すりゃ良いんだって言ってて、全く同意。 もしくはFFOSですかね…

高速化の話

高速化の基本

  • オンメモリCanvasを使う スプライト使いましょうみたいな感じ
  • drawimageなどで整数位置を避ける “pos|0” 使う 小数点に置くとアンチエイリアスが起きちゃう
  • 拡大縮小を使わない ブラウザは拡大縮小が不要の場合は高速モードで動けるので凄い早くなる
  • 定型のlineTo, moveToは new Function にまとめてしまう

GPUを意識した高速化

  • 画像がGPUキャッシュに乗る様に使う順序を意識する - どうすればキャッシュに乗るかはブラウザ次第 - どの画像をどのタイミングで描写するか? 意識する
  • Canvasを使って作った画像はキャッシュに乗らない - toDataUrlを使ってimageにしてしまう -> メモリを食うけど, キャッシュに乗る可能性がある - 使わなくなったらGC対象にする様に解放する

バグの話

  • JavaScriptのバグにハマる事がよく有る、徹底的にブラウザを疑う
  • だいたいはベンダーの最適化コードのバグに捕まってる事が多い
  • 明確に最適化出来ないとブラウザを思わせる様にすると何故か迂回出来たりする

例えばこんな事が有った

  • ある2機種だけAndroidでのみ動かない
    • GPU周りを疑った(理由は聞き逃した、GPU種類とベンダが共通してたとか)
    • 画像の高さ・幅が2048pixを越えるとGPUに読み込まずCPUで処理される
    • 崩れる画像周りのサイズを大きくしたらCPU処理になり問題が回避された
  • 代入文が動かない端末が有る( a = b = c =100 みたいな連続代入)
    • 雰囲気として最適化コードの一部が書き換えられてスタックが破壊されてるっぽい
    • なので「消すな」コメント付きの setTimeout(‘return 0’, 0); を直前に配置
  • Android を暖めたら描写が崩れる
    • CPUは熱暴走しないけどGPUが熱暴走して駄目ってケース
    • GPUに負荷が掛からない様に調整した

終わりに

鉄則はこれだ!

  • 高速化・メモリ管理も実際のデータをもとに確認する
  • ある程度は諦める

諦めるって大事ですね。

HTTP/2.0がもたらすWebサービスの進化

バッテリーが上がりそうだったので、あまりメモしてない。 HTTP2の大きな違い。text -> byte になります。 でも、HTTP1.1もまだだよ

論点は色々有って全然決まってないのです。 圧縮周りでHPACKって方法を使っていてアグレッシブに圧縮するんだなって思った。

HTTP2は暗号化を必須にするか否かで協議が割れているらしい。 個人的には必須にするのは役割別な気もしている。 ただPRISM盗聴事件もあったし、その辺プロトコル屋さん達はシビアなんだろうな。

進化を続ける JavaScript 〜次世代言語のステキな機能と高速化の行方〜(浅井 智也 Mozilla Japan)

話題は2つ。

  • ECMAScript6の機能
  • JavaScript が Cに迫りたい

構文上の変化が遂に来るECMA6。 ブラウザの実装も徐々に進んでいる。IEは他言語などビジネスよりなのは積極的に提案・実装してくれるね。

言語機能的な変化

  • 分割代入可能(オブジェクトも)
  • デフォルトパラメタ(FF以外は未実装)rubyっぽい評価タイミング
  • rest paramter`...restArgs`
  • 配列の内包表記 [for (x of [1,2,3,4]) if (x>0) x]
  • ブロックスコープ(let, const)
  • Class入る
  • Module入る
  • Arrow Function入る
  • Arrow Function thisを構文スコープで解決する無名関数
  • Generator Functionが入る
  • Promiseが入る (jQuery::Deferrd みたいな)

Rubyのブロック・無名関数のself解決が複雑な様に混乱を招くんじゃないかしらって思った。 懇親会で聴いてみたのだけど「thisの解決には不満が強いので、mapみたいに使い捨てで使う事を強く意図して導入した」って事らしい。

確かに、短命な使い方を意識しているなら良いかって思た。

use strict でArrow Functionの代入禁止したいけど実効無いから行なわれないだろうな。。

JavascriptもCに迫りたい

FF22が asm.js を採用したって話。 これはJavaScript で早く実行される定石を明示化してまとめたサブセット言語のみたい。 ダグラスのGood Parts にあやかってFast Partsって名付けてた。センス良い。

asm.js というサブセットは指定して使うという事は既存の高速化の定石を使っている事を明示する様なもの。 型情報をコンパイル後のバイトコードから除去したりとかを行ない易くするらしい。 動的型付けの為にタグ付き共用体を使うのは重いから外せるところは外したいって事なんだけど、

asm.jsによって特定コンパイル単位内で動的特性を失うってのは英断よね。 使い方はコード内に use asm を入れる。

静的言語な特性を得るとなるとJavaScriptJITがLuaJITに迫る可能性あるなーって思った。 1つの言語なのにコンパイル単位で要求する方言を切り替えるってのは後方互換の維持とかで観た事あったけど、 動的特性の切り替え等パフォーマンスに使うってのは考えた事無かった。 汚いのだけど面白いアプローチだよね。

ref.

Web Audio API実践的プログラミング

Audio関連APIの紹介。単純に楽しかった。 ハマりどころは

  • Oscilator, とかは使い捨てなのでcrateする
  • Panは3次元で2次元Panを使うのは結構難しい
  • 仕様に変更があったAPIの名前は新しい方を使う (FFが古い名前だとサポートしてなかったり)
  • 音のプログラミングはテストが難しい
]]>
Sun, 01 Dec 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/11/23/construct_php_env.html http://blog.masu-mi.me/2013/11/23/construct_php_env.html <![CDATA[PHP開発環境を整備した(phpenv)]]> PHP開発環境を整備した(phpenv)
  • バージョン・ライブラリ依存を管理したい
  • 実装・デバグ・リファクタのツール類が整っている

PHPでの実装

PHP関係で調べてみたら以下の組み合わせで出来そう。 (エディタ周辺は色々ありそうで除外)

静的チェック php -l
動的チェック xdebug
バージョン管理 phpenv
pkgインストーラ pyrus
プロファイラ xprof
ビルドツール Phing
テストFW PHPUnit

phpenv導入

osxで phpenv を中心に環境を整えた。 httpdhomebrew でインストールしている前提なので他OSだと連携部分が変わると思う。

phpenv でPHPをインストールするとpyrusが自動的に使える。 PHPUnit, xdebug, xprof, phing かは pyrus 経由で導入する(実際は失敗した)。

[準備]PHPビルドに必要なpkgのインストール

他にも必要かも知れないけれど下ので大丈夫だった。 PHPビルド時に怒られたら都度追加する。

# for building php
brew install re2c
brew install libmcrypt

[準備]Apache:httpd インストール

apache::httpd をbrew経由で入れる。 そしてphpを使う様にconfigファイルを書き換える。

ここでは SERVER_CONFIG_FILE を直接書き換えてるけど、 無作法なので ./others, ./conf.d とかに別ファイルで書いて読み込む。

# php is used with apache httpd often.
brew tap Homebrew/dupes
brew install httpd

# libphp5.soを有効にする
httpd_conf_path=$(httpd -V | awk 'BEGIN{FS="\""} /SERVER_CONFIG_FILE/{print $2}')
sed -i -e "s/#LoadModule php5_module/LoadModule php5_module/" $httpd_conf_path

phpenvをインストール

以下の実行後に .bashrcenv 系おなじみの修正を加える。

# install phpenv, dependencies and plugin
curl https://raw.github.com/CHH/phpenv/master/bin/phpenv-install.sh | sh

git clone https://github.com/CHH/php-build/ ${HOME}/.phpenv/plugins/php-build
cp ~/.phpenv/plugins/php-build/bin/phpenv-install ~/.phpenv/plugins/php-build/bin/rbenv-install
sed -i -e "s/# Provide phpenv completions/# Provide rbenv completions/g" ~/.phpenv/plugins/php-build/bin/rbenv-install
phpenv rehash

加える内容は以下になる。自分はdotfile再読み込みでPATHが冗長になるのを避ける為に関数を挟んでる。

export PATH=${HOME}/.phpenv/bin:${PATH}
eval "$(phpenv init -)"

apache::httpdと連携する為に共用ビルドオプションを設定する

phpenv 経由でビルドする際のビルドオプションは .phpenv/plugin/php-build/share/php-build/default_configure_options に記述する。 なので以下を実行するとモジュールが作られる様になる。

# add --with-apxs2=/usr/sbin/apxs
echo "--with-apxs2=/usr/sbin/apxs" >> ${HOME}/.phpenv/plugins/php-build/share/php-build/default_configure_options

使ってみる

# 欲しいver.を探す
phpenv install

# 欲しいver.をインストール
phpenv install 5.5.0RC3
# 激しいログの嵐
phpenv install 5.5.5
# 激しいログの嵐 part 2

# 利用するPHP ver.を切り替える(システム全体)
phpenv global 5.5.5

# 利用するPHP ver.を切り替える(カレントDir以下)
phpenv local 5.5.0RC3

httpd で使うPHPのバージョンを変更可能にする

phpenv から apache モジュールを切り替えるpluginを garamon さんが書いているのでインストールする。

git clone https://github.com/garamon/phpenv-apache-version ~/.phpenv/plugins/phpenv-apache-version

自分の環境だけなのか libphp5.so のパスが変だったので読み込むPATHを柔軟にした。

$ git diff --no-prefix HEAD^
diff --git bin/rbenv-apache-version bin/rbenv-apache-version
index 916b9c6..7ed237c 100755
--- bin/rbenv-apache-version
+++ bin/rbenv-apache-version
@@ -38,7 +38,7 @@ if [ -z "$PHPENV_APACHE_MODULE_PATH" ]; then
 fi

 PHPENV_PREFIX_PATH="${RBENV_ROOT}/versions/${PHPENV_APACHE_VERSION}"
-PHP_MODULE_PATH="${PHPENV_PREFIX_PATH}/libphp5.so"
+PHP_MODULE_PATH=`find ${PHPENV_PREFIX_PATH} -name libphp5.so`

 if [ ! -f "$PHP_MODULE_PATH" ]; then
   echo "Make sure the specified version is installed." >&2

ref. https://github.com/masu-mi/phpenv-apache-version/commit/f870723df2ba697d555607a2e68520e40dd2afbd

使ってみる

$ phpenv apache-version 5.5.5

入れ替わる!

ref. http://techblog.allabout.co.jp/2013/08/01/280/

うまく動かせなかったこと

  • Pyrusが機能しない
  • 依存関係の管理は別
  • Lint系が存在しない
  • phpenvの中が結局rbenvなのは良いけれど…

Pyrusが機能しない

pyrus経由でライブラリをインストール出来るって書いたのだけど失敗しました。

依存関係の管理は別

PyrusはBundlerみたいにローカル環境に入れたいpkgリストから解決みたいな事が出来ない。 Onion ってのがあるらしいけどpear, peclから独立してるのとpear, peclを使う。

「あれ、じゃあモダンなpyrusとの関係は?」って思った。

Lint系が存在しない

php lint とかでググったけど見当たらない。 php -l だとスタティックメソッドで $this 使っても引っかからない。

phpenvの中が結局rbenv

phpenv を叩いて出てくるメッセージとかが rbenv って自覚している文言で悲しい。

]]>
Sat, 23 Nov 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/11/06/try_vim_map.html http://blog.masu-mi.me/2013/11/06/try_vim_map.html <![CDATA[Vimのキーバインド変更した]]> Vimのキーバインド変更した

vim キーバインド変更とか殆どしていなかった。 調べていたら 良さそうなエントリを見つけた。 これによるとユーザー定義なマッピングのprefixは <Space> が良さそう。

よく使う奴から追加してみた。とりあえず vim/support.vim に記述する。 結局 こんな感じに追加した。

"for gnu global
nnoremap <Space>gd :Gtags<Space>
nnoremap <Space>gr :Gtags -r
nnoremap <Space>gf :Gtags -f
nnoremap <Space>gg :Gtags -g
nnoremap <Space>gc :GtagsCursor<Enter>
nnoremap <Space>gu :GtagsUpdate<Enter>

"for Quickfix
nnoremap <C-j> :cn<CR>
nnoremap <C-k> :cp<CR>

nnoremap <Space>vs :VimShell<Enter>
nnoremap <Space>vf :VimFilerExplorer<Enter>

" for file
nnoremap <Space>of :vs<Space>

vimproc など入れただけで使っていないPluginが大分ある。 非同期実行も出来るし 積極的に道具を整備する。

]]>
Wed, 06 Nov 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/11/04/read_tddjs.html http://blog.masu-mi.me/2013/11/04/read_tddjs.html <![CDATA[テスト駆動JavaScript 読了]]> テスト駆動JavaScript 読了

会社同期に薦められて読んでいた。 具体例が長く流し読みしたりしたがとりあえず読了した。 (読書メーター)

プログラマーのためのJavaScriptではホイストなど曖昧だった部分を改めて学ぶ機会になりました。 特にActivationオブジェクト辺りについて勉強になりました。

主題のTDDについてはCommetライブラリを実装する具体例等で学べます。 個人的にはここは長ったらしく感じてしまいました。

読んだり関連情報をwebで調べたりして勉強になった事は

  • 言語・ライブラリの勉強にテストコードを書いておく
  • 良さそうな組み合わせ
  • TDDの効用
  • 良い単体テストの方針
  • 控えめなJavaScriptの目的と規則

いささか基本的な事が多いけど、 業務で単体テストやリファクタリング、その他を主張しても 技術側から反論されたりすると上手く答えられず、 改めて整理するきっかけとしてありがたかった。

言語・ライブラリの勉強にテストコードを書いておく

言語やライブラリの簡単な挙動確認でREPLを使う事がある。 ここでテストコードを作っておくと再確認が楽ですよって話でした。

特にJavaScriptは効果が大きい。 理由は実装系(ブラウザ)が多く増え続けているため。 新しいブラウザや処理系が出るたびに学習テストを走らせれば変化を直ぐに確認できる。

良さそうな組み合わせ

本書というか関連してWebで調べた結果だけどJavaScriptの場合テストを実行するにあたり3つレイヤーが協調する必要がある。

リモートテストランナー ホスティング環境(ブラウザなど)でテストを実行する
テストフレームワーク テスト結果を管理する
アサーションライブラリ テストを行なう

リモートテストランナーに付いては id:teppeisさんの記事 で触れられています。

本書で紹介されているリモートテストランナーは js-test-driver です。 しかし最近の動向的には 非推奨でもっと良いランナーの選択肢がある様子 。 ちなみにリンク先のtestacularは現在 Karma に名前を変えています。 前にYeomanで何かのスケルトン叩いて遊んだ時に Karma が使われていて触った事がある。 特に理由がなければ Karma から入ろうと思う。

テストフレームワークは JasmineMochaメインストリームっぽい 。 そして何が理由かよくわからないけど Mocha人気が登っているらしい 。 (なんかさっきから根拠が同じ記事に向かっている… しかもその記事の根拠は弱い) Mocha の場合アサーションライブラリに Sinon を使う事が前提になっている。 一方 Jasmine はアサーションライブラリも付いてくる。

なので「手を付けてみようかなー」と思っている組み合わせは以下になる。

TDDの効用

  • 動くコードが手に入る
  • 単一責任の原則を守りやすくなる
  • 意識的な開発が強制される - これは開発者の開発速度向上にも繋がる
  • 生産性が向上する - 回帰テストが多くなり”時間コスト/品質”を小さくし易いという意味 - リファクタリングしやすくコードの品質(簡潔さ)を維持できる

最後のリファクタリングし易くってのは リファクタリング とか レガシーコード改善ガイド とかで書かれていた気がするし、 業務で個人的に実践する様になってから強く実感してる。

良い単体テストの方針

  • テストには意図がはっきりわかる名前をつける - 斜め読みしやすい名前
  • テストを<セットアップ/実施/確認> に分割する
  • テストを単純に保つ - 重複個所を取り除く - テストにロジックを含めない - 1つのテストでは1つの振る舞いをテストする - 振る舞いをテスト内に閉じ込める

控えめなJavaScriptの目的と規則

目標

  • アクセシビリティ 多くのユーザーエージェントが利用出来る形を保つ
  • 柔軟性 外部ソースに変更を加えなくても文書構造に簡単に変更を加えられる様にする 文書に手を加えなくてもJavaScript, CSSに修正を加えられる様にする
  • 堅牢生 振る舞いを段階的に追加する事を可能にする 機能検出を用いて動作する機能をユーザーに応じて安全に追加する事を可能にする
  • パフォーマンス 外部スクリプトをWebページ全体でキャッシュさせる
  • 拡張性 新ブラウザで機能拡張を容易に行なえるようにする

ルール

書かれてたルールをまとめると以下になった。 JavaScriptは外部コードと共存する・実行環境が多様って事を強く意識する必要があり、 その辺が強調された内容だった。

  • 実際に機能するか確認してから実行するように書く (外部スクリプト・マークアップ・ユーザーを勝手に想定しない)
  • モジュール間の結合度を落とす為にイベントを使う
  • 問題の責任を何処に持たせるか考えて繰り返しを減らす
  • グローバルスコープを出来るだけ汚さない
]]>
Mon, 04 Nov 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/11/02/reading_llex.html http://blog.masu-mi.me/2013/11/02/reading_llex.html <![CDATA[Lua字句解析 llex.* を読んだ]]> Lua字句解析 llex.* を読んだ

luaに演算子を追加したのだけど単に感想を書いただけだと何の意味もなくなってしまうので、 テーマ毎に整理しておく。 最初は字句解析器関係(llex.h, llex.c)について。

公開API

字句解析器はユーザーの文字列から字句列に変換する部分。 ヘッダファイル で公開されている関数は以下。

  • 基本的に構文解析器が呼ぶ
  • 字句解析処理の進行は構造体LexStateの変化に一致する
  • 実際の先読み字句取得などはLexStateのメンバで判断する

読んだところ以下の様な機能を提供している。

関数 処理
void luaX_init (lua_State *L) Lua仮想機械に予約語を登録
void luaX_setinput
(lua_State *L, LexState *ls, ZIO *z, TString *source)
字句解析器に解析対象設定
TString *luaX_newstring (LexState *ls,
const char *str, size_t l)
解析結果文字列を文字列定数として格納 格納先は構文解析器
void luaX_next (LexState *ls) 字句解析を進める(現在の字句)
void luaX_lookahead (LexState *ls) 先読み字句の解析を行ないlsに設定する
void luaX_lexerror (LexState *ls,
const char *msg, int token)
字句解析エラーをLua状態機械に伝える
void luaX_syntaxerror
(LexState *ls, const char *s)
構文解析エラーをLua状態機械に渡す (luaX_lexerrorをそのまま使ってる)
const char *luaX_token2str (LexState *ls,
int token)
字句に対応するLua文字列を取得

luaX_init詳細

Lua_Stateを予約語を受け付けられる状態にする。

  1. 予約語をLua文字列として生成する(luaX_tokens, RESERVED)
  2. luaX_fixを用いてガベージコレクションの対象から外す
  3. TString.txv.reserved にトークンの番号+1 を代入する (lu_byteにキャストしてだけど)

3つ目の具体的な目的がよくわかっていない。

luaX_setinput詳細

Lexerを初期化している

  1. 仮想マシンを保持
  2. 先読み字句を無しにする(まだ先読みしていない状態) TK_EOS
  3. メンバ(source)にソースコード格納
  4. デバッグ用?に現在の行数と最終行数を1に初期化
  5. ZIO(?)を格納

llex詳細

文字列から字句を判別して返却する

check_next

現在の文字が与えた文字集合に属するか判別し含まれる場合、確認する文字を1つ進める。 その際、次の字句の為にbufferに文字を追加する。

save

字句に対応する文字列を特定する為に字句解析最中に文字をバッファに保存する。

read_numeral, read_string, read_long_string

それぞれ対応する字句か判別すると思う。

その他

他にある関数は以下で詳細は追っていない。

  • txtToken
  • luaX_token2str
  • luaX_newstring
  • skip_sep
  • buffreplace
  • trydecpoint

字句の登録

字句の登録は配列 luaX_tokens で行なった。 対応する様に`enum RESERVED に字句種別を登録する必要がある。 llex が字句識別の本体なので他の真似をして追加した。 これらの事を行なったコミットが以下。

ref. https://github.com/masu-mi/lua-with-yorihijouni/commit/3b601929ee2d6fd5ba87e31ad7f8795abe4a7047

書いたときは普通にTK_WHILEより後ろにTK_LSなどを追加したが以下の記述があったので予約語として扱われる為には TK_WHILEより前に置くか下の記述のTK_WHILEを自分で追加した予約語に置き換える必要がある。

#define NUM_RESERVED>-(cast(int, TK_WHILE-FIRST_RESERVED+1))

これを怠ると何が不都合なのかはまだわかっていない。

  • ガベージコレクションの対象になる? そもそも文字列が生成されないので問題になるかわからない
  • 字句から予約語の文字列として引き当てに失敗するのかも知れない 前に書いた時は引き当てられていたけどそれは対応する意味情報として引き当てていただけ?

感想

字句解析は単純な処理だけあり読み易い。 ただLua仮想機械でエラーが把握するためにLua文字列の生成や メモリ・バッファの管理などが入り組んでしまう所もある。

字句解析処理はllexで決まっていて既にcodeになっているのに対応する予約語は 後からLua仮想機械に文字列として登録する仕掛けになっているの何でだろうって思った。

次は何処を読もうか迷っている。 順当には構文解析なのだけどLuaはLL(1)手書きなので想像はつく。 やはり, lcode, lvm, ldo あたりに手をつけた方が得る物が大きいだろうか。

]]>
Sat, 02 Nov 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/30/lua_with_yorihijouni.html http://blog.masu-mi.me/2013/10/30/lua_with_yorihijouni.html <![CDATA[Luaに演算子を追加してみた]]> Luaに演算子を追加してみた

NetBSD、カーネル内部でLua動作 ってニュースがありました。 さすが変態OSって言ってる人もいた。 とりあえず、読むだけでなく中のソースコードを触るきっかけに使わせてもらいました。

タイトル通り << >> 演算子を追加しました。 github

書き換えた箇所

以下のオペコード生成までがLuaバイトコード生成の部分。 演算子の追加のために仮想マシンを書き換えた。実際の挙動のためにイベント・タグメソッドを実装した。

llex.c, llex.h 字句解析器
lparser.c, lparser.h 構文解析器
lcode.c オペコード生成
lvm.c 仮想マシン
ltm.c, ltm.h イベント, タグメソッド

Luaの構文解析器は手書き

理由は以下が 挙げらていた

  • 生成されたコードがANSI C標準でない
  • クオリティコントロールが難しい(解析時スタックオーバーフローなど)
  • 再入可能ではない(解析中にパーサを呼び直すなど)
  • ボトムアップ型パーサーは実行時コード生成にあまり向かない

ただ文法を記述してコードが生成されるのと違って管理コストが大きくシンタックスが成熟する前に手書きにするのはお勧めしないと書かれていた。

書いてみたのだが、自然に感じる記号を選ぶという事は難しいと思った。また演算子を追加するとプリミティブ全てに対してサポート有無・内容を決める必要が出てくる。 この判断は表面的な文字列から逸脱してはならない。 気楽にテーブルだけで適用される << を追加したのだけど不自然だし扱い辛い事この上なかった。

近いうち、構文解析やタグメソッド呼び出し機構など内部の機構と関連関数に関してまとめようと思う。

]]>
Wed, 30 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/21/load_grunt_tasks.html http://blog.masu-mi.me/2013/10/21/load_grunt_tasks.html <![CDATA[load-grunt-tasks が便利で…]]> load-grunt-tasks が便利で…

Gruntタスクに load-grunt-tasks と言うのがある。

githubのREADME.mdに書いてあるけど1行コードを書くと必要なタスクをAutoload するらしい。 要するに以下みたいなコードが不要になる。

grunt.loadNpmTasks('grunt-shell');
]]>
Mon, 21 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/21/try-yeoman-etc.html http://blog.masu-mi.me/2013/10/21/try-yeoman-etc.html <![CDATA[Yeoman+Jasmine+BackboneJS始めました]]> Yeoman+Jasmine+BackboneJS始めました

テスト駆動JavaScriptを勉強する事にした。 題材として評価過程をアニメで表現する brainfa*k 評価器を BackboneJS で書く事にした。

BackboneJS 入門は以下が良いんじゃないかと思います。私はアドベントカレンダーとドキュメントで何とかごまかせています。

開発準備は Yeoman を使う。 Yeoman は開発にまつわる雑務を請け負うコマンドツール。 なんか色々やってくれるらしいのだけどあまり詳しくは知らない。 例えば、noscript対応・旧ブラウザ対応などが済んだテンプレHTMLを生成したり scssCoffeeScript のトランスレートを行なうビルド環境を準備したりする。

今回はMVCフレームワークに BackboneJS 、テストフレームワークに Jasmine を使う。 そのため以下のコマンドを叩いて Yeoman にgeneratorを追加した。

yo install generator-backbone
yo install generator-jasmine

これで YeomanBackboneJS 用プロジェクトを吐き出せる様になる。 あとは以下のコマンドでスケルトンを作る。

yo backbone
yo jasmine
yo backbone:model hoge
yo backbone:view  hoge

プロジェクトの依存関係の管理について

Yeoman では外部リソースは以下で管理するのがデフォルトになる。

対象 管理ツール 定義ファイル
パッケージ npm package.json
クライアントjsライブラリ Bower bower.json

yoコマンドで生成するとオプションで指定しない限り自動で依存pkg, ライブラリを取得してくれる。 ただライブラリが消えてしまったり依存関係に変更を加えた場合は以下で再取得できる。

npm install
bower install

これで準備が完了した。

早速、動くか確認する為に Grunt を動かす。 Grunt はタスクをプラグイン形式で扱う抽象化されたビルドツールでテストやwatchなども可能だ。

grunt build
grunt server

実行したら、依存している scss ファイルに不正文字が含まれていてコンパイルエラーになった。 外部pkgに手を加えるの嫌だけどコメントに変な文字が含まれていただけなのと勉強目的なので削除した。 動く事を確認した。とりあえず Hello World は終了だ。

Jasmine でテスト駆動開発だぜーって所で問題が生じている。

テストケース内部でjsモデルが見えていない。 Grunt から Jasmine の設定を書き換えてglobalに定義した関数は見えたが window 以下に定義したオブジェクトは見えていない。

またFirebugで確認したら modernizr.js が生成されておらず(?)404エラーになっていた。

上記2つはまだ解決していない…

Jasmine の元々の設定もファイル結合で生成されるファイルを対象にしている雰囲気だ。 なので残っている課題は2つ

  • Grunt でJavaScriptファイルを結合するconcatを適切に設定し直す
  • Grunt 経由でJasmineを呼ぶ場合のwindowの扱いなど - PhantomJS上で動いているっぽい

とりあえず使った事がないツール・フレームワークが組合わさった環境に挑むと苦労する。

中間ファイルが生成されていないのは、自分の設定ミスなのかバグなのかすら判断が付かない… (生成して試しただけで modernizr.js が生成されず404になっている事を考えるとバグな気もするけど)

しかし、そんな状況も調べながら手早くこなす頭の使い方・背景知識は身に付けておかないと不便だし。 Yeoman , Grunt , Bower , Jasmine , PhantomJS とかどのみち標準ワークフローの候補なので勉強すると得な事が多い。

まず Jasmine の使い方、次にgenerator-backboneでのconcatの意図や Grunt でconcatの使い方を調べる必要がある。

対応のために以下を読んだりして勉強する。

]]>
Mon, 21 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/19/memo_rabbit_mq.html http://blog.masu-mi.me/2013/10/19/memo_rabbit_mq.html <![CDATA[チーム勉強会: RabbitMQ]]> チーム勉強会: RabbitMQ

ずいぶん昔に RabbitMQ について聞きかじった。 スライドにまとめようとか思っていたけれど、 そんな事を考えていると完成しないので、 当時の Markdown なメモを reST に書き直して晒す。

RabbitMQ 概要

プログラムの重要な要素には <操作/データ> がある。 はっきり切り分けられない事も多いが有用な分類だ。

ミドルウェアもシステムの要素と捉えると上記の2つのどちらかを提供している。 プログラム要素よりも更に曖昧だが、こう捉える事はやはりスタートが早い。

名前の通り RabbitMQ はMQシステムだ。 Queueを提供する「データ構造ミドルウェア」で非同期・永続化通信を実現する。

MQ含めた メッセージ指向ミドルウェア(MOM) は、 疎結合を維持しながら複数システム間の連携を実現するらしい。 まぁ非同期・永続化は、時間的制約を無くしつつ通信を保証されている通信なため、 連携させても切り離し易さを維持し易いのだろう。

サポートプロトコル

MQプロトコルにも幾つか種類がある。 RabbitMQがサポートしているのは以下 - AMQP サポート状況 - STOMP (Pluginによるサポート)

Pluginでサポートされているのはもっとある(MQTT とか)。

モデル(仕様)

構成要素は以下で捉えられる。 (チュートリアルを読むと徐々に登場するので理解し易い)

exchagne メッセージの入り口でありQueueへの振り分けなどを行う
Queue メッセージを溜め込むFILO
Producer メッセージを送信するクライアント
Consumer メッセージを受信するクライアント

実装

リポジトリ

言語 Erlang
フレームワーク Open Telecom Platform

勉強用資料

osxなら homebrew で入るので実験は気楽に出来る。 しかも rabbitmq_management (Web管理画面plugin)が最初から入っている。

brew install rabbitmq
/usr/local/sbin/rabbitmq-server
open http://localhost:15672/

読んだ資料はこの辺り。

コミュニティ

]]>
Sat, 19 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/19/bash_test.html http://blog.masu-mi.me/2013/10/19/bash_test.html <![CDATA[testコマンドで少しハマったのでメモ]]> testコマンドで少しハマったのでメモ

.bashrc${PATH} を設定している。 dotfileは githubで管理 してて複数サーバーに対応させ(様とし)ている。 問題が2点あった。

  • 実際に存在しないPATHも読み込んでしまっている

    dir 存在チェックで対応

  • .bashrc を再読み込みするとPATHに同じdirが登録されてしまう

    ${PATH} 存在チェックで対応

if というか [] で少し躓いた。 -a でバッククォートした $PATH チェックを繋ごうとしたら失敗。 2つの []&& で繋いでも良いのだけど折角 [] 使っているのに変な感じがした。 なので略記を使わず test を明示する方針にした。

結局、関数は以下の形になった。

# 関数定義
function add_path {
    if test -d $1 && test `echo ${PATH} | grep -v $1` ; then
      export PATH="$1:${PATH}"
    fi
}
# 使用例
add_path "/usr/local/bin"

これで上記2つの問題の大部分は解決する。

ただ eval "$(rbenv init -)" の実行が ${PATH} を変更するので、 ${PATH} が伸びる問題は完全には解決していない。

これは rbenv のオプションで対応・実行条件で対応・サブシェル内で関数定義、 などで対応出来る筈。 一旦は別の問題として対応する事にした。

]]>
Sat, 19 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/13/try_fabric.html http://blog.masu-mi.me/2013/10/13/try_fabric.html <![CDATA[Fabricを試してみた]]> Fabricを試してみた

Fabric はシェルスクリプトを補い強化する Python製のライブラリ&ツールだ。

思いつく便利になる点は

  • 複数ホストへの並列実行
  • Pythonでサポートされるデータ構造を利用出来る
  • シェルより変数など扱い易い
  • with 構文でコマンドの実行時コンテキストが明確になる
  • 環境構築の作業が関数(sudo(), local(), etc)で提供され明確になる

になる。 類似ツールに Cinnamon (Perl製) がある。

インストール

pythonは2.5以上が必要。pipでインストールする。 version 1.7 がインストールされた。

やってみた: Doxygen の解析結果を公開する

以前LuaソースコードをDoxygenで解析し結果を公開した。 その作業をFabricで自動で行う様にしてみた。 作業ディレクトリに以下の内容で fabfile.py を作成した。

# coding:utf-8
from fabric.api import lcd, local
from fabric.contrib import project
from shutil import copyfile
import os.path


def setup_lua_doc(ver="5.1.5"):
    """
    特定ver.のLuaを取得してdoxygenで解析してhostingする
    """
    # 変数使って取得するLuaのバージョンを変更している
    lua_name = 'lua-' + ver
    local("wget http://www.lua.org/ftp/%s.tar.gz" % lua_name)
    local("tar zxvf %s.tar.gz" % lua_name)
    local("git clone https://gist.github.com/6752426.git")
    # 本当はコピー前にver 使ってPROJECT_NAME を書き換えるようにする
    # 良い方法がわからなかった
    # - Gist内容をJinjaテンプレート化する
    # - 正規表現で置き換える
    copyfile(
        os.path.join(".", "6752426", "Doxyfile"),
        os.path.join(".", lua_name, "Doxyfile"))
    with lcd(lua_name):
        local("doxygen")
        put_garage("html", "lua-graph")

def put_garage(path, proj_name):
    project.rsync_project(
        os.path.join("/", "var", "www", "garage", proj_name),
        path)

上記を準備し以下のコマンドを叩く。

$ fab setup_lua_doc:ver=5.1.5 -H garage.masu-mi.me

引数を渡すにはコマンド名の後ろに : を使用する。 また、引数が複数ある場合は , で区切る。 実は今回の場合はデフォルト引数と一致しているので渡す必要がない。

これでLuaを落としてきてDoxygenを実行してrsyncで同期するまでが直ぐに実行可能だ。 put_garage() を使えばクライアントだけで動く物に付いてはgarage以下に直ぐに配置出来る。

シンプルなので、こんな風に使い回し易くて良さそうだ。

呼び出している関数の説明

詳しくは Fabric-1.7 を読んで下さい。

local()
ローカルホストでシェルコマンドを実行する。
lcd()
ローカルホストのカレントディレクトリを変更する。 上記の様にwith構文に対応しておりwith文から抜けるとカレントディレクトリは元に戻る。 (リモートホストのカレントディレクトリを変更したい場合 cd() 関数がある)
project.rsync_project()
対象ディレクトリを rsync で同期する。

他にもリモートホストでシェルコマンド実行する sudo(), run() やファイルを送信する put() などがある。

]]>
Sun, 13 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/12/add_social_buttons.html http://blog.masu-mi.me/2013/10/12/add_social_buttons.html <![CDATA[ソーシャルボタン類を追加した]]> ソーシャルボタン類を追加した

Webコンテンツ群はソーシャルPFへの導線を準備しておくのは定石だ。 って訳でこのブログにも設置してみた。

参考にしたのは以下

FB likeボタンは実装方法が複数あり選択基準を定められなかった事と、ogを整えてから設置したいって思ったため後回し。 さっさとogを整えたい。 Sphinxで参照可能な変数の中身や追加方法が調べる必要がある。

]]>
Sat, 12 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/10/04/add_comment.html http://blog.masu-mi.me/2013/10/04/add_comment.html <![CDATA[DISQUS を試してみた]]> DISQUS を試してみた

ブログにコメントを付けるたくなり調べたら。 TinkerはFacebook or DISQUSが定番的な空気を感じた。 ここは挑まず空気を読む。

DISQUSに登録する

DISQUS というサービスがコメント機能を提供している。 画面左下の”Add Disqus to Your Site” を踏んで設定を済ませる。 コメントを設置するサイトの設定・管理者のアカウント登録を済ませる必要がある。

サイトの設定項目

項目 内容
Site URL サイトのURL
Site Name サイトの名前(日本語もOK)
Site Shortname サイトの略称, disqus.comの管理画面用サブドメインに使われたりする

Tinkererでの設定

利用するにはconf.pyに以下を追記する。

disqus_shortname = 'Site Shortname'

1行書き加えただけで動いた。 こりゃ定番になるわ…

]]>
Fri, 04 Oct 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/09/29/used_doxygen.html http://blog.masu-mi.me/2013/09/29/used_doxygen.html <![CDATA[Doxygen&Graphizの利用]]> Doxygen&Graphizの利用

Luaコードを読むにあたりコールグラフ・参照グラフを書き出したら楽だと思い、 Qiita記事 を参考に試してみた。

すぐにクラス(そもそもCだし構造体だけど)の参照関係は吐き出せる。 ただ求めていた関数間のコールグラフを吐き出していない。

設定ファイルの中を読んでいたら EXTRACT_ALL なる項目があった。 ここを YES に設定したところ無事に吐き出されました。

コメントによると:

可能な限り全ての説明項目を出力する。 EXTRACT_PRIVATE, EXTRACT_STATIC の項目を YES にしない限りprivate・staticな要素は隠蔽する

らしい。 ALL なんて過激なオプションじゃなくFUNCTIONの項目だけ出力したい。 ところが探しても EXTRACT_FUNCTION なんて直球な名前は無かった。 幾つかのオプションを試してみたけどALLを切った状態では表示されない。

とりあえず EXTRACT_ALL で満足する事にした。

そのDoxyfileは gist に残した。 解析結果は こちら

記事以外のドキュメント類や実験サイト・サービスとかは garageサブドメイン以下で晒して行こうと思う。

]]>
Sun, 29 Sep 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/09/29/gild_tinkerer_template.html http://blog.masu-mi.me/2013/09/29/gild_tinkerer_template.html <![CDATA[ブログの見栄えと機能を改良する]]> ブログの見栄えと機能を改良する

変更可能なのかも知れないがTinkererのテンプレートエンジンは Jinja2

Jinja2テンプレートの使い方

Jinja2 埋込み

記法 意味
{{ apple }} 変数展開
{% for i in list %} 構文
{# comment #} コメント

Jinja2 ブロックと継承

ブロックと呼ばれる機能がある。以下の様に囲まれた領域に名前を付けられる。 複数回呼ぶ場合や継承を通して上書きする事が可能になっている。

<h1>ブロックの例</h1>
{% block social %}
<div>なんか色々あるよ</div>
{% endblock %}
{% block footer %}
<footer>ショボいフッター</footer>
{% endblock %}

継承する場合, sphinxの探索パスからの相対パスで指定を行いブロックを再定義する。

{% extends "layout.html" %}
{% block title %}シンプルな内容に上書きする{% endblock %}
{% block footer %}
文言を手前に出力する。
{# blockを複数回出力したい場合はself.ブロック名 #}
{{ self.title() }}
{% block inner_block %}
  <p>ネストは許可される。さらにendblockの後ろにブロック名を明記する事も可能</p>
{% endblock inner_block %}
{# 親テンプレートの内容を利用する場合はsuper() #}
{{ super() }}
{% endblock footer %}

extends での探索パスについては調べてない。 tinkererだと conf.py のtemplate_path, html_theme_path 直下が使われるっぽい。

他にも Jinja2 には空行・空白のコントロール・ ネストしたブロックのスコープ操作や略記等があるのでDocumentを読むと良い。

Tinkererでのテンプレート継承関係

大事なテンプレート

  • layout.html
    • ブログ全体で利用する全体像
  • page.html
    • コンテンツ部分等を変更(layout.htmlを継承したり)
  • aggregated.html
    • トップページ用(page.htmlを継承したり)
  • archive.html
    • アーカイブページ用(page.htmlを継承したり)

他に何が自動で読み込まれるのかは調べていない。

テンプレートファイルの探索先

プロジェクトdirを {$PROJ} と記述する。 読まれるテンプレート関連のファイルは、以下の様になる。

{$PROJ}
  | - conf.py            # 全体設定 テーマ名(html_theme)
  | - _themes            # テーマ定義
       ` - ${THEME_NAME}  # 個別作成テーマ
  ` - (templates)        # テンプレート準備個所

探索順序は以下の様になっていた。

  1. {$PROJ}/_template
  2. {$PROJ}/conf.pyhtml_theme 項で設定したテーマディレクトリ({$THEME})
  3. {$THEME}/theme.confinherit 項で設定した継承元テーマディレクトリ({$SUPER_THEME})

テーマディレクトリの探索先

前述の {$THEME}, {$SUPER_THEME} などテーマディレクトリは何処を探索されるかまとめる。

ちなみに自分だとtinkerer のインストール先ディレクトリ({$PACK})は、 $HOME/.virtualenvs/for-blog/lib/python2.7/site-packages/tinkerer だった。

デフォルトではテーマディレクトリは以下が探索される。

  1. {$PROJ}/_themes
  2. {$PACK}/themes

テンプレートに渡される値

tinkerer経由でJinja2に渡される値は未調査…

]]>
Sun, 29 Sep 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/09/23/void_0.html http://blog.masu-mi.me/2013/09/23/void_0.html <![CDATA[((void)0)の使い方]]> ((void)0)の使い方

ヘッダファイル lua/lua-5.2.2/src/llimits.h に以下の様なマクロが定義されていた。

#define lua_lock(L)     ((void) 0)
/* ... */
#define lua_unlock(L)     ((void) 0)

(void)0 は何もしないopコードを吐くらしい。何でこんなのを書くのかサッパリだった。

検索したらこんなのを見つけた stackoverflow::Purpose of lua_lock ...

これによると、Luaを別のプラットフォームに移植する際に lua_lock, lua_unlock を上書きし mutexなどのロック機構を導入する事でPythonのGILみたいな事を実現するためらしい。 なので #if !defined(lua_lock) で囲まれており上書き時は定義されていない。

そこで ((void) 0) じゃなく /* no lock mechanism */ コメントだったら駄目なのか考えた。 結論は ((void)0) の方が良い。

理由は以下の様なコードが存在した場合コンパイルを通過しなくなるため。

apple? lua_lock(L) : orange();

コメントへ置き換えるマクロでは、三項間演算子が不正でコンパイルエラーを起こす。 見た目が式なので式として振る舞う方が混乱が少ないからだ。

]]>
Mon, 23 Sep 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/09/21/ruby_community.html http://blog.masu-mi.me/2013/09/21/ruby_community.html <![CDATA[ツールを生み出すRubyコミュニティは作法のハードコートで育ったのかしら]]> ツールを生み出すRubyコミュニティは作法のハードコートで育ったのかしら

このまえ同期と少しRubyについて話した。 同期はRubyを触った事が無いらしく雑談の中で「どんな感じ?」と聴いてきた。

雑談は紆余曲折を経て「何故Rubyコミュニティは多くのツールやDSLを生み出してきたのか?」について答える形で終わった。 私も”メタプログラミングRuby”を読んだばかりで詳しくないため印象に過ぎないが結論めいた物は出たのでメモしておく。 ただ本当にこんな結論だったかは酒も手伝いイマイチ覚えていない。

フルスタックエンジニアってRubyist界隈から始まった言葉なのですかね

Rubyにはシステム構築・管理等をコーダー視点で解決するツールが非常に多い。 Rubyはあくまで開発者を想定している印象がある。 企画・システム管理者を想定したツールって少ない印象がある。

私は開発者だし恩恵を受ける立場だけど、CMS等は少なく他の立場にも優しいコミュニティといった印象はない。

柔軟で読みにくいRuby

まず言語の特性から考えてみた。 Rubyはメタプログラミング・DSL実装が気楽に出来るほど柔軟だ。 (PHPで似た事をやろうとすると記述量がとんでもなくなるし泣ける)

思いつくだけでも、

  • 無名関数
  • ブロック
  • オブザーバブルな言語操作
  • 単純なオブジェクトモデル
  • モジュールインクルード
  • リフレクション
  • オープンクラス
  • (ブロック内self)の動的スコープ
  • 多様な略記

そして可読性を消し飛ばせる言語でもある。 そのためユーザー(プログラマー)間で可読性を維持する為に作法・イディオムの共有が重要になる。

作法のハードコート

この問題の一部はRuby自身の柔軟性が解決している。 柔軟であるため関心対象を限定したDSLを作る事が可能で「作法」をハードコートしてしまう。 初級者は上級者の強制した作法の影響を受ける。 これにより作法の共有という曖昧な文化的問題の多くは(少なくともDSLを書ける程度の)上級者に限定される。

カリスマ性って大事

では上級者の間で作法の共有はどのように維持されるのか。これはカリスマが解決しているのではないか。 要するにMatzが上級者を牽引して言語の(使い方含めて)方向性が定まる。 実際とても積極的に引っ張る人という噂だし…

開発者向けツールが生まれる流れ

要するに、柔軟で可読性を落とせる言語でカリスマの牽引力が強いため以下が繰り返される。

  1. Rubyistは敷居が低い事もあり可読性維持の為にDSL・ツールを作る
  2. Rubyに触れているとDSLなどツール類に出会う。意欲的なユーザーは”開発者向けツール”に挑む
  3. 受け入れられる開発者向けツールは既存の上級者に受け入れられる作法を共有している必要がありRubyコミュニティ全体で方向が維持される
  4. また車輪の再発明を避けると、開発以外の問題を対象とした言語・ツールが生まれる

酔いが醒めてから

Matzが居なくなったらどうなるのかは気になる点だ。 コア開発の方では不穏な噂が立っては消えしている。 標準化はMatzの仕事抱え込み過ぎ状態を解消する布石になるのかも知れない。

上級者向けの解決要因は大分怪しい。コア開発レイヤのコミュニティの印象になっている。 そして開発者がDSLやツールを作る時に「なぜ”開発者向け”ツールを作るのか」には実は答えられていない。

酔っぱらってると変な論に落ちるもんですねって言い訳を書きたくなるし書いている…

]]>
Sat, 21 Sep 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/09/08/lua_macros.html http://blog.masu-mi.me/2013/09/08/lua_macros.html <![CDATA[Luaコードを読んでいて気になったマクロ]]> Luaコードを読んでいて気になったマクロ

luaのソースコードを読んでいてマクロの使い方に感心した。 そんなに真剣にプログラミングのイディオムとか勉強した事無かった。

複数環境に向けたシンボルを晒す

以下はluaconf.hで定義されている。

LUA_API core API function
LUALIB_API 補助関数
LUAMOD_API 標準モジュールの外部関数

これらを関数宣言の前に記述する事で役割を明記しつつVisualStudio対策も行っている。 __declspec(dllexport)はDLL作る時に外部晒す関数で宣言するキーワードらしい。

#defined(LUA_BUILD_AS_DLL)

#if defined(LUA_CORE) || defined(LUA_LIB)
#define LUA_API __declspec(dllexport)
#else
#define LUA_API __declspec(dllimport)
#endif
#else
#define LUA_API extern
#endif
/* ... */

#define LUALIB_API>-LUA_API
#define LUAMOD_API>-LUALIB_API

モジュール外へ公開する意図のない識別子の宣言

関数・定数・変数の定義を分けている。 意図を明確にするというのは大事だね。pythonでプライベート的なメソッドは_leadingにするってのに近い。 特にアクセス範囲などは定型情報だし、コメント(自然言語)より記法(マクロ)の方が良いのかも知れない。

#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
     defined(__ELF__)
#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF /* empty */

#else
#define LUAI_FUNC extern
#define LUAI_DDEC extern
#define LUAI_DDEF /* empty */
#endif

キーワード__attribute__はGCCで引数・返値の形式をコンパイラに通知する事で可変引数を実現したり, 返り値が存在しなくてもコンパイラがwarnを出さない様にしたりする。

同じキーワードなのにARM系だとシンボルの可視性をコントロール出来る。なんか毛色が違う気がした。

エキスパートC読もうって思った。 次はLuaVMのlua_State,global_Stateとか仮想マシンの操作周辺について調べる。 あとライブラリの作り方についてもまとめておいた方が良いな。

]]>
Sun, 08 Sep 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/08/31/brew_error.html http://blog.masu-mi.me/2013/08/31/brew_error.html <![CDATA[Homebrew Updateの更新時エラー]]> Homebrew Updateの更新時エラー

brew update でエラーが出たのでメモする。

$ brew update
$ vim drafts/brew_error.rst

[No write since last change]
error: The following untracked working tree files would be overwritten by merge:
        Library/Formula/haxe.rb
Please move or remove them before you can merge.
Aborting
Error: Failure while executing: git pull -q origin refs/heads/master:refs/remotes/origin/master

shell returned 1

Press ENTER or type command to continue
[No write since last change]
エラーコメントを超訳するとこんな感じ。
ちょっと奥さんアップデートはgit pullが実態でして、このままだとtrackされてないhaxeのformulaがmergeの際に上書きされちゃうよ。moveとかして下さいよ

いま削除してもアップデート後にはhaxeのformulaは利用出来る筈で削除しても大丈夫そう。

ついでに cd /usr/local/Library/Formula && git status したら大量にtrackされていないformulaがあった。いつこんなに追加されたのか気になる。

他のformulaは上書きするコメント出てないし謎formulaが沢山あるからといっても git reset --hard HEAD をしたらインストール出来なくなるpkgとか出てきそう。

そのため素直に haxe.rb だけ削除した。無事アップデートできた。

]]>
Sat, 31 Aug 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/08/31/practice_lua.html http://blog.masu-mi.me/2013/08/31/practice_lua.html <![CDATA[Luaソースコード読みはじめる]]> Luaソースコード読みはじめる

Luaの構造を掴むためにヘッダファイルを眺めたりしたのでメモを残しておく。

Lua実装のヘッダファイル達

$ ls src/*.h
src/lapi.h      src/lctype.h    src/lfunc.h     src/llimits.h   src/lopcodes.h  src/lstring.h   src/lua.h       src/lundump.h
src/lauxlib.h   src/ldebug.h    src/lgc.h       src/lmem.h      src/lparser.h   src/ltable.h    src/luaconf.h   src/lvm.h
src/lcode.h     src/ldo.h       src/llex.h      src/lobject.h   src/lstate.h    src/ltm.h       src/lualib.h    src/lzio.h

それぞれの内容

ヘッダファイル 概要
lapi.h 補助関数群
lauxlib.h 補助関数(Luaライブラリビルド向け)
lcode.h LuaVM オペコード生成
lctype.h Lua向けctype関数群(文字種判別とか)
ldbebug.h きっとデバッグ向け
ldo.h コールスタックの操作等
lfunc.h prototype, closureを操作する補助関数群
lgc.h きっとガベージコレクション
llex.h 字句解析器
llimits.h 最大値,最大長など限界や範囲を定義している
lmem.h メモリ管理インタフェース
lobject.h Luaの型を定義している
lopcodes.h Luaオペコードの定義とインタフェース
lparser.h Lua構文解析器(LL1,手書き最適化)
lstate.h LuaVMの状態管理用構造体の定義 CallInfo,global_State,struct lua_State,GCObject
lstring.h StringTable(Luaの文字列を全て格納管理する)の定義
ltable.h Tableオブジェクトの定義
ltm.h タグメソッド(メタメソッド)の定義
lua.h lua REPL
luaconf.h lua コンパイル用の設定など?
lualib.h Lua 標準ライブラリ
lundump.h コンパイル前のLuaチャンク(コード片)の操作?
lvm.h LuaVMの操作
lzio.h バッファ付きストリームのインタフェース

ヘッダ無しのファイル

ファイル 概要
luac.c Luaコンパイラ
loadlib.c 動的ライブラリのローダ

今度REPL,CompilerからLuaVMがどう呼ばれて利用されているかまとめて見ようと思う。 またはLuaVMがスタック操作をどう行っているか?や動的ライブラリの読み込み部分のあたりかな。

]]>
Sat, 31 Aug 2013 00:00:00 +0900
http://blog.masu-mi.me/2013/08/24/my_first_post.html http://blog.masu-mi.me/2013/08/24/my_first_post.html <![CDATA[Tinkererでblogを立ててみた]]> Tinkererでblogを立ててみた

ちゃんと自ドメインでお金払ったサーバー(VPS)ってネット内の一等地が欲しかった。 さくらの VPS を契約してからやったこと を参考にblogを立てた。 上記のエントリはリンクの後に、その4 , その5 までありTinkererでブログをビルドして gitoliteで自動ホスティングまで丁寧に書かれている。

blog用リポジトリにpushした時にhookスクリプトが失敗してて何かと思ったらpermissionの問題だった. /var/www/blog/tinkerer/blog/html以下がrootになっていた。 なんでrootになってしまってたかわからない。 /var/www/blogにリポジトリをmvした時にまだ存在しなかったからだろうか…

まずはCSS を少し改良したりモジュール追加する。 次にFabricで再構築出来る様にする。 実験・翻訳・スライドの配置場所を作らないと。

]]>
Sat, 24 Aug 2013 00:00:00 +0900