E : エスカレート・ロック
ロック・テーブルをオーバーフローさせることなく、同時ロックの最大数を適用できます。既定では、ロックは非エスカレートです。ロックの適用時に、locktype “E” を使用して、そのロックをエスカレートとして指定できます。エスカレート・ロックのリリース時には、アンロック文で locktype “E” を指定する必要があります。排他ロックと共有 (“S”) ロックの両方をエスカレートと指定できます。
一般に、同じ添え字レベルで多数の同時ロックを適用する場合に、エスカレート・ロックを使用することになります。例えば、LOCK +^mylock(1,1)#"E",+^mylock(1,2)#"E",+^mylock(1,3)#"E"... のようになります。
同じロックを、非エスカレート・ロックおよびエスカレート・ロックとして同時に適用することができます。例えば、^mylock(1,1) や ^mylock(1,1)#"E" のようにすることができます。InterSystems IRIS は、ロック・テーブルで locktype "E" を指定して発行されたロックを個別にカウントします。ロック・テーブルでエスカレート・ロックおよび非エスカレートロックがどのように表示されるかについての詳細は、"ObjectScript の使用法" の “ロック管理” の章を参照してください。
添え字レベルの “E” ロックの数がしきい値に達すると、その添え字レベルで要求される次の “E” ロックは親ノード (次に高位の添え字レベル) を自動的にロックしようとします。不可能な場合は、エスカレーションは発生しません。親ノードのロックに成功すると、1 つの親ノードのロックが下位の添え字レベルのロックの数 + 1 に対応するロック・カウントで設定されます。下位の添え字レベルのロックは解除されます。その後の下位の添え字レベルへの “E” ロックの要求は、この親ノードのロックのロック・カウントをさらにインクリメントします。親ノードのロック・カウントを 0 にデクリメントし、下位の添え字レベルにエスカレーション解除するには、適用済みのすべての “E” ロックを解除する必要があります。ロックの既定のしきい値は 1000 ロックです。1001 番目のロックが要求されると、ロックのエスカレーションが発生します。
ロックがエスカレートすると、ロック・オペレーションは、ロックされた特定のリソースではなく、適用されたロックの数のみを保持することに注意してください。そのため、ロックした同じリソースのロック解除に失敗すると、“E” ロックのカウントが同期されなくなります。
以下の例では、プログラムがロックしきい値 + 1 の “E” ロックを適用すると、ロックのエスカレーションが発生します。この例では、ロックのエスカレーションにより、次に高い添え字レベルにおいてロックが適用されると同時に、下位の添え字レベルにおいてロックが解除されることを示しています。
Main
TSTART
SET thold=$SYSTEM.SQL.Util.GetOption("LockThreshold")
WRITE "lock escalation threshold is ",thold,!
SET almost=thold-5
FOR i=1:1:thold+5 { LOCK +dummy(1,i)#"E"
IF i>almost {
IF ^$LOCK("dummy(1,"_i_")","OWNER") '= "" {WRITE "lower level lock applied at ",i,"th lock ",! }
ELSEIF ^$LOCK("dummy(1)","OWNER") '= "" {WRITE "lock escalation",!
WRITE "higher level lock applied at ",i,"th lock ",!
QUIT }
ELSE {WRITE "No locks applied",! }
}
}
TCOMMIT
ロック・エスカレーションに対してカウントされるのは “E” ロックだけであることに注意してください。以下の例では、既定 (非 “E”) のロックと “E” ロックの両方を同じ変数に設定します。ロックのエスカレーションは、変数における “E” ロックの合計数がロックしきい値に達した場合にのみ発生します。
Main
TSTART
SET thold=$SYSTEM.SQL.Util.GetOption("LockThreshold")
WRITE "lock escalation threshold is ",thold,!
SET noE=17
WRITE "setting ",noE," non-escalating locks",!
FOR i=1:1:thold+noE { IF i < noE {LOCK +a(6,i)}
ELSE {LOCK +a(6,i)#"E"}
IF ^$LOCK("a(6)","OWNER") '= "" {
WRITE "lock escalation on lock a(6,",i,")",!
QUIT }
}
TCOMMIT
“E” ロックのロック解除は、上記の逆です。ロックがエスカレーションされている場合、子のレベルでのロック解除は、ゼロに達してロック解除されるまで親ノードのロックのロック・カウントをデクリメントします。これらのロック解除はカウントをデクリメントし、特定のロックとは一致しません。親ノードのロック・カウントが 0 に達すると、親ノードのロックが削除され、“E” ロックが下位の添え字レベルへとエスカレーション解除されます。それ以降の下位の添え字レベルのロックは、そのレベルで固有のロックを作成します。
“E” locktype は、他の任意の locktype と組み合わせることができます。例えば、“SE”、“ED”、“EI”、“SED”、“SEI” などです。“I” locktype と組み合わせると、現在のトランザクションの最後ではなく、呼び出された直後に “E” ロックを解除できます。この “EI” locktype は、ロックがエスカレートされる状況を最低限に抑えることができます。
通常、“E” ロックは、トランザクション内の SQL INSERT、UPDATE、および DELETE 処理において自動的に適用されます。ただし、“E” ロックをサポートする SQL データ定義構造について固有の制限事項が存在します。詳細は、固有の SQL コマンドを参照してください。
I : 即時アンロック
トランザクションの終了まで待つのではなく、ロックを即時に解除します。
-
非増分 (ロック・カウント 1) ロックのアンロック時に “I” を指定すると、ロックは即時に解除されます。既定では、アンロックは非増分ロックを即時に解除しません。代わりに、非増分ロックをアンロックすると、InterSystems IRIS はそのロックを、トランザクションの終了までロック解除状態に維持します。“I” を指定すると、この既定の動作はオーバーライドされます。
-
増分ロック (ロック・カウント > 1) のアンロック時に “I” を指定すると、増分ロックは即時に解除され、ロックカウントは 1 だけデクリメントされます。これは増分ロックの既定のアンロックと同じ動作です。
“I” locktype は、トランザクション中にアンロックを実行する場合に使用します。これには、ロックがトランザクションの内部または外部のどちらで適用されたかに関係なく、InterSystems IRIS のアンロック動作に対して同じ効果があります。“I” locktype は、アンロックがトランザクションの外部で行われる場合は、オペレーションを実行しません。トランザクションの外部では、アンロックは必ず指定されたロックを即時に解除します。
“I” は、アンロック・オペレーションにのみ指定できます。ロック・オペレーションには指定できません。“I” は、共有ロック (#"SI") または排他ロック (#"I") のアンロックに指定できます。Locktypes “I” および “D” は、相互排他的です。“IE” は、エスカレート・ロックの即時アンロックに使用できます。
この即時アンロックを以下の例で示します。
TSTART
LOCK +^a(1) // apply lock ^a(1)
LOCK -^a(1) // remove (unlock) ^a(1)
// An unlock without a locktype defers the unlock
// of a non-incremented lock to the end of the transaction.
WRITE "Default unlock within a transaction.",!,"Go look at the Lock Table",!
HANG 10 // This HANG allows you to view the current Lock Table
LOCK +^a(1) // reapply lock ^a(1)
LOCK -^a(1)#"I" // remove (unlock) lock ^a(1) immediately
// this removes ^a(1) from the lock table immediately
// without waiting for the end of the transaction
WRITE "Immediate unlock within a transaction.",!,"Go look at the Lock Table",!
HANG 10 // This HANG allows you to view the current Lock Table
// while still in the transaction
TCOMMIT
D : 遅延アンロック
アンロックされたロックをトランザクション中に解除するタイミングを制御します。アンロック状態は、そのロックの直前のアンロックの状態まで遅延されます。そのため、ロックをアンロックするときに locktype “D” を指定すると、そのトランザクション中のロックの履歴に応じて、即時アンロックになるか、またはトランザクションの終わりまでロック解除状態になるかのいずれかの結果になります。複数回ロック/アンロックされたロックの動作は、現在のトランザクション中に 1 回のみロックされたロックの動作とは異なります。
“D” アンロックは、ロックを解除するアンロック (ロック・カウント 1) のみに有効であり、ロックをデクリメントするアンロック (ロック・カウント > 1) には無効です。ロックをデクリメントするアンロックは、常に即時に解除されます。
“D” は、アンロック・オペレーションにのみ指定できます。“D” は、共有ロック (#"SD") または排他ロック (#"D") に指定できます。“D” は、エスカレート (“E”) ロックに指定できますが、当然ながらアンロックもエスカレート (“ED”) として指定する必要があります。ロック・タイプ “D” と “I” は、相互排他的です。
トランザクション内でのこの “D” アンロックの使用を以下の例に示します。HANG コマンドを実行すると、ロック・テーブルにあるロックの ModeCount を確認する時間を取ることができます。
ロックが現在のトランザクション中に 1 回のみ適用された場合、“D” はロックを即時に解除します。これは “I” の振る舞いと同じです。詳細は、以下の例を参照してください。
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
HANG 10
TCOMMIT
現在のトランザクション中にロックが複数回適用された場合、“D” アンロックは直前のアンロック状態に戻します。
-
最後のアンロックが標準アンロックであった場合、“D” アンロックは、その直前のアンロックの動作に戻します。つまり、トランザクションの終了までアンロックを遅延します。詳細は、以下の例を参照してください。
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive->Delock
WRITE "1st unlock",! HANG 5
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1) // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "3rd unlock",! HANG 5
TCOMMIT
-
最後のアンロックが “I” アンロックであった場合、“D” アンロックは、その直前のアンロックの動作に戻します。つまり、ロックを即時にアンロックします。詳細は、以下の例を参照してください。
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: null (immediate unlock)
WRITE "1st unlock",! HANG 5
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
-
最後のアンロックが “D” アンロックだった場合、“D” アンロックは直前の非 “D” ロックの動作に従います。
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "3rd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "3rd unlock",! HANG 5
TCOMMIT