-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add docs/limestone_race.md #44
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,122 @@ | ||||||
# limestoneにおけるraceについて | ||||||
|
||||||
2023-10-23 horikawa | ||||||
|
||||||
## この文書について | ||||||
下記を説明する。 | ||||||
* shirakamiがcallすることを想定しているlimestoneのdatastore::switch_epoch()とdata_channel::begin_session()のタイミング制約 | ||||||
* durable epochを決める前提となるdata_channel::begin_session()の挙動、特に、begin_session()が属するepochを決める方法 | ||||||
|
||||||
## log書き込みの基本動作 | ||||||
1) あるepochに属するlogのshirakamiによる書き込みは、data_channel::begin_session()で開始し、data_channel::add_entry()によりlogをlimestoneに送り、data_channel::end_session()で終了する。 | ||||||
2) 通常、limestoneはdata_channel::end_session()を契機として、data_channel::add_entry()によって送られたlogを不揮発性記録媒体に書き込む操作を開始する。 | ||||||
3) logが属するepochは、data_channel::begin_session()をcallしたときのlimestone epochとなる。 | ||||||
4) limestone epochは、shirakamiがdatastore::switch_epoch()をcallすることで切り替わる。 | ||||||
5) どのlimestone epochまでdurableになった(logが不揮発記録として書き込まれた)のかは、datastore::last_epoch()で調べることができる。 | ||||||
6) durableとなったlimestone epochは、datastore::add_persistent_callback()でcallbackを登録しておくことで、durable epochがが更新される度にcall backとして通知を受け取ることもできる。 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
なお、現在の仕様では、data_channel::begin_session()により開始したlog書き込みが属するlimestone epochを陽に知ることはできない。 | ||||||
|
||||||
|
||||||
## shirakami | ||||||
### limestoneに対する操作 | ||||||
* shirakamiは、datastore::switch_epoch()により、limestone epochの切り替わりをlimestoneに伝える。 | ||||||
* shirakamiは、data_channel::begin_session()により、現在のlimestone epochに属するlog書き込み開始をlimestoneに通知する。 | ||||||
|
||||||
上記の操作がshirakamiの別スレッドで実行されると、両者の間でlimestone epochに関するraceが発生する可能性がある。つまり、 | ||||||
shirakamiがlimestone epochをn-1からnに切り換えるためにdatastore::switch_epoch()をcallする場合、それがreturnするまでの間はlimestone epochがn-1かnかは不定となるため、 | ||||||
その実行期間(callからreturnまでの間)とdata_channel::begin_session()の実行期間に重なりがあると、data_channel::begin_session()が属するlimestone epochがn-1なのかnになるのかが不定となる。 | ||||||
(図1 case 1~4)。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig01.png" width="400"> | ||||||
|
||||||
図1 datastore::switch_epoch()とdata_channel::begin_session()の実行期間が重なっている場合 | ||||||
</p> | ||||||
|
||||||
なお、両者が重なっていない場合(図2)は、data_channel::begin_session()が属するlimestone epochが不確定となることはない。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig02.png" width="400"> | ||||||
|
||||||
図2 datastore::switch_epoch()とdata_channel::begin_session()の実行期間に重なりがない場合 | ||||||
</p> | ||||||
|
||||||
|
||||||
## limestone | ||||||
### durable epochの定義 | ||||||
limestoneが認識するdurable epochは、 | ||||||
1) limestone epochより小さく、かつ、 | ||||||
2) 不揮発性記憶への書き込みが完了していないlogを持っているdata_channelのepoch | ||||||
よりも小さいepochの最大値である。 | ||||||
|
||||||
### limestoneによるdurable epochの追跡 | ||||||
limestoneがdurable epochを認識できるようにするため、各log_channelは、各々が書き込んでるlogのepochを管理している。 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
その基本動作を図3に示す。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig03.png" width="400"> | ||||||
|
||||||
図3 log_channelによるlogのepoch管理<br> | ||||||
各log_channelは、begin_session()時にlimestone epochを調べ、そのepochを以降のadd_entry()で送られるlogのepoch(channel's epoch)として記憶しておく。 | ||||||
ここで、channel's epochがUINT_MAXとなっている期間は、log_channel::begin_session()が行われていない(未書き込み尾logは存在しない)ことを示している。 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
UINT_MAX だと unsigned int の MAX となってしまい多くの場合 32bit になってしまうため。(図3~7 も同様) |
||||||
なお、channel's epochはlimestone内の他モジュールから読み出せるようになっている。 | ||||||
|
||||||
</p> | ||||||
|
||||||
### channel's epochに関する制約 | ||||||
limestoneによるdurable epochの認識でraceが発生しないようにするため、各々のlog_channelがlogのepochを確定する操作には、以下の制約を設ける。 | ||||||
* limestoneのモジュールがlimestone epochとしてnを読み込んだ後(datastore::switch_epoch()によりnが設定された後)に全log channelのlog epochを読み出す操作を行った場合、 | ||||||
n-1以下のlogを書き込んでいるlog_channelが存在するのであれば、そのchannel's epochは必ずreadできる。 | ||||||
|
||||||
端的な例を示すと、datastore::switch_epoch()がnをlimestone epochとして書き込んだ後に全log channelのlog epochを読み出すと、 | ||||||
n-1以下のlogを書き込んでいるlog_channelが存在するのであればそのchannel's epochは必ずreadできる(図4の状況)、 | ||||||
逆に、n-1以下のlogを書き込んでいるlog_channelが存在しないことが判明した場合は、 | ||||||
その操作それ以降にepochがn-1以下のlog書き込みを開始(begin_session())するlog_channelは存在しないことが保証されている、ということである。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig04.png" width="400"> | ||||||
|
||||||
図4 datastore::switch_epoch()とlog_channel::begin_session()の関係<br> | ||||||
switch_epoch()がlimestone epochをn-1からnに更新した後にlog_channelのchannel's epochをreadした場合、n-1のchannel's epochがreadできる状況。 | ||||||
|
||||||
</p> | ||||||
|
||||||
但し、naiveに構築された(race対策が施されていない)log_channel::begin_session()では、図5に示すraceが発生し、上記の制約を満たさなくなる。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig05.png" width="400"> | ||||||
|
||||||
図5 datastore::switch_epoch()とlog_channel::begin_session()間のrace<br> | ||||||
switch_epoch()がlimestone epochをn-1からnに更新する際、log_channel::begin_session()は更新前のlimestone epochをreadし、switch_epoch()によるchannel's epochのread操作後にchannel's epochをn-1に設定すると、channel's epochに関する制約を満たさなくなる。 | ||||||
|
||||||
</p> | ||||||
|
||||||
このため、log_channel::begin_session()では、図6に示すように、channel's epochへの書き込みを行った後、再度limestone epochを読み込み、それがchannel's epochに書き込んだepochと同じかどうかを確認する。 | ||||||
両者が一致している場合は、channel's epochに関する制約が満たされるので、begin_session()の操作を完了させる一方、 | ||||||
両者が異なっている場合は、channel's epochへの書き込み操作を再実行し、channel's epochに書き込んだepochと同じ値がlimestone epochから読み込まれるまで繰り返すことで、 | ||||||
channel's epochに関する制約を満たすことを保証する。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig06.png" width="400"> | ||||||
|
||||||
図6 datastore::switch_epoch()とlog_channel::begin_session()間のrace防止<br> | ||||||
log_channel::begin_session()が更新前のlimestone epoch(n-1)をreadしてchannel's epochに設定後、再度limestone epochをreadし、それがn-1でない(図ではnの)場合はchannel's epochの設定操作をやり直す。 | ||||||
|
||||||
</p> | ||||||
|
||||||
|
||||||
このようなlimestone epochの再読み込みを行うと、「channel's epochに関する制約」が満たされることを図7に示す。 | ||||||
|
||||||
<p> | ||||||
<img src="limestone_race/Fig06.png" width="400"> | ||||||
|
||||||
図7 datastore::switch_epoch()とlog_channel::begin_session()間のrace防止<br> | ||||||
log_channel::begin_session()が更新前のlimestone epoch(n-1)をreadしてchannel's epochに設定後、再度limestone epochをreadした値がn-1の場合、 | ||||||
そのchannel's epochは、switch_epoch()がn-1をnに更新した時点でn-1であることが保証される。 | ||||||
|
||||||
</p> | ||||||
|
||||||
|
||||||
なお、このようなリトライを行うと、channel's epochとして最初に書き込んだn-1がswitch_epoch()等からreadされる可能性もある。 | ||||||
この場合、n-1がdurable epochになっているにも関わらず、それはdurable epochではないと誤認識される可能性につながることになる。 | ||||||
但し、この誤認識は安全方向(危険方向の誤認識は「durableでないにも関わらずdurableと認識」される方向)であることと、発生頻度は非常に低い、の2点から実用面での問題はないと考えられる。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おそらく文中と図3~7の data_channel はすべて log_channel の誤記かと思います。