Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

ロック管理

LOCK コマンドを使用すれば、プロセスはロックの適用と解放を行うことができます。ロックは、グローバル変数などのデータ・リソースへのアクセスを制御します。アクセス制御は規約に従って機能します。ロックおよび対応する変数は同じ名前となることがありますが (通常は同一)、互いに独立しています。ロックの変更によって同一名の変数が影響を受けることはなく、変数の変更によっても同一名のロックが影響を受けることはありません。

ロック自体は、他のプロセスが関連するデータを修正しないようにすることはありません。Caché が一方的なロックを強制しないからです。規約では、互いに競合するプロセスが、すべて同じ変数にロック設定を実行していることが必要とされています。

ロックはローカル (現在のプロセスによってのみアクセス可能) またはグローバル (すべてのプロセスによってアクセス可能) にすることができます。ロックの名前付け規約はローカル変数およびグローバル変数の名前付け規約と同じです。

ロックは、それをロックしたプロセスによってアンロックされるまで有効です。システム管理者によってアンロックされるか、またはプロセスの終了時に自動的にアンロックされます。

この章では、以下の項目について説明します。

  • 管理ポータル・ロック・テーブル - システム全体で保持されたすべてのロックと、保持されたロックの解除を待機するすべてのロック要求を表示します。ロック・テーブルは、保持されたロックの解除にも使用できます。

  • ^LOCKTAB ユーティリティ - ロック・テーブルと同じ情報を返します。

  • 待機ロック要求 -Caché において保持されたロックの解除を待機するロック要求がキューに格納される方法を説明します。

  • デッドロックの回避 (ロック要求の相互ブロック)

ロック方法の開発についての詳細は、"ロックと並行処理の制御" の文書を参照してください。

システム全体での現在のロックの管理

Caché は、システム全体のロック・テーブルを保持しています。このテーブルには、その時点で有効なロックおよびそれをロックしているすべてのプロセスと、すべての待機ロック要求が記録されています。管理ポータル・インターフェースまたは ^LOCKTAB ユーティリティを使用すれば、システム・マネージャでロック・テーブルの既存ロックを表示したり、または選択されたロックを削除することができます。また、%SYS.LockQueryOpens in a new tab クラスを使用して、ロック・テーブルの情報を読み込むこともできます。%SYS ネームスペースから SYS.LockOpens in a new tab クラスを使用して、ロック・テーブルを管理することもできます。

ロック・テーブルを使用したロックの表示

管理ポータルを使用すれば、システム全体で現在保持または要求 (待機) されているすべてのロックを表示できます。管理ポータルから、[システム処理] を選択してから、[ロック] を選択して、さらに [ロック表示] (システム, ロック表示) を選択します。[ロック表示] ウィンドウには、ディレクトリごとのアルファベット順で ([ディレクトリ])、なおかつ各ディレクトリ内にはロック名による照合順で([リファレンス])、ロック (およびロック要求) の一覧が表示されます。各ロックはプロセス ID ([所有者]) にて認識され、[ModeCount] (ロック・モードおよびロック・インクリメント・カウント) を有します。ロックおよびロック要求の最新リストを表示させるためには、[再表示] アイコンを使用する必要があります。このインターフェースの詳細は、"Caché 監視ガイド" の “管理ポータルを使用した Caché の監視” の章にある "ロックの監視" を参照してください。

[ModeCount] は、特定の [リファレンス] についての特定の [所有者] プロセスによって、保持されたロックを指定することができます。以下は、保持されたロックに対する [ModeCount] 値の例です。

Exclusive 排他ロック、非エスカレート (LOCK +^a(1))
Shared 共有ロック、非エスカレート (LOCK +^a(1)#"S")
Exclusive_e 排他ロック、エスカレート (LOCK +^a(1)#"E")
Shared_e 共有ロック、エスカレート (LOCK +^a(1)#"SE")
Exclusive->Delock ロック解除状態にある排他ロック。ロックはアンロックされていますが、現在のトランザクションの終了までロックの解除が延期されます。これは、標準のアンロック (LOCK -^a(1)) または遅延アンロック LOCK -^a(1)#"D") により発生できます。
Exclusive,Shared 共有ロックと排他ロックの両方 (いずれの順序でも適用)。エスカレート・ロックも指定可能です。例 :Exclusive_e,Shared_e
Exclusive/n 増分排他ロック (LOCK +^a(1)n 回発行される)。ロック・カウントが 1 の場合、カウントは表示されません (ただし、以下参照のこと)。増分共有ロックも指定可能です。例 :Shared/2
Exclusive/n->Delock ロック解除状態にあるインクリメンタル排他ロック。ロックのインクリメントはすべてアンロックされていますが、現在のトランザクションの終了までロックの解除が延期されます。トランザクション内で、個々のインクリメントをアンロックすることで、これらのインクリメントはすぐに解除されます。ロックは、ロック・カウントが 1 のときにアンロックが発行されるまで、ロック解除状態になりません。この ModeCount 値 (ロック解除状態のインクリメンタル・ロック) は、それより前のすべてのロックが単独の操作 (引数なしの LOCK コマンドまたはロック・オペレーション・インジケータ (LOCK ^xyz(1)) のないロックのどちらか) によってアンロックされたときに発生します。
Exclusive/1+1e 2 つの排他ロック。一方は非エスカレートで、もう一方はエスカレートです。インクリメント・カウントはこれら 2 種類の排他ロックに対して別々に維持します。共有ロックも指定可能です。例 :Shared/1+1e
Exclusive/n,Shared/m 共有ロックと排他ロックの両方。ともに整数インクリメントとなります。

保持されたロック [ModeCount] は、インクリメントの有無にかかわらず、共有または排他、エスカレートまたは非エスカレートのロックのあらゆる組み合わせを表すことができます。排他ロックまたは共有ロック (エスカレートまたは非エスカレート) はロック解除状態にすることができます。

[ModeCount] によって、WaitExclusiveExact などのロック待機プロセスを指定することが可能です。以下は、待機ロック要求に対する [ModeCount] の値です。

WaitSharedExact 保持または事前に要求されたまったくの同一ロックに対する共有ロックの待機 :LOCK +^a(1,2)#"S" はロック ^a(1,2) に対する待機となります。
WaitExclusiveExact 保持または事前に要求されたまったくの同一ロックに対する排他ロックの待機 :LOCK +^a(1,2) はロック ^a(1,2) に対する待機となります。
WaitSharedParent 保持または事前に要求されたロックの親に対する共有ロックの待機 :LOCK +^a(1)#"S" はロック ^a(1,2) に対する待機となります。
WaitExclusiveParent 保持または事前に要求されたロックの親に対する排他ロックの待機 :LOCK +^a(1) はロック ^a(1,2) に対する待機となります。
WaitSharedChild 保持または事前に要求されたロックの子に対する共有ロックの待機 :LOCK +^a(1,2)#"S" はロック ^a(1) に対する待機となります。
WaitExclusiveChild 保持または事前に要求されたロックの子に対する排他ロックの待機 :LOCK +^a(1,2) はロック ^a(1) に対する待機となります。

[ModeCount] によって、ロック要求をブロックしているロック (またはロック要求) を指定します。これは必ずしも [リファレンス] と同じではなく、ロック・キュー先頭で現在保持されているロックを指定します。このロック・キューには当ロック要求が待機しています。[リファレンス] は必ずしも、このロック要求を即座にブロックする被要求ロックを指定するものではありません。

[ModeCount] は、特定の [リファレンス] についての特定の [所有者] プロセスに対するその他のロック・ステータス値を指定することができます。以下は、それらのその他の [ModeCount] ステータス値です。

LockPending 排他ロックの保留中です。サーバが排他ロックの付与プロセス中にある場合に、このステータスが発生することがあります。ロック・ペンディングの状態のロックは削除できません。
SharePending 共有ロックの保留中です。サーバが共有ロックの付与プロセス中にある場合に、このステータスが発生することがあります。ロック・ペンディングの状態のロックは削除できません。
DelockPending アンロックの保留中です。サーバが保持ロックのアンロック・プロセス中にある場合に、このステータスが発生することがあります。ロック・ペンディングの状態のロックは削除できません。
Lost ネットワークがリセットされたため、ロックが失われました。
LockZA DSM–11 専用ZALLOCATE コマンドを使用して DSM–11 で設定された排他ロックです。Caché では、ZALLOCATELOCK コマンドと同義となり、LOCK と同一の [ModeCount] 値を設定します。
WaitLockZA DSM–11 専用ZALLOCATE コマンドを使用して DSM–11 で要求された排他ロックが待機中です。Caché では、ZALLOCATELOCK コマンドと同義となり、LOCK と同一の [ModeCount] 値を設定します。

[ルーチン] 列は、所有者プロセスが実行しているルーチンおよび現在行数になります。

[ロック表示] ウィンドウを使用して、ロックを削除することはできません。

ロック・テーブルを使用したロックの削除

システム上で現在保持されているロックを削除するには、管理ポータルに移動して、[システム処理] を選択してから、[ロック] を選択して、さらに [ロックの管理] (システム, ロックの管理) を選択します。目的のプロセス ([所有者]) に対して、[削除] または [プロセスが保持するすべてのロックを削除] のいずれかをクリックします。

ロックの削除により、全形式の該当ロック (すべてのインクリメント・レベルのロック、すべての排他、排他エスカレート、および共有バージョンのロック) が解放となります。1 つのロックを削除すると、そのロック・キューで待機している次のロックが即座に適用となります。

また、SYS.Lock.DeleteOneLock()Opens in a new tab および SYS.Lock.DeleteAllLocks()Opens in a new tab メソッドを使用して、ロックを削除することもできます。

ロックを削除するには、WRITE 権限が必要になります。ロックの削除は監査データベースにおいてログが記録されますが (有効な場合)、これは cconsole.log へのログ記録ではありません。

^LOCKTAB ユーティリティ

また、%SYS ネームスペースから Caché ^LOCKTAB ユーティリティを使用して、ロックを表示および削除することもできます。^LOCKTAB は、以下の形式のいずれかで実行できます。

  • DO ^LOCKTAB : ロックを表示および削除できます。個々のロックの削除、指定のプロセスが所有しているすべてのロックの削除、またはシステム上のすべてのロックの削除を行う文字コード・コマンドが用意されています。

  • DO View^LOCKTAB : ロックを表示できます。ロックを削除するオプションは用意されていません。

これらのユーティリティ名は、大文字と小文字が区別されることに注意してください。

以下のターミナル・セッション例は、^LOCKTAB が現在のロックを表示する方法を示しています。

%SYS>DO ^LOCKTAB

                                   Node Name: MYCOMPUTER
                   LOCK table entries at 07:22AM  12/05/2016
                 1167408 bytes usable, 1174080 bytes available.
 
Entry Process     X#   S# Flg   W# Item Locked
   1) 4900         1               ^["^^c:\intersystems\cache151\mgr\"]%SYS("CSP","Daemon")
   2) 4856         1               ^["^^c:\intersystems\cache151\mgr\"]ISC.LMFMON("License Monitor")
   3) 5016         1               ^["^^c:\intersystems\cache151\mgr\"]ISC.Monitor.System
   4) 5024         1               ^["^^c:\intersystems\cache151\mgr\"]TASKMGR
   5) 6796         1               ^["^^c:\intersystems\cache151\mgr\user\"]a(1)
   6) 6796        1e               ^["^^c:\intersystems\cache151\mgr\user\"]a(1,1)
   7) 6796              2        1 ^["^^c:\intersystems\cache151\mgr\user\"]b(1)Waiters: 3120(XC)
   8) 3120         2               ^["^^c:\intersystems\cache151\mgr\user\"]c(1)
   9) 2024         1    1          ^["^^c:\intersystems\cache151\mgr\user\"]d(1)
 
Command=>

^LOCKTAB の表示では、保持された排他ロックを X# 列がリストして、保持された共有ロックを S# 列がリストします。X# または S# の数字は、ロック・インクリメント・カウントを示します。“e” 接尾語は、ロックがエスカレートとして定義されていることを示します。“D” 接尾語は、ロックがロック解除状態であることを示します。ロックはアンロックされていますが、現在のトランザクションの終了まで別のプロセスが使用することはできません。W# 列では待機ロック要求の数をリストします。上記の表示で示すように、process 6796 は増分共有ロック ^b(1) を保持しています。Process 3120 はこのロックを待つロック要求を 1 つ有しています。このロック要求は、^b(1) の子 (C) に対する排他 (X) ロックのためにあります。

このユーティリティのヘルプを表示するには、Command=> プロンプトで疑問符 (?) を入力します。これには、この表示の解読方法およびロックを削除する文字コード・コマンド (ある場合) についての詳細が含まれています。

Note:

Flg 列の値で示されるように、ロック保留状態にあるロックは削除できません。

^LOCKTAB ユーティリティを終了するには Q を入力します。

待機ロック要求

あるプロセスが排他ロックを保持する場合、別のプロセスが同じロック、または保持されたロックの上層や下層レベルのノード上のロックを取得しようとすると、待機状態が発生します。添え字付きグローバル (配列ノード) をロックする場合、以下のように、ユーザがロックするものと他のプロセスでロック可能なものとの区別が重要になります。

  • ユーザがロックするもの:ユーザは指定したノードに対してのみ明示的なロックを有します。その上層や下層のレベルのノードに対してはロックを有しません。例えば、^student(1,2) をロックする場合、ユーザは ^student(1,2) に対してのみ明示的なロックを有します。上層レベルのノード (^student(1) など) の解放によってこのノードを解放することはできません。なぜなら、上層レベルのノードに対して明示的なロックを有していないためです。もちろん、ユーザは任意の順序で上層または下層のノードを明示的にロックすることができます。

  • 他プロセスが何をロックできるか:ユーザがノードをロックすることにより、他のプロセスがその同一ノード、または上層や下層レベルのノード (該当ノードの親や子) をロックできません。親の ^student(1) をロックすることはできません。なぜなら、これをロックすると、子の ^student(1,2) (プロセスによって既に明示的にロックされている) も暗示的にロックされるためです。子の ^student(1,2,3) をロックすることはできません。なぜなら、プロセスが既に親の ^student(1,2) をロックしているためです。それらの他のプロセスは、指定の順序によりロック・キューにおいて待機となります。これらはロック・テーブルにリストされ、キュー内において他に優先することを指定された最上層レベルのノードで待機となります。これはロックされたノード、またはロックを待つノードとなる場合があります。

例えば以下のようになります。

  1. プロセス A は ^student(1,2) をロックします。

  2. プロセス B は ^student(1) のロックを試行しますが、禁じられます。これは、プロセス B が ^student(1) をロックすると、^student(1,2) も (暗示的に) ロックされるためです。ただし、プロセス A は ^student(1,2) に対するロックを保持しています。ロック・テーブルには、これが WaitExclusiveParent ^student(1,2) としてリストされます。

  3. プロセス C は ^student(1,2,3) のロックを試行しますが、禁じられます。ロック・テーブルには、これが WaitExclusiveParent ^student(1,2) としてリストされます。プロセス A は ^student(1,2) に対するロックを保持しており、そのため ^student(1,2,3) に対する暗示的なロックを保持しています。ただし、プロセス C はキュー内でプロセス B よりも下層となるため、プロセス B が ^student(1) をロックして解放するのをプロセス C は待つ必要があります。

  4. プロセス A は ^student(1,2,3) をロックします。待機ロックはそのままで変更ありません。

  5. プロセス A は ^student(1) をロックします。待機ロックは以下のように変化します。

    • プロセス B は WaitExclusiveExact ^student(1) としてリストされます。プロセス B は、プロセス A が保持するものと同一のロック (^student(1)) をロックすることを待ちます。

    • プロセス C は WaitExclusiveChild ^student(1) としてリストされます。プロセス C はプロセス B よりもキュー内で下層となるため、要求されたロックをプロセス B がロックして解放するのを待ちます。そのときには、プロセス C がプロセス B ロックの子をロックできるようになります。同様に、プロセス A が ^student(1) を解放するのをプロセス B は待ちます。

  6. プロセス A は ^student(1) をアンロックします。待機ロックは WaitExclusiveParent ^student(1,2) に戻ります。(手順 2 および 3 と同一)。

  7. プロセス A は ^student(1.2) をアンロックします。待機ロックは WaitExclusiveParent ^student(1,2,3) に変化します。プロセス B は ^student(1) (現在のプロセス A ロック ^student(1,2,3) の親) のロックを待ちます。プロセス C はプロセス B が ^student(1) (プロセス C により要求された ^student(1,2,3) ロックの親) をロックしてからアンロックするのを待ちます。

  8. プロセス A は ^student(1,2,3) をアンロックします。プロセス B は ^student(1) をロックします。プロセス C は現在、プロセス B によって禁じられています。プロセス C は WaitExclusiveChild ^student(1) としてリストされます。プロセス C は ^student(1,2,3) (現在のプロセス B ロックの子) のロックを待ちます。

配列ノードに対するロック要求のキュー

配列ロックに対する Caché キュー・アルゴリズムでは、リソースが直接的に競合しない場合でも、同一リソースのロック要求は受信した順で厳密にキューに置かれます。これは一般的な想定や、他のデータベースにおけるロック・キューの実装とは異なるため、以下に明確な説明を提供します。

同じグローバル配列に対する 3 つのロックが、以下のように 3 つの異なるプロセスによって要求されているとします。

Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)

この場合、Process A は ^x(1.1) のロックを取得します。^x(1) をロックする前に、Process A が ^x(1,1) を解放するのを Process B は待つ必要があります。しかし、Process C についてはどうでしょうか。Process A に付与されたロックが Process B をブロックしますが、Process C のロック要求をブロックするロックはありません。Process B は、^x(1) の明示的なロックと、Process C がロックしようとしているノード ^x(1,2) の暗示的なロックを待機しており、これにより Process C がブロックされます。Caché では、Process B がロックおよびロック解除するのを Process C は待機する必要があります。

Caché のロック・キュー・アルゴリズムは、Process B に対して公正です。Process C がキューをジャンプできる他のデータベース実装では、Process C は速く実行されますが、Process B には重大な遅延が生じる可能性があります (特に、Process C のようなジョブが数多くある場合)。

Note:

この厳密なプロセスのキューイング・アルゴリズムは、すべての添え字を持つロック要求に適用されます。ただし、添え字のない待機ロック要求 (LOCK +^abc) と添え字のある待機ロック要求 (LOCK +^abc(1,1)) の両方がある場合に添え字のないロック (LOCK -^abc など) を解除するプロセスは、特殊なケースです。この場合、処理されるロック要求は予測できず、厳密なプロセスのキューイングに従わない場合があります。

ECP ローカルおよびリモート・ロック要求

ロックを解除する際、ECP クライアントは、パフォーマンスを向上させるためにその他のシステム上の待機に優先してローカルの待機にロックを付与できます。リモート・ロック待機で許容できないほどの遅延が発生しないように、これが発生できる回数は制限されています。

デッドロックの回避

既存の共有ロックを保持している際の (+) 排他ロックの要求は、潜在的な危険を伴います。これは、"デッドロック"として知られる状況を引き起こす可能性があるからです。この状況は、既に他のプロセスによって共有ロックとしてロックされているロック名に対して、2 つのプロセスがそれぞれ排他ロックを要求するときに発生します。その結果、各プロセスは、他のプロセスが既存の共有ロックを解除するまで待機する間、停止します。

次の例では、これがどのように行われるかについて説明します (数字は処理の順番を示します)。

プロセス A プロセス B

1.LOCK ^a(1)#"S"

3.LOCK +^a(1)

プロセス B の共有ロックの解除を待機。デッドロック。

2.LOCK ^a(1)#"S"

4.LOCK +^a(1)

プロセス A の共有ロックの解除を待機。デッドロック。

これは最も単純な形式のデッドロックです。デッドロックは、保持されているロックの親ノードまたは子ノード上のロックをプロセスが要求する際にも発生する可能性があります。

デッドロックを防止するには、プラス記号なしで排他ロックを要求する (そうすることで共有ロックをアンロックする) 必要があります。以下の例では、両方のプロセスが排他ロックを要求する際に以前のロックを解除することで、デッドロックを防止しています (数字は操作の順序を示しています)。どのプロセスが排他ロックを取得するかに注意してください。

プロセス A プロセス B

1.LOCK ^a(1)#"S"

3.LOCK ^a(1)

共有ロックを解除し、プロセス B の共有ロックを待機。

2.LOCK ^a(1)#"S"

4.LOCK ^a(1)

共有ロックを解除し、直ちに排他ロックを適用。

他のデッドロック回避方法には、LOCK + および LOCK - コマンドを実行する順序に関する、厳密なプロトコルに従う方法もあります。すべてのプロセスが、この同じ順序に従っている限り、デッドロックが発生することはありません。単純なプロトコルは、すべてのプロセスにおいて照合順序でロックを適用および解除するものです。

デッドロック状況の影響を最小限に抑えるために、プラス記号のロックを使用する際は常に timeout 引数を含める必要があります。例えば、LOCK +^a(1):10 のようにします。

デッドロックが発生した場合は、管理ポータルまたは LOCKTAB ユーティリティを使用して、問題になっているロックのいずれかを削除できます。管理ポータルから、[ロック] ウィンドウを開き、デッドロック・プロセスに対して [削除] オプションを選択します。

FeedbackOpens in a new tab