TCPのTail Loss Probeと再送周りについて少し

仕様は RFC にはないっぽくて(?) 2013年にgoogleの方々が出してるinternet draft で定義されている模様。

Tail Loss Probe は、一連の送信パケットの最後のパケットがロスした場合に、送信側が再送タイムアウトを待たずにロスを検知して回復することを目的としている。

パケットがロスした時、後続のパケットが次々と送られている場合はduplicate ackが返されるため、fast retransmitによってリカバリすることができる。

しかし、末尾のパケットや途中から末尾までウィンドウいっぱいのパケットがロスしてしまった場合などは、dup ackが届かないためfast retransmitはトリガーされないため再送タイムアウトまでリカバリできない。

再送タイムアウトを待つと時間がかかりすぎるし、タイムアウトが発生すると輻輳ウィンドウが小さくなってスロースタートからやり直しになってしまう。

そのためなんとか末尾のパケットのロスもタイムアウトより先に検知してリカバリしたいというのが動機。

それをどうやって実現しているかというと、簡単には次のような感じ。

再送タイムアウト(RTO)とは別に、probe timeout (PTO) を定義する。PTOの初期値は先述のdraftで max(2 * SRTT, 10ms) となっており、linuxのRTOの初期値の1秒と比べると短め。

で、データを送信するたびにPTOをスケジュールして、タイムアウトを迎えたらプローブを送信するというもの。

プローブとしては、まだ送っていないセグメントがある場合は新しいセグメントを送り、ない場合は最後に送信したセグメントを再送する。

プローブを送ることで、

  1. 最後のセグメントだけがロスしている場合、最後のセグメントを再送することによってリカバリできる。
  2. 複数のセグメントがロスしている場合、プローブによって他のリカバリの仕組みがトリガーされてリカバリできる。

他のリカバリの仕組みというのは、early retransmit[RFC5827]FACK fast recoveryなど。

early retransmitは、ネットワークに送出されているセグメントが4つ未満である場合、fast retransmitをトリガーするduplicate ackの回数を減らすというもの。

SACKオプションが有効な場合は、(送出中のセグメント-1)回のdup ackを受け取り、かつ最後のセグメントがSACKされている場合は再送する。

例えば最後の2つのセグメントがロスした場合、duplicate ackを受け取ることはないので、TLPがない場合はタイムアウトまで再送されることはない。

TLPがある場合は、PTO後に最後のセグメントを再送するので、それがちゃんと届けば送信側は最後のセグメントがSACKされたdup ackを受け取り、early retransmitにより(dup ackのthreasholdが低くなっているのでfast retransmitがトリガーし)ロスしたセグメントが再送される。

最後の3つのセグメントがロスした場合については1つのプローブを再送しただけではRFC5827のearly retransmitの範囲では再送するには足りないので、最後のセグメントがSACKされたら再送し始めるアルゴリズムを提案している。(proportional rate reduction algorithm。http://conferences.sigcomm.org/imc/2011/docs/p155.pdf

FACK fast recoveryも、同じくduplicate ackの数が少なくても再送しようというもの。

再送する時duplicate ackを3つ以上受け取ったら、となっているのはパケットの順序が入れ替わっただけの場合でもduplicate ackを受け取る可能性はあるからだが、FACK fast recoveryでは順序の入れ替わりであっても抜けが多かったら再送してしまおうというもの。(超ざっくり)

SACKされている最大のack番号と、送信済みでackされていない最小のシーケンス番号の差が3(fast retransmitをトリガーするdup ackの閾値)以上なら再送する。

最後のセグメントを含む4つ以上のセグメントがロスしている場合、再送されたプローブが届いたらこれで再送が始まり、リカバリできる。

ちなみに上記の通り色々な箇所でSACKが使われているので受信者側がSACKオプションを使えることは必須。

ということでTLPでロスをリカバリできるようになる、ということでした。

(主に参照したdraftが古いので、既に古いところはありそう)

Laravel でログのフォーマット変えたり Monolog の Processor 追加したり

もう Laravel から Rails に移行する決意をしたもののめんどくさくて実際は放置、そうしてる間にもログをみることはあって不便だったりして仕方なくいじる。

やりたいのは

  • ユーザがログインしてたらエラーログに user id を extra に追加する
  • extra を表示する位置を先頭付近に持ってくる

の2つ。

公式の ↓ の Custom Monolog Configuration に設定の変更の仕方は載っている

laravel.com

設定を書くのは bootstrap/app.php で、Processor の設定はこのままこれで良さそう。

Monolog がわからないのでフォーマットの変更がよくわからなかったが、↓を参考にした。

blog.muya.co.ke

これだと getMonolog とかしているが、同じ場所でそのまま設定できるので別にファイルを作って...とかはやってない。

bootstrap/app.php で、Monolog のクラスを使うようにするのと、

<?php
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;

return $app の直前に↓でやりたいことはできた。( extra に user_id 追加するのと、 extra を message の前に出す )

$app->configureMonologUsing(function ($monolog) use ($app) {
    $log_path = $app->storagePath().'/logs/laravel.log';
    $log_stream_handler = new StreamHandler($log_path);

    $log_format = "[%datetime%] %channel%.%level_name%: %extra% %message% %context%\n";
    $formatter = new LineFormatter($log_format);
    $log_stream_handler->setFormatter($formatter);
    $monolog->pushHandler($log_stream_handler);

    $monolog->pushProcessor(function ($record) {
        if (Auth::check()) {
            $user = Auth::user();
            $record['extra']['user_id'] = $user->id;
        }
        return $record;
    });
});

Vue.js の observe あたり雑に追う

(まとまりのなさがひどすぎてアレで放置してたらもう1.0.7になってますはい)

もう 1.0.4 になっとるやないけ

1.0.4 見ますはい。

データバインディングをどう実現しているのかが気になるのでその辺。

データバインディングといえば Observer ということで、 srsc/observer あたりを見てみようかと。

一年くらい前の記事だけど、 JavaScript フレームワークがデータバインディングを実現する4通りの手法 の中で、 Vue.js は「モデル書き換え方式」として紹介されている。

記事の中にもあるように、モデルを書き換えまくることで Vue.js はデータバインディングを実現してる。

おかげで特定のクラスのインスタンスを使わないといけないとかいうことはなく、意識せず使える。

ここから引用すると、 http://vuejs.org/guide/instance.html#Properties_and_Methods

var data = { a: 1 }
var vm = new Vue({
  data: data
})

vm.a === data.a // -> true

// setting the property also affects original data
vm.a = 2
data.a // -> 2

// ... and vice-versa
data.a = 3
vm.a // -> 3

console.log を仕込んでみると書き換えられている様子がわかる。

// インスタンスにセットする前
console.log(data) // -> { a: 1 }

// 後
console.log(data) // -> { a: [Getter/Setter] }

実際に取得できる値に変化はないけど、中身が書き換えられていることがわかる。 [Getter/Setter] という関数(?)になっちゃってる。


Observerhttps://github.com/vuejs/vue/blob/1.0.4/src/observer/index.js#L6L29 ここ。

コメントに、依存関係を収集したり(?)更新をディスパッチするために対象のオブジェクトのプロパティを geter/setter に変換するよ、って書いてある

  • Observer class that are attached to each observed
  • object. Once attached, the observer converts target
  • object's property keys into getter/setters that
  • collect dependencies and dispatches updates.

で、 Dep というオブジェクトが出てくるが、名前的にきっと依存関係を表すものかな。

_.define というので __ob__ というプロパティを対象のオブジェクトに生やして自分自身をそこに入れてる。

_.define は util で、 Object.defineProperty のラッパー

対象が配列なら何とかして(protoAugmentcopyAugment)配列用の便利関数的なものを生やしまくる。

そして walk で実際に convert していく様子

convertdefineReactive を呼び出す。

defineReactive によって、オブジェクトに getter/setter が定義されてる。

getter のほうは、値を返す前に depdepend をたくさん呼んでるが、これはなんだろう。

setter のほうは dep.notify してて、これは更新を伝えるためのものだろう。

Dep がわからんとわからんので src/observer/dep.jsを読む。

メンバ変数としてid, subsを持ってて、 target というクラス変数がある。

https://github.com/vuejs/vue/blob/1.0.4/src/observer/dep.js#L11L19

target には Watcher が入るみたいだがよくわからん。

さっきよく呼ばれてた depend は、targetaddDep を呼び出すもの。

うーん

watcher も見る。

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js

変更があったら何かを実行するのがこいつの役目。

addDep は自分自身の依存( newDeps, deps )に渡された dep を追加するのと、 depsub に自分自身を追加している

ちょっとこんがらがってきた

Observerインスタンスdep を持っていて、値を get するときに Watcherdepインスタンスdep を追加する

set の時には dep.notify を呼ぶことで、 depsubs を更新して回る。

get の際に addDep したタイミングで 自分のdep.subs にその時点での Dep.target (=watcher) が追加されてる。

nofity で呼ばれる update は、設定によって同期/非同期で値を更新する。

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js#L209

実際に更新するのはこっちの run メソッドBatcher から実行するためのインターフェースだと書いてある

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js#L237

ここで watcher 自身の value を更新してコールバックを呼び出している。

watcher を使っている場所を見てみると、 src/directive.js などにある。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L117L129

ここで第3引数が callback なので this._update が Watcher の値が更新されるときに呼ばれる callback ということになる。

this._updatedir.update を呼んでると。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L103L107

update を代入しているのはここ。 descriptor を調べる必要がある。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L79L83

descriptorコンストラクタで引数にとってるので Directive を初期化しているところを見に行く

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L34

_bindDir で使われている

https://github.com/vuejs/vue/blob/1.0.4/src/instance/lifecycle.js#L109L113

_bindDir を使っているところはいくつかあるが、わかりやすそうなところでいくとここ

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L395

で、 token.descriptor は何かなというと、雑に見ると恐らく下記

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L360L365

publicDirectives[type] になる。

publicDirectives は何かというと

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L2

var publicDirectives = require('../directives/public')

これなので、 directives/public を見てみる

https://github.com/vuejs/vue/tree/1.0.4/src/directives/public

各種ディレクティブのファイルが置いてある。

簡単そうだから text.js を見てみると、 update が定義されてる

https://github.com/vuejs/vue/blob/1.0.4/src/directives/public/text.js#L11L13

  update: function (value) {
    this.el[this.attr] = _.toString(value)
  }

まさに要素の中身を書き換えているようだ

まだ全体像は見えてないが、なんとなく値が更新された時に DOM にも反映される流れはつかめた。

__ob__ の役割とかよくわかってないな。また後で使いつつ読んでみる。

しかし大変だなー。 Object.observe が使えれば楽なのに

わたしとVue 今すぐダウンロード

小粒なうぇっぶあぷりを作ってて、 Vue.js を使いたいなと思ってる(使ってる)

小さいしドキュメントも充実しているので、ちょっとガイド読めば使えるのであんまり把握せずに使ってるけど、それはよくないよねということでコード読むところから始めようと思う

読むのはこれ。

https://github.com/vuejs/vue

現時点の Latest release な 1.0.1 を読む

v-cloak

最初は v-cloak.

理由は特になくなんとなく、簡単にわかりそうだから

http://vuejs.org/api/#v-cloak

要素に付けておくと Vue オブジェクトのコンパイルが終わると消える属性で、コンパイルが完了する前にテンプレートが表示されてしまうのを防ぐために CSS と組み合わせて使ったりするやつ。

ファイルを見てみるとそのものずばりな src/directives/public/cloak.js というのがあるのでそこに目を通す。

予想通りわかりやすそう。

compiled というフックに 'v-cloak' という属性を削除する関数を登録しているように見える。

こっから少し掘り下げてみる。

bind という名前で関数を export しているのはきっとそういう決まりかな。

src/directives/public 以下の他の js を見てみても、 bind という関数を export していそうに見える

bind が使われているところとかはもう少し後で見る。

cloak で src 以下を検索してみると該当するのはわずか。

cloak.js 自体と src/directives/public/index.js で cloak.js を require しているところ。

それとあと一箇所 src/directives.js で 'cloak' が使われてる。

https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L68L75

場所は Directive というオブジェクトの _bind 関数

属性が 'v-cloak' でないか vmコンパイル済みだったら属性を消すという感じの処理。

descriptor.attr ってのはなんなのかわからないが、'v-' なんとかの属性はどっかのタイミングで消すもののようだ。

その時に 'v-cloak' を先に消さないようにするための分岐っぽい。

そうすると vm ってのはちゃんと見たほうがよさそうだな〜

Directive から辿ってくと、 vmコンストラクタの第2引数なので、 new してるところを見る。

src/intance/lifecycle.js で new してる。

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L111

_bindDir の中で new していて、第2引数は this

ここでの thisexports してる module 自体って理解でいいのかな

ということはこの lifecycle のオブジェクトなのか・・?

確かに、 _compile という関数の中で this._isCompiled という変数を設定しているようだ。

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L68

さっき読んだところで this.vm._isCompiled というのがあったからなんとなくあってそう。

https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L70

今読んだ範囲だと vm を使っているところはあとひとつ、 $once というのがあった。

しかし $once を export しているのは src/api/events.js だなぁ。

vue/directive.js at 1.0.1 · vuejs/vue · GitHub

これは一体どういうことか。 lifecycle を require しているところを見れば多分わかりそう。

https://github.com/vuejs/vue/blob/1.0.1/src/vue.js#L85L86

src/vue.js で require している。

なるほど、 p というオブジェクトに extend していってるんだね。

確かに require('./api/events') もしている。

ということは↑の vmp オブジェクトで、 $once も持っているんで理解正しそう。

$once は予想通りな感じで、一回だけ関数が実行されるように登録された関数を実行したら登録を削除する処理を挟み込むようなもの。

さてじゃあ compiled という hook を呼んでるのはどこかな?と考えると、さっき compile っぽい関数あったよね。

はい、lifecycle.js

で、_isCompiled の直後にあるね、 callHook('compiled')

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L69

これだよこれ。

callHook は src/instance/events.js で定義されている

https://github.com/vuejs/vue/blob/1.0.1/src/instance/events.js#L155L163

handlers があればひたすら呼び出していて、 handlersthis.$options に hook ごとに登録されてる。

でもここまで handlers というのは特に出てこなかったような気がする。

$emit のほうが大事かな。

フックで実行する関数の登録処理は $once あたりでやってるはず。

$once を見ると、実際登録してるのは $on っぽい。

https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L10L34

$onthis._events に関数を push してる。

$emit をみてみると

https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L89L105

_event に登録されているコールバックを apply で呼び出してる。

ということで、ここで最初に読んだところで登録された 'v-cloak' 属性を削除するコールバックが呼ばれて、コンパイルが完了すると 'v-cloak' 属性が消えてくれるということだ。

多分。

とりあえずこんなところ。

なんとなく構造がわかってきたしその辺もまとめつつまた読む。

いつもこうなんとなく読み始めちゃうけど、最初に全体像を把握したりとか、あとコメントに色々書いてあるんでコメント読んだりとかちゃんとしたほうがいいな〜と反省する

macでターミナルの起動がめちゃくちゃ遅くなってた

最近家のmacのターミナルの起動が超遅くてストレスを感じてた

きっとzshrcにいろいろ書きまくっているからだろうとそろそろ治すか・・と思ってたら、どうもターミナルの起動時とかタブを新しく開いた時によく見てみると遅いのは login だった。

login が遅いで調べると asl を消すとか出てくる。

Speed Up a Slow Terminal by Clearing Log Files | OSXDaily

asl は Apple System Log ということらしい。

login 時に last login を表示するときにここを検索してるんでここが肥大化すると遅くなるとか。

システムログなんかいらない!(わけない)ということで早速 /var/log/asl 以下のログを消して再起動してみるけど改善せず。

他に方法はないものかと探してると俺しか使わないmacだし quiet に login すれば良さそう。

.hushlogin を置いておくとできるようだが touch ~/.hushlogin しても変化なし

原因わからないのでこの辺は時間あるときにもうちょっと調べたいがとりあえずは iTerm の Profiles から起動時のコマンドをデフォルトの Login Shell (login -fp ) から Command に変更して、Commandに login -qfp <user> と入れる

これで速くなったのでとりあえずしばらくこれでしのぐ

ハロー "Hello, World" がおもしろい

まだ3章までしか読んでないけど、『ハロー "Hello, World"』がおもしろい

最近はLinux Kernelのコード読んだりしてみたいな〜と思って読んだりしてたんだけど、やっぱ膨大なのでとっつきにくい。

そこでこんな本を見かけたものだから、"OSと標準ライブラリのシゴトとしくみ" ってのに惹かれて買ってみた。

はじめに、の部分を軽く読んで「手を動かして、調べかたを知る」とか、資料に頼るんじゃなくて手を動かして調べることを重視した本なんだということが書いてあっていいねーと思う

やっぱり自分で動かしながら動きを追ってみないと頭に入ってこないなーと思ってたので色々な角度から解析してる本とかとても魅力的。

というわけで読んでみると、僕のような素人にも優しい感じ。

一章でアセンブラな解説もあるしVMの使い方とかも載ってる。

親切親切

二章から GDB を使ってがんばって題名の Hello, World を解析していく。

GDB はあんまり使ったことがなかったけどまぁ本の通りにやっていけばなんとなく動かせる

disable とか知らなかったけど便利だ

ひたすら追いかけるのはどこでどうやって hello world って文字列が出力されるのかということ

それを知るためにステップ実行してアセンブリ読んでコード読んで、後は確かめるために文字列を出力している部分のバイナリをnopに書き換えてみて出力されなくなることを確認したり。

おもしろい!!

IO はカーネルがやるからシステムコールカーネルに処理を頼むんだよなーとかそのくらいはわかってたつもりだし、CPUは動くときにレジスタ使ってどうこう、スタック使ってどうこうとかもなんとなーく知ってたけど、hello worldでそれが具体的にどう動いてるかと言われるとまぁよーわからんなーという程度の知識しかなかったんで、それを丹念に追っていくのは大変興味深い

システムコールに引数をどう渡すか、どう値を返すのか、エラーをどうセットするのか。

負の値を返せないのどうしてるのかとか、標準ライブラリの役割とか。

知らんことばかりでした

動かしながら学ぶとなんとなく納得感があっていい。

先が楽しみ