ロックテーブルの参照方法とその見方
これは InterSystems FAQ サイトの記事です。
ロックテーブルを参照する方法として、主に以下の3つの方法が挙げられます。
1. 管理ポータルで参照する方法
⇒ 管理ポータル:システムオペレーション > ロック > ロックを表示(または管理)
2. ^LOCKTAB ユーティリティ を使用する方法
⇒ %SYS> do ^LOCKTAB
3. プログラムで参照する方法
⇒ プログラム内でロック情報を取得する方法
こちらの記事では、ロックテーブルで参照できる情報について、以下の3つのケースに分けて、かかるロックとその意味をご説明します。
1.トランザクションで更新クエリ実行時、他のプロセスで更新・参照した状態 2.デッドロックとなった状態 3.テーブルロックがかかった状態
目視で一番わかり易いのは、1の 管理ポータルで参照する方法 になるので、こちらで説明したいと思います。
最初に、
1.トランザクションで更新クエリ実行時、他のプロセスで更新・参照をすると、どのようなロックがかかるのか見ていきます。
a. プロセスA(PID=10044)にてトランザクションで、Sample.Personテーブルの ID=1 を更新します。 ⇒ Exclusive_e->Delock ロック
[SQL]TL1:USER>>update Sample.Person(Name) values('bbb') whereID=1b. プロセスB(PID=46952)にて、Sample.Personテーブルの ID=1 を更新します。 ⇒ WaitExclusiveExact ロック
→ ロックタイムアウト後(既定10秒)、[SQLCODE: <-110>:<ファイル中にロック競合が発生しました>] エラーが返ります。
[SQL]USER>>update Sample.Person(Name) values('ccc') whereID=1c. プロセスC(PID=45680)にて、read commit モード で、Sample.Personテーブルの ID=1 を参照します。 ⇒ WaitSharedExact ロック
→ ロックタイムアウト後(既定10秒)、[SQLCODE: <-114>:<ひとつまたはそれ以上のマッチする行が別のユーザによりロックされています>] エラーが返ります。
[SQL]USER>>settransactionisolationlevelread committed
[SQL]USER>>select * from Sample.Person whereID=1
管理ポータルでロックテーブル情報を見てみます。青四角がそれそれでの持しているロックになります。
※複数の増分ロックがかかっているときは、「Exclusive/5」のように、ロック数も表示されます。1つのロックの時は表示されません。
.png)
次に、
2.デッドロックが発生しているとき、どのようなロックの状態になるのか見てみます。
1. プロセス A(PID:43468) で次のコマンドを発行します : lock +^MyGlobal(15) 2. プロセス B(PID:2198) で次のコマンドを発行します : lock +^MyOtherGlobal(15) 3. プロセス A で次のコマンドを発行します : lock +^MyOtherGlobal(15) ⇒ この LOCK コマンドは返りません。このプロセスは、プロセス B がロックを解放するまでブロックされます。 4. プロセス B で次のコマンドを発行します : lock +^MyGlobal(15) ⇒ この LOCK コマンドも返りません。このプロセスは、プロセス A がロックを解放するまでブロックされます。 プロセスA、プロセスB、ともにロックの解放待ちで、応答が返らない状態(デッドロック)になりました。
管理ポータルでロックテーブル情報を見てみます。
.png)
プロセスA(PID:43468)
・^MyGlobal(15) に対する Exclusive(排他ロック)を保持
・^MyOtherGlobal(15) に対し、WaitExclusiveExactで同一ロックに対する排他ロックの待機(ロック解放待ち)
プロセスB(PID:2198)
・^MyOtherGlobal(15) に対する Exclusive(排他ロック)を保持
・^MyGlobal(15) に対し、WaitExclusiveExactで同一ロックに対する排他ロックの待機(ロック解放待ち)
お互いに、それぞれが保持しているロックの解放待ちで、デッドロック状態となっていることが分かります。
デッドロックを防止するには以下のような方法があります。
- 常に timeout 引数を使用する。
- 増分 LOCK コマンドを発行する際にその順序に関して厳格なプロトコルに従う。すべてのプロセスが、ロック名に関して同じ順序に従っている限り、デッドロックが発生することはありません。単純なプロトコルは、照合順序でロックを追加するものです。
- 増分ロックではなく単純ロックを使用する (つまり、+ 演算子を使用しない)。前述のとおり、単純ロックでは、LOCK コマンドは最初に、プロセスによって以前から保持されていたすべてのロックを解放します (ただし、実際には単純ロックはあまり使用されません)。
最後に、
3.テーブルロックがかかった状態では、どのようなロックがかかるのか見ていきます。
今回は、Create Table で作成した、SQLUser.tab1 テーブルで実験してみます。
現在、ロック閾値 が 1000(デフォルト) なので、トランザクションでそれ以上の更新をしてみます。
1回目の Insert で、「Exclusive_e->Delock」のロックが1つかかっているのが分かります。
.png)
2回目の Insert で、「Exclusive_e->Delock」のロックが2つになったのが分かります。
.png)
1001回目の Insert では、テーブルロック閾値(1000)を超えたために、「Exclusive/1001E->Delock」というテーブルロックにまとめられたことが分かります。
.png)
今回は、管理ポータルで参照する方法をご紹介しましたが、^LOCKTABユーティリティ や、プログラムで取得する方法 でも、同様の情報を見ることが可能です。
なお、正常に終了したプロセスは取得していたロックを全て解放します。
【ご参考】