Skip to content
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

bg_commit worker の commit 試行削減を目的とする変更 #140

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ban-nobuhiro
Copy link
Contributor

bg_commit worker の負荷を減らすために、今試してもあきらかに再度 commit 待ちになりそうなものはスキップするという改良を加えました
案件: https://github.com/project-tsurugi/tsurugi-issues/issues/460

性能評価も上記案件で進行中です。
新設プロパティ名とかは、適宜変えてください。

変更概要

  • bg_commit のコンテナタイプを set → map に変更 (5fd621c)
    • もともと set<ltx_id, token> だったが、 ltx_id はユニークかつ再利用されないためこの変更で問題はない。また、純粋にエントリの検索(挿入位置の検索や削除時の検索を含む)が速くなる
  • LTX コミットで待たされた場合には、どの ltx_id のトランザクションに待たされたかを記録するようにした (17b4847 session.h)
    • session object に記録用の領域を新設
      • いまのところ、 「ltx_id を記録する」のみとしているが、ほかの情報も記録する価値があるかもしれない
    • long_tx::commit の最初の待ち判定で boundary check で待たされていると判断された場合には、そこに記録
    • 待ちが解消された場合や session 初期化時にはそこをクリア
  • bg_commit worker スレッドは、ひとつ コンテナから処理候補を取り出した際に、その ltx が待っている ltx_id が bg_commit コンテナにいるかを確認して飛ばすようにした (17b4847 bg_commit.cpp)
    • 待たされている ltx の生存確認に使える安価なものとして bg_commit コンテナを使用した。
    • これだと まだ一度も commit を試していない LTX のスキップができないので、改良の余地はある
  • 追加で read area check での待ちの場合にも同様に記録するようにした (05fc529)

@thawk105
Copy link
Contributor

thawk105 commented Mar 14, 2024

bg_commit のコンテナタイプを set → map に変更

こちらは良い変更だと思います。

LTX コミットで待たされた場合には、どの ltx_id のトランザクションに待たされたかを記録するようにした
bg_commit worker スレッドは、ひとつ コンテナから処理候補を取り出した際に、その ltx が待っている ltx_id が bg_commit コンテナにいるかを確認して飛ばすようにした
追加で read area check での待ちの場合にも同様に記録するようにした

他の作業に関しては取り込みに注意が必要であると考えます。

wait には boundary wait と read wait があります。
作業プロセスとしては boundary wait の確認と waiting bypass, read wait の確認があります。

こちら、boundary wait の確認と waiting bypass に関しては注意が必要です。
私は実装前から waiting bypass のコストは数学的に高価であると見立てをたてて、下記のようなコメントと実装をしていました。
https://github.com/project-tsurugi/shirakami/blob/dev-ban-bg_commit-checkroot/src/concurrency_control/ongoing_tx.cpp#L195
すなわち、定期的(待ち確認の度)に全てのパスを一つのみ短絡化しています。

つまり、ltx id x に関して waiting bypass を試みた結果、boundary wait になったという判断をした時点で、次回以降 x が生きていたらチェックすらしないと思うのですが、それは waiting のパスを短絡化させきったこととは同義ではありません。従って、最適化ロジックとしては

「waiting bypass させきった上で依然としてboundary waiting していて、その相手のtx 群が一つでも生きているならば、boundary wait はチェックしなくても待ちが確定する。」

になると思います。

・waiting bypass させきったかどうか?
・ラストチェックの一txではなく、相手のtx群が一つでも生きているならば?の方が良いのではないか?
という議論があると思います。

部分的に改善しており、改悪していない部分はないか?(無難に取り込めるか?)の観点にも議論があります。

read wait の件に関しては改善している部分と改善していない部分があります。

改善しうる部分
・待つと決めた相手が依然として生きていたら待ち確認スキップ

改悪しているかもしれない部分
・待つと決めた相手の状態がコミットトライ前で、全て読みうるだったと仮定する。そのときは衝突判定で待つことにしたと仮定する。下記部分、待つと決めた相手がコミットトライして read are をテーブルレベルからキー範囲レベルまで詳細に確定させたと仮定する。その後であれば待つ相手がコミットを終わらせていなくても(生きていても)衝突判定の結果ぶつからないかもしれないケースを、相手がコミットを終わらせるまで待ってしまうように改悪しうる。
https://github.com/project-tsurugi/shirakami/blob/dev-ban-bg_commit-checkroot/src/concurrency_control/interface/long_tx/termination.cpp#L776

@ban-nobuhiro
Copy link
Contributor Author

ありがとうございます。
指摘を受けていろいろ再検討しました。

今回提案のやり方だと、
「boundary check / read check をして何かとぶつかって待たされたらその相手を覚えておく」なので
この機構によって待ちスキップをし始めると、待ちを解除される (= 覚えた相手がいなくなることと同義) まで check をしなくなるので、commit 時に細粒度化する情報(READ AREA) や commit 後に細粒度化する情報(waiting bypass) で衝突対象が減っていく場合にいろいろ損をする (余計に待ってしまう)
という問題があるということですね。

また、

待たされている ltx の生存確認に使える安価なものとして bg_commit コンテナを使用した。
これだと まだ一度も commit を試していない LTX のスキップができないので、改良の余地はある

この部分、むしろ commit 前であれば、衝突候補は増える一方のはずなので、 commit 前のものによって待たされると衝突検出したのならば、理論上は待たせる側が commit try するまでの間は、ずっとスキップできるのはずなのにしていない。
これも残念ではある。

改悪しているかもしれない部分

これを意識して例を構成すると

  1. LTX1: (LTX2 と干渉)
  2. LTX2: WP storageA、 READ AREA 宣言なし
  3. LTX2: storageA のみを読み書き
  4. LTX3: storageB のみを読み書き
  5. LTX3: commit → waiting (いまのところ LTX2 を待つ必要はないがまだわからない)
  6. LTX3: bg_commit → waiting
  7. LTX2: commit → waiting LTX1。READ AREA は storageA にみに縮小される
  8. LTX3: bg_commit → OK (LTX2 と干渉しなくなった)
  9. LTX2: bg_commit → waiting LTX1
  10. LTX1: abort
  11. LTX2: bg_commit → OK

これが以下のようになる

  1. LTX3: bg_commit は (LTX2 が bg_commit cont にいないので) commit をスキップしない commit → waiting
  2. LTX2: commit → waiting LTX1。READ AREA は storageA にみに縮小される
  3. LTX3: bg_commit は (LTX3 は LTX2 に待たされていた、かつ LTX2 が bg_commit cont にいるので) commit をスキップ (※不適切) ← 7の情報が反映される機会がない
  4. LTX2: bg_commit は commit をスキップしない commit → waiting LTX1
  5. LTX1: abort
  6. LTX2: bg_commit は commit をスキップしない commit → OK
  7. LTX3: bg_commit は commit をスキップしない commit → OK

待たされスキップ判定で、待たせている相手が bg_commit にいないものはスキップしないので、待たされ判定が広めに誤判定しても問題ないような気がしていましたが、
考えてみると 待たされ判定した次のターンまでに 待たせている相手がコミットすると、READ AREA が狭められた情報で更新されないまま bg_commit cont に入ってしまい、(commit しないと情報が更新されないので) そのままずっと LTX2 を待ってしまうのでダメですね (本来 8 で終了できていたのに)
さらに 6 は安全にスキップできるはずが (commit 前のものはスキップ判定対象外としているため) できていないし、このケースではいいことが一つもない。

・ラストチェックの一txではなく、相手のtx群が一つでも生きているならば?の方が良いのではないか?
という議論があると思います。

これは理論的にはそう思いますが、複数記録するとなると実装上複雑になることを懸念しています。
仮に、tx群を、ある程度の精度で代表できる tx 一つ があるのならば、1 つでもいいのではないかと思っています。
例えば ltx_id が一番小さいものとか逆に大きいものとか。

@thawk105
Copy link
Contributor

これは理論的にはそう思いますが、複数記録するとなると実装上複雑になることを懸念しています。
仮に、tx群を、ある程度の精度で代表できる tx 一つ があるのならば、1 つでもいいのではないかと思っています。
例えば ltx_id が一番小さいものとか逆に大きいものとか。

考え直したのですが、1txの判定で十分だと思いました。その理由は下記です。

・本件、待ち対象のtxを一つずつチェックしている。その結果、待つことになったtxを記録するアプローチである。
・相手のtx群として記録する場合、待つことが確定した後にそれ以外の群に含まれるtxを判定するコストがエクストラであり、そのコストに見合った見返りはチェックのスキップである。
・チェックする順序は現状tx_info (ongoing tx list) の順番であり、それはltxの開始順序である。tx_1 をチェックするコスト 1a, tx_2 をチェックするコスト 2a, ... と仮定したとき、待ち対象のtx群とするアプローチは事前に 1a, 2a, ... を支払うわけだが、tx_2, tx_1 の順で終わってしまったときに待ち対象のtx1個とするアプローチでは 1a のコストしか払っていない。

この部分、むしろ commit 前であれば、衝突候補は増える一方のはずなので、 commit 前のものによって待たされると衝突検出したのならば、理論上は待たせる側が commit try するまでの間は、ずっとスキップできるのはずなのにしていない。
これも残念ではある。

何か最適化のためのインデックスのようなものを新たに設けても良いかもしれませんね。例えば、ltx 開始、map に登録、ltx終了(map から削除)という処理プロセスを仮定したとき、「map にエントリがあれば生存中ltx」ということが分かります。tx_info (ongoing tx list) がそうではないか?という疑問があるかもしれませんが、現状それへのロック競合が問題視されています(よね?)。本件はそれの悪化を避ける、ジャイアントロックを細粒度化するだとか分散指向のアプローチになります。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants