OceanBaseデータベースは、メモリ内でロック間の待機関係を維持します。ロックが解放されると、そのロックを待機していたトランザクションが起動されます。
Lock Wait Mgr(ロック待機管理)の役割は、メモリ内で行とトランザクションの待機関係を維持し、ロックが解放された際に待機中のトランザクションを起動して再試行させることです。起動操作は、トランザクション終了、SAVEPOINTによるロールバック、およびロックの早期解放などの状況から発生する可能性があります。
ロック待機関係の種類
Lock Wait Mgrでは、行ロック、テーブルロック、およびトランザクションの3種類のロック待機関係が存在します。
行ロック待機関係
行ロック待機関係は一般的なデータ待機関係です。行ロックが解放されると、システムは待機キューの先頭にあるトランザクションを起動して再試行させます。
テーブルロック待機関係
テーブルロック待機関係は行ロックと似ていますが、競合はテーブルレベルのロックに基づきます。テーブルロックは、そのテーブルに対するすべての操作に影響します。
トランザクション待機関係
メモリ使用量を削減するため、ダンプなどのシナリオが発生した場合、行ロック待機関係はトランザクション待機関係に変換されます。トランザクションが終了すると、システムはそのトランザクションを待機している他のすべてのトランザクションを同時に起動します。
ロック待機関係の確立
ローカルでの確立
行ロックを例にすると、異なるトランザクションが同一の行ロックに対して排他的にロックを取得しようとした際、競合情報を収集します。これには、ロック取得時間、ロック対象行のHash、ロック保持トランザクションID、ロック取得トランザクション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はどちらもウェイクアップされて再試行されます。