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をスケジュールして、タイムアウトを迎えたらプローブを送信するというもの。
プローブとしては、まだ送っていないセグメントがある場合は新しいセグメントを送り、ない場合は最後に送信したセグメントを再送する。
プローブを送ることで、
- 最後のセグメントだけがロスしている場合、最後のセグメントを再送することによってリカバリできる。
- 複数のセグメントがロスしている場合、プローブによって他のリカバリの仕組みがトリガーされてリカバリできる。
他のリカバリの仕組みというのは、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 に設定の変更の仕方は載っている
設定を書くのは bootstrap/app.php
で、Processor の設定はこのままこれで良さそう。
Monolog がわからないのでフォーマットの変更がよくわからなかったが、↓を参考にした。
これだと 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]
という関数(?)になっちゃってる。
Observer
は https://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
のラッパー
対象が配列なら何とかして(protoAugment
かcopyAugment
)配列用の便利関数的なものを生やしまくる。
そして walk
で実際に convert
していく様子
convert
は defineReactive
を呼び出す。
defineReactive
によって、オブジェクトに getter/setter が定義されてる。
getter のほうは、値を返す前に dep
の depend
をたくさん呼んでるが、これはなんだろう。
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
は、target
の addDep
を呼び出すもの。
うーん
watcher も見る。
https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js
変更があったら何かを実行するのがこいつの役目。
addDep
は自分自身の依存( newDeps
, deps
)に渡された dep
を追加するのと、 dep
の sub
に自分自身を追加している
ちょっとこんがらがってきた
各 Observer
のインスタンスは dep
を持っていて、値を get
するときに Watcher
の dep
にインスタンスの dep
を追加する
set
の時には dep.notify
を呼ぶことで、 dep
の subs
を更新して回る。
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._update
は dir.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 を使いたいなと思ってる(使ってる)
小さいしドキュメントも充実しているので、ちょっとガイド読めば使えるのであんまり把握せずに使ってるけど、それはよくないよねということでコード読むところから始めようと思う
読むのはこれ。
現時点の Latest release な 1.0.1 を読む
v-cloak
最初は 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
ここでの this
は exports
してる 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')
もしている。
ということは↑の vm
は p
オブジェクトで、 $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
があればひたすら呼び出していて、 handlers
は this.$options
に hook ごとに登録されてる。
でもここまで handlers
というのは特に出てこなかったような気がする。
$emit
のほうが大事かな。
フックで実行する関数の登録処理は $once
あたりでやってるはず。
$once
を見ると、実際登録してるのは $on
っぽい。
https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L10L34
$on
は this._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 login -qfp <user>
と入れる
これで速くなったのでとりあえずしばらくこれでしのぐ
ハロー "Hello, World" がおもしろい
まだ3章までしか読んでないけど、『ハロー "Hello, World"』がおもしろい
最近はLinux Kernelのコード読んだりしてみたいな〜と思って読んだりしてたんだけど、やっぱ膨大なのでとっつきにくい。
そこでこんな本を見かけたものだから、"OSと標準ライブラリのシゴトとしくみ" ってのに惹かれて買ってみた。
はじめに、の部分を軽く読んで「手を動かして、調べかたを知る」とか、資料に頼るんじゃなくて手を動かして調べることを重視した本なんだということが書いてあっていいねーと思う
やっぱり自分で動かしながら動きを追ってみないと頭に入ってこないなーと思ってたので色々な角度から解析してる本とかとても魅力的。
というわけで読んでみると、僕のような素人にも優しい感じ。
親切親切
二章から GDB を使ってがんばって題名の Hello, World を解析していく。
GDB はあんまり使ったことがなかったけどまぁ本の通りにやっていけばなんとなく動かせる
disable とか知らなかったけど便利だ
ひたすら追いかけるのはどこでどうやって hello world って文字列が出力されるのかということ
それを知るためにステップ実行してアセンブリ読んでコード読んで、後は確かめるために文字列を出力している部分のバイナリをnopに書き換えてみて出力されなくなることを確認したり。
おもしろい!!
IO はカーネルがやるからシステムコールでカーネルに処理を頼むんだよなーとかそのくらいはわかってたつもりだし、CPUは動くときにレジスタ使ってどうこう、スタック使ってどうこうとかもなんとなーく知ってたけど、hello worldでそれが具体的にどう動いてるかと言われるとまぁよーわからんなーという程度の知識しかなかったんで、それを丹念に追っていくのは大変興味深い
システムコールに引数をどう渡すか、どう値を返すのか、エラーをどうセットするのか。
負の値を返せないのどうしてるのかとか、標準ライブラリの役割とか。
知らんことばかりでした
動かしながら学ぶとなんとなく納得感があっていい。
先が楽しみ