PSQL Programmer's Guide (v11)

複数並行制御ツールの例 (トランザクショナル インターフェイス)

以下の例は、さまざまな並行制御機構の使用例を示したものです。

例 1

例 1 は、明示的レコード ロック、暗黙レコード ロック、明示的ページ ロック、受動的並行性の相互関係を示したものです。この例で操作される 2 つのレコード、レコード A とレコード B は、同じデータ ページに存在し、ファイルにはキーが 1 つだけあるものとします。各手順の詳細説明については、例の後を参照してください。

次の表は、暗黙レコード ロック、明示的レコード ロック、暗黙ページ ロック、受動的並行性の相互関係を示したものです。

表 38 レコード ロック、ページ ロック、並行性の相互関係
クライアント 1
クライアント 2
クライアント 3(非トランザクション)
1. 複数ノーウェイト ロック バイアスを指定して並行トランザクションを開始する(1419)
2. 単一ウェイト ロック バイアスを指定して並行トランザクションを開始する(1119)
3. 単一ノーウェイト ロック バイアスを指定した Get Equal を使用してレコード A を読み取る(205)
4. Get Equal(5)を使用してレコード B を読み取る(単一ウェイト ロック バイアスを継承)
5. Get Equal(5)を使用してレコード B を読み取る
6. レコード B の削除(4)を試みる:MicroKernel がステータス コード 84 を返すため、クライアント 3 は再試行しなければならない
7. レコード B を更新する(3)
8. レコード A の更新(3)を試みる:MicroKernel が再試行しなければならない
9. トランザクションを終了する(20)
10. レコード A の更新(3)を再試行する:正常終了
11. レコード B の削除(4)を再試行する:MicroKernel がステータス コード 80 を返すため、クライアント 3 はレコード B を再度読み取らなければならない
12. Get Equal(5)を使用してレコード B を再度読み取る
13. レコード B の削除(4)を再試行する:MicroKernel はステータス コード 84 を返す
14. トランザクションを終了する
15. レコード B の削除(4)を再試行する:正常終了

手順 1 で、クライアント 1 の Begin Concurrent Transaction オペレーションには一般的なバイアス値 400(複数レコード ノーウェイト ロック)を指定します。このバイアスは、このトランザクション内にあるバイアスのかかっていない各 Get または Step オペレーションに継承されます。この時点では、MicroKernel はファイル、ファイルのページまたはレコードにロックを適用していません。

手順 2 で、クライアント 2 の Begin Transaction オペレーションには一般的なバイアス値 100(単一レコード ウェイト ロック)を指定します。このバイアスは、このトランザクション内にあるバイアスのかかっていない各 Get または Step オペレーションに継承されます。MicroKernel はまだ、ファイル、ファイルのページまたはレコードにロックを適用していません。

手順 3 で、クライアント 1 の Get Equal オペレーションはバイアス値 200(単一レコード ノーウェイト ロック)を指定しています。MicroKernel は、継承された 400(複数ノーウェイト レコード ロック)ではなくこのバイアス値を受け入れます。これは、継承されたバイアス値よりも、個々のオペレーションに指定されたバイアス値が優先されるからです。

手順 4 で、クライアント 2 の Get Equal オペレーション(5)は独自のバイアス値を指定していません。したがって、このオペレーションはクライアント 2 の Begin Concurrent Transaction オペレーション(1119)から単一ウェイト ロック バイアス値 100 を継承します。たとえレコード A とレコード B が同じページ上にあっても、双方のロック要求(手順 3 と手順 4)は成功します。なぜなら、レコード ロック要求は指定されたレコードだけをロックするものであり、そのレコードが位置するデータ ページも、関連するどのインデックス ページもロックしないからです。

手順 5 で、クライアント 3 のロックを要求しない非トランザクションの Get Equal オペレーション(5)は成功します。これは、要求したレコードが存在する限り、非トランザクションの読み取りは常に成功するからです。

手順 6 で、クライアント 3 はレコード B の削除(4)を行おうとしますが、クライアント 2 がそのレコードに明示的ロックをかけているので、レコード B に対してレコードの削除に必要な暗黙レコード ロックを取得できません。その結果、MicroKernel はクライアント 3 にステータス コード 84(レコードまたはページがロックされている)を返します。そうなると、クライアント 3 は制御を放棄して、必要であれば後で Delete オペレーションを再試行する必要があります。

手順 7 で、クライアント 2 はまずレコード B に対する暗黙レコード ロックの取得に成功します。レコード B は、手順 4 で手順 2 から単一ウェイト ロック バイアスを継承するため、既にクライアント 2 で明示的にロックされていますが、明示的ロックと暗黙ロックの両方が同じクライアントに属しているので、問題はありません。それと同時に、クライアント 2 は、レコード B を含んでいるデータ ページとレコード B のキー値を含んでいるインデックス ページに対するページ ロックの取得にも成功します。


メモ

クライアント 2 によってロックされたデータ ページには、クライアント 1 で明示的にロックされたレコード A が含まれていますが、暗黙ロックで説明しているように、レコード ロックはページ ロックをブロックしません。


MicroKernel は手順 7 で Update オペレーション(3)そのものを実行するときに、変更されたデータ ページとインデックス ページのコミットされていない新しいイメージをシャドウ ページとしてファイルに書き込みます。この時点で、MicroKernel はレコード B に対するクライアント 2 の明示的ロックを解除しますが、クライアント 2 は今し方取得した暗黙ページ ロックに加えて、レコード B の暗黙レコード ロックも保持します。クライアント 2 が手順 7 で Update オペレーション(3)を終了した後でも、クライアント 3 がまだレコード B に対する暗黙レコード ロックを取得できないのは、クライアント 2 がレコードに対する暗黙レコード ロックを今も保持しているからです。クライアント 3 は、その再試行を続ける必要があります。

クライアントがリモートである場合、クライアント 2 は実際にファイルを更新する前に、クライアント 2 のローカル クライアント間の並行制御に必要なページ ロックを設定するほか、ファイルを保留中の変更の状態とします。

手順 8 で、クライアントはまずレコード A に対する暗黙レコード ロックをうまく取得します。たとえレコード A のデータ ページが既にクライアント 2 でロックされていても、ページ ロックはレコード ロックをブロックしないので、ロックの競合はありません(暗黙ロックを参照してください)。次に、クライアント 1 はレコード A を含んでいるデータ ページの暗黙ページ ロックを取得しようとします。この試行は、データ ページが手順 7 でクライアント 2 によって既にロックされているため失敗します。Begin Concurrent Transaction オペレーション(1419)は 500 バイアスを指定していないため、MicroKernel はオペレーションを再試行します(クライアントがローカルである場合、MicroKernel はデッドロック検出も行います)。

もしもクライアント 1 が 500 バイアスを追加して Begin Transaction オペレーション(1919)を発行していたら、MicroKernel は直ちにユーザーに制御を返したでしょう。

クライアントがリモートである場合、クライアント 1 は手順 7 でクライアント 2 によって設定された保留中の変更の状態に直面するため、MicroKernel はオペレーションを再試行します。

手順 9 で、そのトランザクションを終了することによって、クライアント 2 はレコード B に対する暗黙レコード ロックを解除し、手順 5 でロックしたデータ インデックス ページに対する暗黙ページ ロックを解除します。この時点で、MicroKernel はクライアント 2 がトランザクションで作成した新しいページ イメージをすべてコミットします。これで、これらのイメージがファイルの有効な部分になります。

クライアントがリモートである場合、クライアント 2 はファイルに対する保留中の変更の状態をクリアすると共に、ロックを解除します。

手順 10 で、クライアント 1 が続行している更新の再試行がようやく成功するのは、クライアント 2 がレコード A のデータ ページとインデックス ページをロックしなくなったからです。

手順 11 で、クライアント 2 が手順 9 でトランザクションを終了し、それによってすべてのロックを解除したにもかかわらず、クライアント 3 はまだレコード B を削除できません。現状では、クライアント 3 がレコードを削除しようとすると、MicroKernel の受動的並行制御はステータス コード 80(競合)を返します。これは、クライアント 3 が手順 5 で最初にレコード B を読み取った後で、クライアント 2 がこのレコードを変更したからです。この時点で、クライアント 3 はレコードを再度読み取らないと、Delete オペレーションを再試行できません。

手順 12 で、クライアント 3 はレコード B を再度読み取ることにより、クライアント 2 が手順 7 でレコードに加えた変更を反映し、手順 9 でコミットされたイメージを取得します。

手順 13 で、クライアント 3 はレコード B を削除しようとしても再びうまくいかず、MicroKernel からステータス コード 84 が返されます。このステータス コードは、クライアント 1 がレコード A を更新するために、レコード B を含むデータ ページとインデックス ページの暗黙ページ ロックを持っているという事実を反映しています。最初に述べたように、同じデータ ページにレコード A とレコード B が含まれており、同じインデックス ページにこれらのレコードのキー値が含まれているものと仮定します。

手順 14 で、クライアント 1 はトランザクションを終了することによって、変更をコミットし、暗黙ページ ロックを解除します。

手順 15 で、クライアント 3 はようやくレコード B を削除することができます。

例 2

例 2 は、ファイル ロックと受動的並行制御の相互関係を示したものです。各手順の詳細説明については、例の後を参照してください。

表 39 ファイル ロックと受動的並行性の相互関係
クライアント 1
クライアント 2
1. ファイル 1 を開く(0)
2. ファイル 2 を開く(0)
3. ファイル 3 を開く(0)
4. 単一レコード ロックを使用してファイル 3 のレコード E を取得する(105)
5. ファイル 1 を開く(0)
6. 排他トランザクションを開始する(19)
7. ファイル 1 のレコード B を取得する(5)
8. ファイル 1 のレコード A を取得する(5)
9. ファイル 1 のレコード A を更新する(3)(ステータス コード 85、再試行)
10. ファイル 2 のレコード C を取得する(5)
11. ファイル 2 のレコード C を更新する(3)
12. ファイル 1 のレコード B を削除する(4)
13. トランザクションを終了する(20)
14. 手順 9 を再試行する(成功)

手順 4 で、クライアント 1 はファイル 3 のレコード E に対する明示的レコード ロックを取得します。

手順 6 で、クライアント 1 は排他トランザクションを開始します。クライアント 1 が 3 つのファイルを開いていますが、MicroKernel はこれらのファイルをまだロックしていませんし、Begin Transaction オペレーションを実行した結果として、ファイル 3 のレコード E に対する明示的ロックを解除することもありません。

手順 7 で、クライアント 1 はファイルにアクセスした結果としてファイル 1 に対するファイル ロックを取得します(ファイル ロックを参照してください)。もし、直前の手順(たとえば手順 5 と 6 の間)でクライアント 2 がロック バイアスを持つオペレーションを使用してファイル 1 からレコードを読み取っていたら、手順 7 は失敗します。

手順 8 で、クライアント 2 はファイル 1 からレコード A を正常に読み取ります。この読み取りが成功するのは、ロックを要求しないからです。ただし、Get Equal オペレーション(5)がロック バイアスを指定して発行されていたら、クライアント 1 がファイル 1 を現在ロックしているため、オペレーションは失敗します。

手順 9 では、クライアント 1 がファイルをロックしているため、クライアント 2 は暗黙レコード ロックを取得できません。したがって、MicroKernel はクライアント 2 にステータス コード 85(ファイルがロックされている)を返します。クライアント 2 は直ちに制御を放棄し、クライアント 1 が手順 13 でトランザクションを終了または中止するまで、手順 9 を再試行しなければなりません(レコードが既にロックされている場合を参照してください)。

手順 10 で、クライアント 1 はファイル 2 に対するファイル ロックを取得します。

手順 13 で、クライアント 1 はファイル 1 と 2 に対するファイル ロックを解除します。


メモ

クライアント 1 は排他トランザクションでファイル 3 にアクセスしていないので、ファイル 3 をロックしませんでした。事実上、手順 13 以降でも、クライアント 1 はファイル 3 のレコード E に対する明示的レコード ロックを保持します。クライアント 1 は、ファイル 3 にアクセスしてトランザクションでファイル全体をロックしていた場合のみ、レコード E を解除したでしょう。


手順 14 で、ようやく手順 9 におけるクライアント 2 の Update オペレーションの再試行が成功します。


ユーザー トランザクション (トランザクショナル インターフェイス)

複数ポジション ブロックの並行制御 (トランザクショナル インターフェイス)