OceanBaseデータベースは、メモリ内でロック間の待機関係を維持します。ロックが解放されると、そのロックを待機していたトランザクションが起動されます。
Lock Wait Mgr(ロック待機管理)の役割は、メモリ内で行とトランザクションの待機関係を維持し、ロックが解放された際に待機中のトランザクションを起動して再試行させることです。起動操作は、トランザクションの終了、SAVEPOINTによるロールバック、および早期ロック解除などの状況から発生する可能性があります。
ロック待機関係の種類
Lock Wait Mgrには、行ロック、テーブルロック、およびトランザクションの3種類のロック待機関係が存在します。
行ロック待機関係
行ロック待機関係は一般的なデータ待機関係です。行ロックが解放されると、システムは待機キューの先頭にあるトランザクションを起動して再試行します。
テーブルロック待機関係
テーブルロック待機関係は行ロックと似ていますが、競合はテーブルレベルのロックに基づきます。テーブルロックはそのテーブルに対するすべての操作に影響します。
トランザクション待機関係
メモリ使用量を削減するため、ダンプなどのシナリオで行ロック待機関係はトランザクション待機関係に変換されます。トランザクション終了時、システムはそのトランザクションを待っている他のすべてのトランザクションを同時に起動します。
ロック待機関係の確立
ローカルでの確立
行ロックを例にすると、異なるトランザクションが同一の行ロックを取得しようとした際に排他状態になると、競合情報を収集します。これには、ロック取得時間、ロック対象行のHash、ロック保持トランザクションIDなどが含まれます。また、この時点でのHashに対応するLock Wait Mgr Bucket上のseq値を記録します。この値はBucketと一対一で対応しており、そのBucketにマッピングされたHashが解放されるたびに1が加算されます。その後、ロック取得に失敗したトランザクションはステートメントをロールバックし、ロールバック後に対応するBucketでロックを待つ前に、記録されたseq値と現在のBucket上のseq値を比較し、ロックが解放されたかどうかを判断します。変化があれば、直ちにリクエストを再試行し、ロック待機キューには入りません。変化がなければ、キューに入ってロックを待ちます。

上図のように、トランザクション3がロック競合を発生させ、Bucketでロックを待とうとした際、記録されたseq=1であるのに対し、現在のBucketのseqが既に2に変わっていることを検出すると、ロック待機キューに入る前にロックリソースが解放されたと判断し、トランザクション3は直ちにステートメントを再試行し、ロック待機キューには入りません。もしBucket上のseqが変わらず依然として1であることを検出すると、トランザクション3はBucketでロックを待ちます。
以上で説明したロック待機関係はすべて、トランザクションがローカルで実行するステートメント、つまり、トランザクションステートメントリクエストを処理するObserverノード(制御側)と、ステートメントリクエストの実行でロック競合が発生したノード(実行側)が同じ場合の待機関係の確立プロセスです。
リモートでの確立
リモート実行の場合、待機関係の確立はより複雑になります。リモート実行時も競合情報を収集し、制御側に持ち帰ります。制御側では対応するLock Wait Mgr Bucketで待機します。待機する行が現在のノードにないため、実行側でもLock Wait Mgr Bucketで待機します。その役割は、ロックが解放された際にそれを感知し、制御側にリモートで再試行リクエストを通知することです。つまり、ロックが解放されると、実行側キュー内の待機ノードを通じて制御側をリモートで起動し、リクエストを再試行させます。 ネットワーク障害やダウンなどの異常によりリモート起動操作が失われるのを防ぐため、定期的なプローブメカニズムも備えられています。制御側で待機しているトランザクションは、定期的に待機中の実行側ノードの状態をプローブし、異常が検出された場合は、直接キューから取り出してリクエストを再試行します。
ロック待機関係のメンテナンス
実際には、Lock Wait Mgrは固定数のBucketを持つHashMapをメンテナンスしており、Hashマッピングの結果に基づいて、ロックを待つトランザクションをBucketに連結リスト形式で掛けます。起動時には、対応するHash Bucketから該当するトランザクションを取り出して再試行するだけで済みます。

上図のように、Bucket N-1にはトランザクション2がロックを待っています。トランザクション3が行ロックを解放する際、その行のHash値がBucket N-1にマッピングされている場合、Bucket N-1上でロックを待つトランザクションを走査し、待機Hashがその行のHashと同じトランザクションを見つけて取り出して再試行します。Bucketの数には限りがあるため、異なるHashが同じBucketにマッピングされる場合に生じる誤った起動を回避できます。また、トランザクション待機関係の起動時、もしトランザクションのHashがBucket 3に対応する場合、トランザクション1とトランザクション4はどちらも起動して再試行されます。