2017/04/22

tmux 2.4 を全角記号対応させる

2017/04/20 に tmux 2.4 が Release されていたので、前回の記事に書いたパッチを 2.4 にも当ててみました。
tmux 2.4 の border-ascii + EastAsianAmbiguous を強制2幅 版です。

作業としてはは rebase したただけなので修正点は全くありません。


環境

  • macOS Sierra 10.12.4
  • Homebrew 1.1.12-40-g02f018933
  • Homebrew/homebrew-core (git revision 5559; last commit 2017-04-15)
  • tmux 2.4 (正確には 2.4リリース以降の fd13731049148d0205fa6ed1843041dad0573677)
  • utf8proc 2.1
  • フォントは Ricty

インストール手順

  • $ brew tap atton-/customs
  • $ brew install atton-/customs/utf8proc
  • $ brew install --HEAD atton-/customs/tmux


atton-/customs/tmux の formula は HEAD build しか対応していないので、もし 2.3 のパッチ版が使いたい場合は tap したリポジトリを巻き戻すことで 2.3 が使えるはずです。
おそらくもっと楽な巻き戻し方があると思いますが、個人的には最新しか使っていないので調べていません。

2017/04/16

tmux 2.3 を全角記号対応させる

tmux 2.3 をちょっといじって全角記号の幅を2にした版を作ってみました。


環境

  • macOS Sierra 10.12.4
  • Homebrew 1.1.12-40-g02f018933
  • Homebrew/homebrew-core (git revision 5559; last commit 2017-04-15)
  • tmux 2.3 (正確には 2.3リリース以降の 640666fb36d7465b188f9d0bedc83ad60b83a1d7)
  • utf8proc 2.1
  • フォントは Ricty



状況

tmux を使っていると ─(U+2500) や(U+25bd) な文字の幅が半角扱いになってしまい、表示がおかしくなる時があります。
例えば、画面を縦2つに分割すると



のように線が何故か二本表示されたり、記号の表示が変になってしまいます。

これは分割に使用されている文字(─)の幅の扱いを tmux が勘違いしているために起こる問題です。
─ といった記号は EastAsianAmbiguous といった種類に区分され、言語圏によって文字幅が違います。
例えば英語圏では基本的に使う文字幅は1なので ─ の幅は1ですが、日本語圏では全角が基本なので文字幅は2となります。
この問題に関しては https://github.com/hamano/locale-eaw などが詳しいです。


解決法

これは Terminal の設定と locale の設定とフォントに依存するので解決方法はいくつかあります。
今回は
  • Terminal は EastAsianAmbigous を Full-Width にしている
  • フォントは日本語フォント( EastAsianAmbiguous は幅2)
  • locale には依存しない (en_US.UTF-8 でも ja_JP.UTF-8 でもOK)
の時を想定しています。
具体的には tmux が文字幅の取得に使っている utf8procちょっといじって、EastAsianAmbiguous の幅を強制的に2にしています。
あと、画面分割に使う文字を ascii にしています。


インストール方法

formula にしてあるので

  • $ brew tap atton-/customs
  • $ brew install atton-/customs/utf8proc
  • $ brew install --HEAD atton-/customs/tmux
でインストールできます。
縦に分割した時に


のようにきちんと線が1本になるはずです。



まとめ

強制的に EastAsianAmbiguous の幅を2にして日本語フォントとの相性を良くしました。
実はこれは対処療法的な解決案で、根本的な解決ではありません。
その辺りは結構長くなると思うので書くなら別の記事で書きます。


参考文献

2016/12/21

qcow2 の cluster leak を直す

qcow2 の cluster leak を直してみたログ。
オチがついてて原因が完全特定できていないのでふわっとしたお話。


環境

Host OS: CentOS 7.1.1503
Host Kernel: 3.10.0-327.4.5.el7.x86_64
qemu-img: 1.5.3


状況

VMイメージ を GFS2 上に置いているVMで ls が返ってこない。
pcs から見る限り clvmd も dlm も全ノード上で動いているし全ノード online になっている。
過去にクラスタの1ノードが物理的な問題で急に落ちたこともあって VM イメージの破損を疑ってみる。
調べてみると qcow2 の整合性の確認には qemu-img の check コマンドを使うことができるらしい。

qemu-img check を qcow2 に対して打つとこんな結果が返ってくる。
[root@hoge ~]# qemu-img check /mnt/hoge/fuga.qcow2
Leaked cluster 42362 refcount=1 reference=0
Leaked cluster 42363 refcount=1 reference=0
Leaked cluster 42364 refcount=1 reference=0
Leaked cluster 42365 refcount=1 reference=0
4 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
65043/524288 = 12.41% allocated, 0.15% fragmented, 0.00% compressed clusters
Image end offset: 4264099840
何やらエラーが返ってきている。
同じ GFS2 の上にある VM に対しても qemu-img check すると
[root@hoge ~]# qemu-img check /mnt/hoge/piyo.qcow2
No errors were found on the image.
468877/524288 = 89.43% allocated, 0.13% fragmented, 0.00% compressed clusters
Image end offset: 30733303808
と返すので問題の VM のみがエラーを吐いているらしい。


解決方法

qemu-img check -h を読んでいると -r オプションがあって、リカバリを試すことができる様子。
Parameters to check subcommand:
  '-r' tries to repair any inconsistencies that are found during the check.
       '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all
       kinds of errors, with a higher risk of choosing the wrong fix or
       hiding corruption that has already occurred.
今回は cluster leak のようなので qemu-img -check r leaks を実行してみた。
どうやら上手くいったようで check してもエラーを返さなくなった。
直したイメージを起動すると ls が返ってきたのでめでたしめでたし。


オチ

これで直ったと思っていたらlsを返さない他のVMを発見。
そしてこいつは qemu-img check でエラーを返さない。
修復した VM の /var/log/messages に、 nfs への書き込みが time out している kernel panic っぽいものを発見。
両方のVMは同じ nfs をマウントしてたので nfs が原因説が濃厚に。
ちなみにある時間から nfs head server がレスポンスを返さない状態になっていたらしい。
おそらく前にもあった案件と同じ原因では無いかと思ってます。
しかし若干の謎があって、nfsをマウントしていたVMは最低限3つある上2つは死んでいたのに1つだけは生きていた。
しかも生きていたVMの mount option に intr は無い。
生きてたVMは書き込していなかった、とすれば辻褄はあうのですがそれはログからは分からなかった。

nfs server 側は私が直接触っていないので余計曖昧な情報ですが、レスポンスを返さない原因は特定のパーティションの容量が一杯だったせいとか。
容量一杯で nfs への書き込みができないのはともかく、それでハングするものなのだろうか。
最終的な対応としては nfs server 側の容量を空けることでおしまい。


ということで qcow2 の cluster leak を直したものの、本来の原因では無かった可能性がある。

2016/12/06

何故 Rails では View から Controller のインスタンス変数にアクセスできるのか

この記事は Okinawa.rb Advent Calendar 2016 6日目の記事です。


はじまり

むかしむかし、あるところでひとりのあっとんさんが Okinawa.rb Advent Calendar のネタをどうるか考えていました。
そこへ @CodeHex さんがあらわれ、ちょっと Rails について質問をしても良いですかと尋ねてきました。

CodeHex さん「Controller で @ を付けた変数は View からアクセスできるんですか?」
あっとんさん「Rails ではそうですね。ちなみに Ruby では @ が付いた変数はインスタンス変数なのです。」
CodeHex さん「なるほど。 Perl では @ があると配列なので違和感がありますね。」

さて、質問された時に Rails ではそういうものだという解答をしたのですがふと思いました。
「別にインスタンス変数だからと言って View から見えるのは関係が無いよね」
そこで調査班は実装を見付けるために Rails へと踏み込むことにしました。


View はどのようにインスタンス変数にアクセスしているのか

まずは View のクラスを確認してみます。
単に Controller を継承しているだけなのかもしれません。
それならこの記事は終わってしまいますがまず確認しないことには始まりません。

ということで Rails のプロジェクトを作ります
$ rails -v # 5.0.01
$ rails new advent2016
$ cd advent2016
$ rails generate scaffold user uid:string
ここで User#index に binding.pry を仕込んで self.class を確認してみます。
[2] pry(#<#<Class:0x007ffdce310d48>>)> self.class
=> #<Class:0x007ffdce310d48>
どうやら特異クラス。さて ancestors を確認してみると
となっていました。
継承しているものに Controller らしきものはパッと見は無いようですね。
調査は続行しそうです。

そこで self を確認していると
とそのまま @_assigns というインスタンス変数があることを発見。あやしいですね。
もちろんこの段階では @users は存在しているので
$ self.instance_eval{@_assigns= nil}
としても @users は変更されません。


@_assign を追いかける

@_assign はどこで変更されるのか。
調査隊はさらに Rails の奥へと踏み込むことを決意します。
$ git grep @_assigns
するとactionview/lib/action_view/base.rb の一つしかありません。
しかもやっていることは instance_variable_set なので怪しさしかありません。
assigns は引数なのでどこかで new されているはず。
次はそれを探します。


ActionView::Base.new はどこだ

まずは素直に git grep します。test もあったので grep -v で除外。
$ git grep ActionView::Base.new | grep -v test
actionpack/lib/action_controller/metal/helpers.rb が引っかかりました。
しかしこいつは module でこれが呼ばれるのを探すのは面倒。
また pry に戻って探してみることにします。

backtrace を覗く

また User#index の binding.pry に戻ります。
User#index の段階では view は用意されてるのでどこかで既に new されているはず。
なのでまず backtrace を眺めてみます。
pry-byebug を入れて pry-backtrace と打つと backtrace が見られます。
さて覗いてみると

多い。111もあります。
折角 byebug で repl も動くことなので up していきます。
途中で String を freeze しているころを見付けます。
噂の物体を副産物で見付けた気分ですね。
どんどん up していきます。
actionview/lib/action_view/renderer/template_renderer.rb の render_with_layout くらいから view という変数がちらほら出てきますね。あやしい。
view は context という名前になったりしながら連れ回されているようです。
actionview/lib/action_view/rendering.rb の _render_template までそれっぽいのがありますが、actionpack/lib/action_controller/metal/streaming.rb の _render_template あたりから出てこなくなります。
この辺りに真相が潜んでいそうです。
というか metal は見覚えがありますね。 ActionView::Base.new しているのも metal の helper でした。


結局どこでインスタンス変数を渡しているのか

最後に view っぽいのを扱っているのは actionview/lib/action_view/rendering.rb の _render_template でした。
context に view_context を代入しています。
view_context の定義に view_assigns という怪しさ満点のものを発見。
しかし rendering.rb に view_assigns は無い。
名前が分かればとりあえず git grep します。
actionpack/lib/abstract_controller/rendering.rb に定義を発見しました。
instance_variables を取ってきてhash にしています。
slice しているのは @ を取りのぞくためですね。
ここでおもしろいのは protected_vars を reject していること。
@_formats などは controller から渡さないようにしているようです。
view_assigns は AbstractController::Rendering に定義されています。
ということは ApplicationController が AbstractController::Rendering を継承していれば、ユーザ定義のコントローラは view_assigns を経由でインスタンス変数を取得して view を生成していそうですね。
となれば気になるのは UsersController の ancestors です。
と AbstractController::Rendering がばっちりありますね。56行目です。
という訳で「何故 View は Controller のインスタンス変数へとアクセスできるのか」を発見できました。
それは「Controller が View を Rendering する時に自分のインスタンス変数を渡してやっているから」です。


view_assigns を上書きするとどうなるか

実装が分かれば遊びたくなるのが常。
自分はきちんとコードが読めたのかも含めてちょっと遊んでみます。
内容は @users という変数を無理矢理作ってやるというもの。
この状態で user#index にアクセスすると DB の中身に関係無く、定義された内容が表示されました。
やはり view に渡すためのインスタンス変数を取得するメソッドは AbstractController::Rendering#view_assign で間違いない様子。
ということで無事 Rails の中からお目当てのものを見付けられました。
めでたしめでたし。


おわり

というおはなしなのでした。
読むのに pry-byebug が便利でした。
むしろ無かったら見付けられなかったかもしれない。
結論としては Controller で view_assigns を上書きすると大変なことになりそう、って感じです。


みなさま良い年末をー。

2016/11/29

Homebrew で Agda 2.5.1.2 を入れる

いつの間にか Homebrew で直接 Agda をインストールできるようになっていたので入れてみたログ。


環境

  • Mac OSX Yosemte 10.10.5
  • Homebrew 1.1.2
  • Homebrew/homebrew-core (git revision a06e; last commit 2016-11-29)
  • GNU Emacs 25.1.1
  • Agda 2.5.1.2


Agda のインストール

Homebrew が直接 formula を提供しているので
  • $ brew install agda
だけでOK。便利。


Agda の設定

  • $ agda-mode setup
するか、その時に表示される
(load-file (let ((coding-system-for-read 'utf-8))
                (shell-command-to-string "agda-mode locate")))
を ~/.emacs や ~/.emacs.d/init.el なりに書いておくとOK。
なんと便利なことに bottle の agda には std-lib が同梱されているので、いきなり open import Relation.Binary.PropositionalEquality とか書いて使うことができます。


特殊文字(Unicode の East Asian Ambiguous) の設定

素の emacs では agda-mode で利用する特殊文字(∏ など)があると表示が乱れます。
これはいくつかの記号の幅が固定されておらず、国によって幅が定義される文字である East Asian Ambigous 文字がソースに含まれる時に発生する問題です。
日本語フォントは基本的に幅2なのですが、英語では幅1らしい。
設定をしないとEmacsが幅を1で処理するため、表示される日本語フォントの幅と合わずに表示が乱れてしまいます。
これを解決する elisp が hamano/locale-eaw に公開されているようなので使ってみます。
README にあるように eaw.el を ~/.emacs/site-lisp に配置して
(add-to-list 'load-path "~/.emacs.d/site-lisp")
(require 'eaw)
(eaw-fullwidth)
を ~/.emacs なり ~/.emacs.d/init.el に書きます。
そうするとEmacs が特殊文字の幅を2として処理してくれます。
ちなみに Terminal や tmux なども East Asian Ambiguous を幅2に設定するのを忘れないように。
過去に自分で書いた elisp もあるのですが割とその場しのぎで書いていたので、これからは eaw.el を使っていこうかなとか。


参考文献