# CHAPTER 12: Empress のロック

## 12.1 はじめに

データベースとアプリケーションの設計では、大体の場合において以下の２つの要求により 制約され、それらを実行し続けなければなりません。

1. 同時にデータにアクセスする複数のプロセスを提供すること
2. データの整合性を維持すること

これらの目的のどちらかを達成するためには、他を犠牲にすることにより得られるため、 データベース管理者とアプリケーション開発者のチャレンジは、そのシステムのユーザーの 必要性に合った最適な折り合いを見つけることになります。

大概の場合、データ整合性は最も重要な関心事です。 データベースへ書き込む（例えば insert , update , delete)プロセスは、 その整合性に影響する可能性を持っています。 そのため、それらの動作を制御する必要があり、 Empressのデータベースアクセスは、プロセスからのデータへの アクセスを制御するデータベースエンジンによって仲介されます。 データベースアクセスの間は他のプロセスによる更新からデータを 保護することにより、その整合性は維持されます。 このメカニズムはロックとして知られ、 整合性を維持するために用いられます。

プロセスの同時性と速度のバランスを考えると、 データベースに書き込み（insert, update, delete 操作を通じて）を行う プロセスによって示されたロックを行う必要があり、 これらの操作を実行するどのようなプロセスでも、 他のプロセスに対して、データアクセスの制限を引き起こし、 その結果としてプロセスが遅くなる原因を生じさせます。 Empress は、ユーザーのアプリケーションに合わせた 最適なロックスキームを選択することにより、これらのボトルネックを 減らすことができます。

このロック機構は、概念的でエンドユーザーに目に 見えないものであるため、このドキュメントでは、 データベース管理者とデータベースアプリケーションの 開発者を対象に説明し、以下を目標とします。

- データベース管理者(DBA)は、効果的なデータベースのセットアップ およびデータベース管理を行うことができる。 また、ユーザーによって要求を加えることでデータベースを 調整することができる。
- アプリケーション開発者は、理想的な同時性と応答性のアプリケーションを作成する。

Empressのロックを理解することにより、 ロック固有の同時に満足できない諸条件の調整を最小限にさせ、 ロックの競合の問題の解決を実現するための手助けとなります。

このドキュメントでは、バージョン 8 に実装されているEmpressのロックに ついて説明されます。 他のEmpressバージョン(V6.x, V4.x)では、ここに記述された内容と ほぼ同様ですが、細かなところで実装の違いがあります。 （例えば、新しい`MSxxx`変数やロックのかかるタイミングなど） 昔のEmpressバージョン(V1.x, V2.x)では、 このドキュメントに記述されたほとんどが実際とは異なることに注意してください。

この章では以下の項目を扱います。

- ロックの基本的な側面

  - ロックの分類とモード
    - ユーザーロックとテーブルオープンモード
    - リレーショナルロック
    - 物理的なロック
  - ロックアルゴリズム
  - ロックマネージャ

- ロックの様々な側面

  - 4GL および AG のロック
  - トランザクション中のロック
  - DBA モード

- ロックの管理

  - ロックの配置
    - 明示的な配置
    - 暗黙的な配置
  - ロックのクリア
  - シェアードメモリロックマネージャの作成

- ロックの監視

  - ロックの監視ツール
  - 例えば: 単純なSQLを使用した場合

- Empress ロックのチューニング

  - 暗黙的なロックのスキーム
  - ロックのパラメータ
  - シェアードメモリ対ファイルロックマネージャ
  - ロックマネージャのチューニング

## 12.2 ロックの基本的な側面

Empressにおいては、論理的、または物理的に基づき、 ロック機構を広範囲に３つの分類として区分し、 ロックを考えることができます。 以下はその分類になります。

表 12-1: Empress ロックの分類

分類 | 説明
操作上のロック | データベースのスキーマ上でのテーブルおよびビューのロックは、 テーブルの実体をロックするための広範囲の規約を指定することにより、 ユーザーによって制御することが可能です。 これは暗黙的にロックの配置が起こる場合にEmpressが配置する リレーショナル分類においてのロックがどのように配置するかを決定します。 規約は要求された全てのデータ整合性の保証するためにユーザーよって選択され、 概してトレードオフは、データ整合性の向上させることにより、 プロセスの同時性を損なう関係になります。
リレーショナルなロック | この分類でのロックは、データファイル、インデックスファイル、 またレコードとしての低レベルでの実体として扱われます。 ロックは明示的、または暗黙的にテーブル上に置かれ、 「操作上でのロック」は、低レベルな対象としての 「リレーショナルなロック」の設定へと訳されます。 この分類のロックは、ユーザーに対し、少なからず透過性があるべきで、 同時性とその効果の問題をユーザーにしばしば気付かせることを求めます。
物理的なロック | この分類のロックは、ファイルまたはシェアードメモリパーティションへの エントリとして実際に現されます。

操作上の分類では、ロックが置かれる規約を定義します。 ロックは、リレーショナルの分類で描かれた配置に置かれ、 そして、そのロック間の相互作用は物理的な分類によって決定されます。 ロックマネージャは、排他的な物理ロックを扱います。 そのロックの働きは（結果としての衝突）は物理ロックの相互作用として 理解することができます。また、物理ロックの存在はリレーショナルと操作上の 分類から理解できます。

概して、より高いレベルのロックは、低いレベルのそれぞれにより実装され、 低レベルでのロックは、それらの操作は独立しているため、 より高いレベルのロックすべてに直接、関係付けることはできません。 そのため、例えば、操作上の分類でのテーブルレベルロックの概念は、 リレーショナル分類では、テーブルロックのような実体ではなく、 代わりにテーブルレベルロックの概念に相当する様々な種類の ロックの集合になります。

### 12.2.1 操作分類のロック

Empressのすべてのロック操作は、各テーブルを基本として定義されます。 レコードの更新や読み込みのためにテーブルがオープンされる場合、 暗黙的なテーブルのロックレベル、または指定されたロックレベルやモードで 明示的にテーブルをオープンすることにより、決められたロックのセット（ロック）が 置かれます。 明示的にロックに影響する共通のユーザーコマンドの要約の記述は、 このドキュメントのロックの管理 のセクションを参照してください。

ロックレベルは、テーブルへのロックの適応範囲を決定します。 これはテーブルの作成者およびによって指定されますが、権限の与えられた ユーザーも変更することができます。 （Empress SQL: リファレンス マニュアル の`GRANT PRIVILEGE`コマンドを参照してください。) 設定可能なロックレベルは以下の表に要約されます。

表 12-2: ロックレベル

ロックレベル | 説明
`record` | 各レコードは個別にロックされ、 ロックは次のレコードにアクセスされた時に解放されます。
`group` | `group` `group`内のすべてのレコードはロックされ、 次のグループにアクセスされたときにロックは解放されます。 ここでの1グループは、Empressが`WHERE`句の条件を満たすために アクセスしなければならないレコードセット（レコードの集合）のことになりますが、 注意として多くの場合、正確に`WHERE`句の条件に満足するこれらのレコードが ロックされるという意味ではなく、 クエリ内のアトリビュートにインデックスが付けられていない場合は、 Empressはテーブル全体を検索します。この場合においては、 "group"は"table"レベルロックと同じ意味を持ちます。
`table` | （テーブル中のいくつかのレコードにアクセスするために） テーブルがオープンされた場合、テーブル全体がロックされます。
`null` | ロックレベルが"null"でテーブルをオープンした場合、 そのテーブルにはロックが置かれません。

`record`, `group` および`table`のロックは、それ自体は存在せず、 これらは概念的なものであり、リレーショナル分類での 一連のロックの操作であり、実行されるロックのスキームの 定義であることに注意してください。

テーブルのオープンモードは、操作上の分類の他の側面になります。 以下は、テーブルをオープンする場合に設定可能なモードになります。

表 12-3: オープンテーブルロックモード

シンボル | モード | 説明
`r` | read | read lockが、テーブルに置かれ、 更新、削除または挿入するための試みは失敗します。 （これらの操作は、その前にupdate lockを テーブルに置くことを必要とします。）
`d` | deferred | テーブルにread locksが、最初に置かれますが、 このテーブルの更新、削除または挿入の操作を妨げません。 これらの操作が行われた場合、そのテーブルに最初に置かれた read lockは、update lockに昇格され、 その操作が終了すれば、read lockに降格されます。
`u` | update | update lockが、テーブルに置かれます。
`n` | dirty read | レコードを検索する場合、read lockは置かれません。 （どのようなロックでもバイパスします。） このモードでは、更新、削除または挿入するための試みは失敗します。
`N` | deferred dirty read | update lockが、最初にテーブルに置かれます。 更新、削除または挿入操作が実行された場合、 そのロックに適合した通常の振る舞いが行われますが、 検索が実行された場合は、どのようなロックでもバイパスし、 データを取得します。

### 12.2.2 リレーショナル分類のロック

ロックの操作は、リレーショナル分類のロックに直接、 関連付けられているため、Empressよって ロックされている対象を見つけることから始まります。

Empressは、読み込みや書き込みの目的のための ユーザーリクエストのサービス中のアクセスにおいて 必要な対象を決定しています。 例えば、

       INSERT INTO table_name VALUES (1, "abcdefghijklmnopqrstuv");

例えば、上記のINSERT文で最初のアトリビュートにインデックスが 付けられていて、次のアトリビュートタイプは`TEXT`である場合、 この操作おいてEmpressは以下の動作を行います。

1. テーブルのオープン

   - `table_name`に関連付けられた`.rel`ファイルを決定します。
   - `table_name`に一致するテーブル名の`sys_dictionary`を読み込みます。 （この操作は`dict_tabname`アトリビュートのインデックスが暗黙的に使用されます。）
   - このテーブルが使用されていることを示すためにテーブルに `ADMIN` `r`のロックをします。 （この操作はアクセスしている間に他のユーザーからのテーブルの定義の変更(`ALTER`) を防ぎます。）

2. レコードを挿入するために 使用または再使用することができる `.rel`ファイルの空きスペースを テーブルのフリーレコードリストから、読み込み、探します。

3. レコードの挿入を行います。必要であるならば、 オーバーフローファイル(`.dtf`ファイル）への データ挿入を含みます。

4. フリーリストの更新

5. インデックスの更新

6. テーブルのクローズ

   - テーブルの`ADMIN` `r` ロックの解放

通常、Empressは、その操作中において以下の対象のいずれかに アクセスが必要な場合、各対象ごとのリレーショナル分類ロックの 決められたタイプが使用されます。

表 12-4 リレーショナルカテゴリーロックの対象

対象 | ロックタイプ
`.rel`ファイル - テーブルヘッダー(フリーレコードリスト) - レコード | `ADMIN` `CRIT` `RECORD`, `ALLRECS`
`.dtf`ファイル | `CRIT`
`.ix` および `.ixl` ファイル | `CRIT`

テーブルヘッダーについてもう少し補足すると、フリーレコードのカウンタ ならびにフリーレコードリストのポインタが含まれています。以下は、それらの 管理についての概要です。

  すべてのテーブルは空きレコードリストを持っています。 （テーブルのフリーリストと呼びます。) フリーリストは、新しいデータを格納するために使用され、 空きレコードのリストが線形でリンクされています。 従って、テーブルからレコードが削除されると、 削除レコードへのポインタが、このリストの最後に追加されます。 （そのため、レコードを削除しても、、 `.rel`ファイルは物理的に小さくはなりません。） そして、その情報は更新され、 `.rel`ファイルのヘッダー に格納されます。 同様にレコードをテーブルに挿入する場合はフリーリストが 使用されます。 (そのため、レコードを挿入にしても必要がなければ（フリーリストがある場合）、 `.rel`は大きくなりません。）

テーブルのフリーリストを更新する多くのプロセスは、 （例えば、登録または削除操作を通しての） 排他的にフリーリストにアクセスしなくてはなりません。 そうしない場合、データの整合性に不整合が発生することがあります。 この理由ため、Empressは これらのすべての操作の間、`CRIT`ロックを適用します。

リレーショナル分類のロックは、それらのモードとタイプの観点から 説明されます。 ロック間の衝突に影響するロックのタイプとモードに関して 2つの重要なポイントがあります。

1. ロックは、様々なタイプとして存在することができますが、 異なるタイプのロックに対して、決して干渉することはできません。 唯一、同じタイプを持つロックに対しては、 衝突（干渉）を引き起こすことができます。

2. 同じタイプのロック内では、他のロックとの互換性によってロックモードが 決定されます。

可能なロックタイプは以下の表になります。

表 12-5 ロックタイプ

タイプ | 説明
`ADMIN` | テーブルが使用され始めたことを示すために置かれます。 (例えばある理由でオープンされた場合)
`CRIT` | タイムクリティカルなリソースが使用される場合に置かれます。 （例えばインデックスやテーブルのフリーリスト、あるいはテーブルの オーバーフローのようなリソースを扱う場合）
`RECORD_n` | テーブルのn番目のレコードがアクセスされた場合に置かれます。 `n`は、テーブル中の物理レコード番号です。
`ALLRECS` | 効果のために置かれます。 テーブル内の少なくとも1レコードがアクセスされ始めたことを示します。

有効なロックモードは、読み込み操作のための`r`と`rr`、 更新操作のための`u`と`uu`があります。 同じタイプ、および異なったモードのロックの互換性は、 下の表に示されます。 表の列 A と 行 B　の交差する`yes`と示されているものは モードA と B を持つロックは共に存在することができます。 同様に`no`は、ロック A が存在する場合、 要求された ロック B は共に存在することができません。 この場合、存在しているロック A が、それを置いたプロセスによって 解放されるまで、ロック B を置くことを要求しているプロセスは 待たなくてはなりません。

表 12-6: 同じロックタイプのロックモードの互換性

ロックモード |  | `rr` | `r` | `uu` | `u`
`rr` |  | `yes` | `yes` | `yes` | `no`
`r` |  | `yes` | `yes` | `no` | `no`
`uu` |  | `yes` | `no` | `yes` | `no`
`u` |  | `no` | `no` | `no` | `no`

全てのタイプのロックは`r`または`u`モードを持つことが 出来ることに留意してください。 また、唯一`ALLRECS`タイプのロックだけは、 `rr`または`uu`モードを持つことができます。

`rr`と`uu`のロックモードは`ALLRECS`のロックタイプとして 説明しましたが、`ALLRECS`ロックは、テーブルに対して 何らかの操作が行われる場合にEmpressによって要求されます。 これは、そのテーブル内のどこかにおいて、例えば読み込みや更新などの操作が 存在することを示し、 より効果的に（操作上の）暗黙的なテーブルレベルのロックスキーム を作成するために示されます。

テーブルレベルのロックスキームでは、 読み込みと更新の操作は、 それぞれ、`r`と`u`のALLRECSロックを 得るための試行が行われます。 レコードレベルのロックでは、 読み込みと更新の操作は、最初に それぞれに、 `rr`と`uu`ALLRECSロック を得るための試行が行われます。 ロックモードの互換テーブル（上の表）での検査では、 `u`ロックは共存することはできませんが、 `uu`ロックモードは共存することができます。 `ALLRECS` ロックを使用することにより、Empressは、 同じ物理ロック機構を使って、レコードレベルロックスキームと同様に テーブルレベルロックスキームを実装することができます。

場合によっては、`rr|uu`として報告された（このドキュメントの ロックの監視 を参照してください。）モードを見つけることが あるかもしれません。 "`|`"は、(`rr` と `uu`)ロックの タイプの両方が存在することを意味するシンボルで、 これは、`ALLRECS`タイプのロックにだけ起こります。 従って、`ALLRECS`の`rr|uu`の指示子は テーブル中のいくつかのレコードが、 それらの中にリードロック(`r`)が置かれ、 また他にアップデートロック(`u`)が置かれている間、 を意味します。

Empressは、ロックのリクエストをロックマネージャに 送ることによって、リレーショナル分類のロックを置きます。 (物理分類のロックを参照してください。) ロックのリクエストは、指定されたテーブル上に１つ以上のロックを 置くかあるいは解放するためのロックマネージャへのステートメントの セットになります。 各操作ごと、それを実行するために問い合わせが行われ、 Empressはそれらの操作の各ステップごとにロックを置くか あるいは解放するために必要なロックのセットを決定します。 それから、このロックのセットの操作を実行するために ロックマネージャへリクエストを送ります。

すべてのロックのリクエストは、以下の３つのうちの１つの結果になります。

a) | 成功
b) | 失敗。ロックマネージャへの排他的なアクセスすることができないため。
c) | 失敗。 少なくとも１つのロックを置くためのリクエストが、 ロックマネージャによって拒否されたため。

a) は、個々のリクエストが全てが成功した場合で、 b) は、個々のリクエストのひとつも成功しない場合、 c) は、個々のロックの配置のいずれかが拒否された場合、 （その理由としてロックマネージャによって衝突が見つかったため） リクエスト中の全てのロックの配置は失敗します。 しかしながら、リクエスト中のすべてのロックの解放は成功しています。

例えば、`table_name`テーブル上に `ADMIN`と`CRIT`ロックの配置を仮定した場合、 １つのロックのリクエストが発生します。 このリクエストによって、`ADMIN`ロックの配置に成功し、 `CRIT` ロックが置くことが出来なかった場合、 全体のリクエストは失敗であり、またロックも置かれません。

リレーショナルロックは様々なSQLのクエリに応じて配置され、 それについてのさらに詳細な情報は このドキュメント内のロックの監視を 参照してください。

### 12.2.3 物理分類のロック

Empressロックマネージャは、排他的な物理分類のロックを扱います。 ロックマネージャの働きは、ロックの取得と解放の仲介を行います。 ロックマネージャでは、ロックは、 取得や解放するかを決定するためのプロパティを持つ、 単純な対象になります。 プロパティには、以下の固有の情報が含まれます。

- ロックが適用されたテーブル番号
- ロックタイプ
- ロックモード
- レコード番号 (適用された場合)
- ロックを所有するプロセスのEmpress ID

ロックマネージャが、ロックを置くためのリクエストに応える場合、 これらのすべての情報を集め、ロックを置くことが可能かどうかを チェックします。 それを決定するための規則は、 リレーショナル分類のロック. に記述されています。

ロックが置くことができない場合、ロックマネージャは、 デッドロック状態を回避するために設計された Empressのロックアルゴリズムを通じて、 その操作をリトライします。 デッドロックは、２つ以上のプロセスが、他プロセスによって ロックされたレコードを得ようとして待っている状況で起こります。 ロックの取得に失敗した（試みを繰り返した後）どのようなプロセスでも、 失敗がデッドロックの状況であるかどうか分からないため、 デッドロックが起こらないことを確実にするために 現在、取得しているロックをすべて解放する必要があります。 これを行うことにより、現在まで保持されていたレコードが 他のプロセスで利用することができ、それによりシステムの デッドロックを防ぎます。

ロックアルゴリズムは以下の図で表されます。

図 12-1: ロックアルゴリズム

このアルゴリズムは、ロックを取得するために、ある回数分、リトライし、 それに失敗するごとに次のリトライをする前に確実にある時間を待ちます。 リトライの回数とそれぞれが失敗した後に待つ時間は システム管理者によって設定することができます。 リトライ回数およびスリープ秒数に関連した8つの `MS`変数があります。 その中の４つは変数の先頭に`MS`が付けられた名前で 残りの４つは`MSIA`が付けられた名前です。 `MSIAxxx`変数は、対話モードでの環境で使用されるもので、 `MSxxx`変数は、バッチ環境で使用されます。 これらのすべての変数は`$EMPRESSPATH/config/initfile` ファイルに定義されています。

`MSEXCLRETRY` | ロックファイルへのオープンが試みられる回数を制御します。
`MSLOCKRETRY` | ロックの取得が試みられる回数を制御します。
`MSEXCLSLEEP` | ロックファイルをオープンするための試みの間のスリープ秒数を指定します。
`MSLOCKSLEEP` | ロックの取得する試みの間のスリープ秒数を指定します。

ロックの競合が激しいと予想される状況では、 ロックの衝突数を減らすため、他のプロセスに 異なった値を`...SLEEP`パラメータに 設定することができます。

インデックスファイルの場合は特別で、 Empressは処理を行う前に クリティカルリードロックのセットを必要とします。 このロックの取得をおこなう間の Empressの動作を制御する 以下の２つの変数が提供されます。

`MSINDEXRETRY` | 上記の`MSxxxRETRY`と同様な変数ですが、 インデックスファイルへのリードアクセスをするために必要な クリティカルロックの取得をする間だけに使用されます。 この変数がセットされない場合は、デフォルト値は 0 です。
`MSINDEXSLEEP` | 上記の`MSxxxSLEEP`と同様な変数ですが、 インデックスファイルへのリードアクセスをするために必要な クリティカルロックの取得をする間だけに使用されます。 この変数がセットされない場合は、デフォルト値は 1秒です。

### 12.2.4 ロックマネージャ

Empressのほとんどのバージョンでは、 ファイルロックマネージャとシェアードメモリロックマネージャの ２つの物理的なロックマネージャが実装されています。 すべてのEmpressのロックマネージャには、 以下の点が設定されています。

1. 同時にアクセス可能な最大プロセス数
2. 保持可能な最大ロック数

こられのパラメータはユーザーによって、 データベースにアクセスするアプリケーションの要求に合った 調整をすることができます。 （詳しくは Empress のロックのチューニング を参照してください。)

デフォルトの物理的なロックの実装は ファイルロックマネージャになります。 データベース`db`中には、 `xxxx.lck`のような名前を持つ、多くのファイルを含んだ ロックディレクトリ`db/_lock`が存在します。 この`xxxx`の番号は、テーブルの`.rel`ファイル名の テーブル番号と一致します。 このことから、テーブル`table_name`が `.rel`ファイル`db/0092.rel`と一致する場合、 ファイルロックマネージャを推測すると そのロックファイルは`db/_lock/0092.lck`になります。 ファイルロックマネージャが削除された場合、 ロックマネージャはロックを保持するために必要とするため、 次回のアクセスにおいて、自動的に作成されます。

ユーザーは、指定されたテーブルのためのロックを にシェアードメモリー中に置くことを選択できます。 シェアードメモリーロックマネージャは、 すべての`xxxx.lck`ファイルが、 各テーブルに対し、１対１で一致するような ファイルロックマネージャとは異なり、 １つ以上のテーブルのロック情報を 持つことができます。 また、ファイルロックマネージャと異なる点として、 システム障害が発生した場合、マシンが再起動されたときに ロックマネージャを保持するシェアードメモリパーティションを 再作成する必要があります。

シェアードメモリロックマネージャは、Empress ユーティリティ `empadm`と`empshm`を通じて作成されます。 これらのユーティリティの使用法などの詳細は、 このマニュアルの シェアードメモリ の章を参照してください。

## 12.3 ロックの様々な側面

### 12.3.1 ロックとトランザクション

トランザクション中、Empressは、 トランザクション時以外の場合と同じ方法で 確実にロックを置きます。 （例えば）特定のテーブルに対して指示されたSQLコマンドは、 同じロック配置のリクエストで同じ順序となります。 （それぞれのロックのリクエストは同じであり、 リクエストは同じ順序で要求されるためです。) しかし、トランザクション時においては以下の2つの点で 異なった動作をします。

1. ロックの解放の順序
2. トランザクションの終了時のロックの取得

トランザクション中に置かれたほとんどの ロックの解放の順序は、通常のEmpressの動作とは異なります。 この規則の例外は、

- すべて`CRIT`タイプのロックになります。： （このロックは使用した後に直ぐに解放するために取得されます。）

トランザクションの終了は、`ROLLBACK`か `COMIT`により知らされ、 その時点でのEmpressの動作は、 ロックメカニズムへのアクセスを含んでいます。 Empressがロールバックする場合、 以下のロックの動作が行われます。

- トランザクション中に確実に操作が行われた テーブルの`CRIT`ロックを取得します。

  - 挿入、削除:　全ての場合、
  - 更新： インデックスを持っているアトリビュートの更新かあるいは バルク/テキスト型のアトリビュートが更新された場合、

- これらのテーブル上で行われた全ての操作の取り消します。

- `CRIT`ロックの解放します。

- トランザクションによって保持され、 残されているすべてのロックを解放します。

コミットの場合、Empressは以下のロックの動作を行います。

- トランザクション中に 書き込み操作がテーブルに行われた全てのテーブルの `CRIT`ロックを取得します

- これらのテーブルのヘッダー情報を更新（例えばフリーレコードリスト）します。

- `CRIT`ロックを解放します。

- トランザクションによって保持され、 残されているすべてのロックを解放します。

`MSTRANSTABLELOCK`環境変数は、 トランザクションの連続性を保証する場合に有効ですが、 それを有効にすると強い同時性の不利があるため、 デフォルトでは有効ではありません。 この変数が効果的な場合は、テーブルレベルロックを持つテーブルを トランザクション中に扱う場合にこの変数をチューニングします。 トランザクションが利用されない場合は、この変数は影響しません。

`MSTRANSTABLELOCK`が有効にされ、トランザクションが開始された場合、 Empressは、現在、オープンされているすべての テーブルに`ALLRECS`を置きます。 また、トランザクションの間にオープンされたすべてのテーブルに このロックは適用されます。 この場合のロックのモードは、 以下のテーブルのオープンモードに依存します。

テーブル `オープン` モード |  | `r` | `d` | `u`
`ALLRECS` モード |  | `r` | `u` | `u`

トランザクションがコミットあるいはロールバックされた時にのみ、 これらのロックは解放されます。

### 12.3.2 シングルユーザー DBA モード

データベース管理者(DBA)は、以下のコマンドを発行することで Empressデータベースを一時的に無効化することができます。 （データベース管理者のみにデータベースアクセスを制限します。）

       empadm database_name singlemode

このコマンドは、他のユーザーからのデータベースアクセスを防ぐために `sys_dictionary`に`ADMIN` `u`ロックを置きます。 この理由は、すべてのデータベースアクセスは、`sys_dictionary`の オープンが必要で`sys_dictionary`の`ADMIN` `r`ロックを 要求しますが、`singlemode`の実行で`ADMIN` `u`ロックが かけられているため、衝突し、このロックを得ることができません。 逆に、あるユーザーがデータベースにアクセスしている場合は、 ユーザーは`sys_dictionary`の`ADMIN` `r`ロックを 得れますが、DBAが、`singlemode`を実行しようとしても `ADMIN` `u`ロックは得ることは出来ないため `singlemode`に入ることはできません。

注意として、DBAモード中ではシングルユーザーDBAモードの効果を無くすような 全体のロックをクリアするコマンド (`empadm database_name lockclear`のような) を発行すべきではありません。

### 12.3.3 4GL と AG のロック

Empress 4GLとアプリケーション・ジェネレータ(AG)は、 ロックに関して特別な動作を要求します。 要求は以下の２つになります。

1. `sys_4gl_xxx`と`sys_ag_xxx`テーブルに 格納されたユーザーアプリケーションは、 アプリケーションが修正されている場合でも 実行できる必要があります。

2. アプリケーションが1人のユーザーによって修正される場合、 他の人が同時にそれを修正をすることはできません。

4GLアプリケーションの実行および アプリケーションの定義(例えばソースコード)が、 異なったテーブルに格納されるため、 Empressのレコードレベルでのロック機構は、 1番目の要求には適合しますが、2番目の要求には不十分です。

4GL アプリケーションは、以下のテーブルにレコードセットとして格納されます。 （これらはアプリケーション・ジェネレータのためのテーブルのセットと同様です。 詳細はマニュアルのEmpress 4GL: 管理者ガイドを参照してください。）

|  |  | `sys_4gl_application sys_4gl_compile sys_4gl_domain` | `sys_4gl_field sys_4gl_form sys_4gl_key` | `sys_4gl_link sys_4gl_script sys_4gl_window`

4GL アプリケーションは、上記の分割されたテーブルに格納されるため、 通常のEmpressのロックスキームは、 1ユーザーのみが指定されたアプリケーションの全体を 修正する場合にそれを保証する能力はありません。 従って、追加的なロックメカニズムが必要になります。

Empressは、4GL と AG のロックを提供しますが、 このドキュメントで説明されている ロック機構を使用するのではなく、 ロックは`sys_4gl_application`と`sys_ag_definition`の 単なるアトリビュートとして存在します。 そのため、Empressのロック機構を通して検査されはしませんが、 4GL と AG のアプリケーション自身によって確かめられ、 ロック機構の代わりになります。

4GL と AG の`sys_4gl_application`と `sys_ag_definition`の両方が ロックを示すアトリビュートになります。 ユーザーがアプリケーションを編集する場合、 これらのアトリビュートに`y` が設定されます。 設定された場合は、他のユーザーはアプリケーションの編集を 許可されませんが、そのアプリケーションを実行することはできます。

これらのロックをクリアするために、 ユーザーは以下のコマンドを使用できます。

       empclrlk -ag Database_name

       empclrlk -4gl Database_name

この`empclrlk`ユーティリティは、 特定のテーブル内のロックアトリビュートをヌルにします。 `-ag`が付加された場合は、 様々な`sys_ag_xxx`テーブルに対してクリアします。 このユーティリティは、通常のデータベースのロックを もまたクリアすることに注意してください。

## 12.4 ロックの管理

Empressは、データベースに暗黙的あるいは明示的にロックを置くことができます。 多くの状況では暗黙的にロックは、配置されるため、 ロックの配置と削除の詳細について、ユーザーに透過する必要があります。

しかしながら、Empressは、 Empress SQL、Empress 4GLやmrのC言語のレイヤのような いくつかのインターフェイスでは明示的なロックを置くことをユーザーに許していますが、 リポートライター、フォートランインターフェイス、 埋め込み SQL(スタテックとダイナミック) およびmx C言語インターフェイスでは、明示的なロック配置のメカニズムを 提供しておりません。

Empressの暗黙的なロック配置のスキームの動作は、 環境変数によって変更することが可能です。

通常の処理において、 Empressは、ロックを配置し、解放しますが、 場合により、ロックが残されることがあります。 これは、ロックを置いたプロセスが、それをクリアする機会がなく、 死んでしまったための結果で、このことにより、 他のプロセスに対してデータのアクセスを防ごうとするため、 問題が生じます。 この場合、手動でロックをクリアする必要があり、 `empadm`ユーティリティを使用します。

最後に、ロックはファイルロックマネージャかシェアードメモリロックマネージャの いずれかに置くことができます。 ファイルロックマネージャはデフォルトで、テーブル作成の時に作成されます。 シェアードメモリロックマネージャは、テーブル作成後、DBAによってセットアップされ、 マシンが再起動されたときに再作成する必要があります。

### 12.4.1 明示的なロック

以下は、明示的なロックに関する共通ユーザーコマンドの構文です。

SQL: |
`LOCK LEVEL [ON] table [IS]` | `|TABLE |GROUP |RECORD |NULL` | `|; | | |`
このコマンドは、テーブルのロックレベルを暗黙的に設定します。
`LOCK table [IN]` | `|EXCLUSIVE |EXCL |SHARE` | `| [MODE]; | |`
このコマンドはトランザクションの間だけ効果を持ちます。 `EXCLUSIVE` または `EXCL` モードは、 テーブルに`ALLRECS` `u`ロックを取得します。 `SHARE`モードは、テーブルに`ALLRECS` `r`を取得します。 ロックはトランザクションの終了時に解放されます。 また、これはテーブルレベルの読み込みおよび更新ロックに効果があります。
4GL: |
`LOCK table [IN]` | `|EXCLUSIVE |EXCL |SHARE` | `| [MODE]; | |`
このコマンドは、上記のSQLバージョンと同じです。 これはテーブルレベルの読み込みおよび更新ロックに効果があります。
mr: |
    mrlkrec (record_descriptor)
可能であるならば、レコードに`RECORD_n` `r` または `u`ロックを 取得します。 これはレコードレベルの読み込みおよび更新ロックに効果があります。
    mrlktab (table_descriptor)
可能であるならば、テーブルに`ALLRECS` `r` または `u`ロックを 取得します。 これはテーブルレベルの読み込みおよび更新ロックに効果があります。
    mrulrec (record_descriptor)
レコードの`RECORD_n` `r` または `u` ロックを解放します。 また、解放した`RECORD_n`ロックが、そのテーブルの唯一の未解決のレコードロック であった場合、テーブルのすべての`ALLRECS`ロックも解放します。
    mrultab (table_descriptor)
テーブルに`ALLRECS` `r` または `u`ロックが存在する場合、 それらを解放します。 このロックモードは、テーブルのオープンモードによって取得されます。 設定可能なテーブルのオープンモードは、`r` (read), `d` (deferred), `u` (update), `n` (dirty read)および `N` (deferred dirty read)です。 詳細な情報は以下を参照してください。 Empress: SQL リファレンス, Empress: C カーネルレベルインターフェイス - mr ルーチン Empress 4GL 言語リファレンス マニュアル および、このドキュメントのロックの基本的側面

### 12.4.2 暗黙的なロック

暗黙的なロックが行われる場合、 ロックは以下の要因によって置かれます。

1. 暗黙的なテーブルレベルロックによる
2. テーブルのオープンモードによる
3. 操作の実行されることによる
4. 様々なEmpressの`MSxxx`システム変数による

Empressの操作は、大きく分けると以下の２つのカテゴリに分けることができます。

- データベースに格納されたレコードの更新および検索するためのデータ操作言語(DML)コマンド
- データベースおよびテーブルの構造自体を修正、定義するためのデータ定義言語(DDL)コマンド

ここでは、 `update`および`read` 操作をはじめとする DML および DDL グループに分類された コマンドについて説明を進めていきます。

以下は、Empressのいくつかのインターフェイスコマンドの分類の例です。

- |  | SQL インターフェイス | mr プログラム | 4GL インターフェイス
DML-Update |  | `INSERT DELETE UPDATE` | `mradd () mrdel () mrput ()` | `insert delete update`
DML-Read |  | `CREATE TABLE DROP TABLE ALTER TABLE CREATE INDEX DROP INDEX` | n/a | n/a
DDL-Read |  | `DISPLAY TABLE` | n/a | n/a

これらのカテゴリの各操作は、いくつかの暗黙的なロックを置きます。 以下の表は、 対話型 SQL インターフェイスを通して置かれるロックを示した例です。 （以下の表ではテーブルはインデックスを持っているとして、 `.ix`と`.ixl`ファイルに`CRIT`ロックが置かれますが、 インデックスがない場合は、`.ix`と`.ixl`ファイルはなく、 `CRIT`ロックもありません。） また、ここでは操作の順番については言及しません。 （詳しくはこのドキュメントの ロックの監視 のセクションを参照してください。)

DML 操作、レコードレベルロック

操作分類
ロックの対象 | タイプ | モード
DML-Update |
`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `uu`
`.rel` file header | `CRIT` | `u`
`.ix`, `.ixl` files | `CRIT` | `u`
`.dtf` files | `CRIT` | `u`
`.rel` file record | `RECORD_n` | `u`

DML-Read

`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `rr`
`.rel` file header | `CRIT` | `r`
`.ix`, `.ixl` files | `CRIT` | `r`
`.dtf` files | `CRIT` | `r`
`.rel` file record | `RECORD_n` | `r`

DML 操作, グループレベルロック

操作分類
ロックの対象 | タイプ | モード
DML-Update |
`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `uu`
`.rel` file header | `CRIT` | `u`
`.ix`, `.ixl` files | `CRIT` | `u`
`.dtf` files | `CRIT` | `u`
`.rel` file record | `RECORD_n` | `u`

DML-Read

`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `rr`
`.rel` file header | `CRIT` | `r`
`.ix`, `.ixl` files | `CRIT` | `r`
`.dtf` files | `CRIT` | `r`
`.rel` file record | `RECORD_n` | `r`

DML 操作、 テーブルレベルロック

操作分類
ロックの対象 | タイプ | モード
DML-Update |
`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `u`
`.rel` file header | `CRIT` | `u`
`.ix`, `.ixl` files | `CRIT` | `u`
`.dtf` files | `CRIT` | `u`
`.rel` file record | `RECORD_n` | `u`

DML-Read

`.rel` file | `ADMIN` | `r`
`.rel` file | `ALLRECS` | `r`
`.rel` file header | `CRIT` | `r`
`.ix`, `.ixl` files | `CRIT` | `r`
`.dtf` files | `CRIT` | `r`
`.rel` file record | `RECORD_n` | `r`

DML 操作、 ヌルレベルロック

操作分類
ロックの対象 | タイプ | モード
DML-Update |
`sys_dictionary` | - | `r`
DML-Read |
`sys_dictionary` | - | `r`

DDL 操作

操作分類 | ロックの対象 | タイプ | モード
DML-Update
       create/drop comment
       create/drop index
       create/drop range check
       create/drop referential
       create/drop table
       create/drop view
       grant/revoke privilege
       lock level
       lock table
       rename table
| `sys_dictionary` | - | `u`
DDL-Read
       display db
       display privilege
       display table
| `sys_dictionary` | - | `r`

上記の表において、 システムテーブル(`sys_dictionary`, `sys_tables`, `sys_attrs`, `sys_privs`および `sys_attr_privs`)は、 デフォルトのロックレベル（例えば`RECORD`) であると仮定します。 しかし、この仮定とは違う場合 （例えば、DBAが`sys_tables`にロックレベル`NULL`を設定した場合） の操作は、確実に上の表とは異なるロックが置かれます。

`sys_dictionary`テーブルは、Empressによって作成され、管理されます。 この`sys_dictionary`テーブルは、 `sys_tables`、`sys_privs`, `sys_attrs`, および`sys_attr_privs` をコンパイルしたデータを持つテーブルです。

DML操作では、 問い合わせまたは更新をおこなうためにテーブルの定義や位置を格納している `sys_dictionary`に常に最初にアクセスされます。 `sys_dictionary`テーブルは、ユーザーによって作成される テーブルと同様な形式を持つ、Empressのテーブルで、 アクセスされるとき常に暗黙的ロックが置かれます。 以下のように`sys_dictionary`へ、暗黙的ロックは適用されます。

操作分類
タイプ | モード
DML-Update |
`ADMIN` | `r`
`CRIT` | `r`
`RECORD_n` | `r`
DML-Read |
`ADMIN` | `r`
`CRIT` | `r`
`RECORD_n` | `r`
DDL-Update |
`ADMIN` | `r`
`CRIT` | `r`, `u`
`RECORD_n` | `u`
DDL-Read |
`ADMIN` | `r`
`CRIT` | `r`
`RECORD_n` | `r`

表の`RECORD_n`は、その操作で扱われるテーブル番号と `.rel`ファイル名と一致するところの `sys_dictionary`の n 番目のレコードを示します。 `.rel`ファイル名のテーブル番号は、 システムテーブル`sys_tables`の `tab_number`アトリビュートに格納されています。 例えば、データベースに`tab`というテーブルがあると仮定した場合、 このテーブルに一致するテーブル番号を見つけるための検索は以下になります。

       SELECT tab_number FROM sys_tables WHERE tab_name = 'tab';

`tab_number = 19`である場合、 `sys_dictionary`のロックは、 `RECORD_19`のタイプのロックを示します。 これは、`sys_dictionary`の19番目のレコードに アクセスされ始めたことを指し示めします。 （このレコードが`tab`テーブルの情報を 含んでいるためです。）

`ALTER` や `TABLE`のようなEmpressの操作は、 確実にテーブルの`tab_number`を変更します。 そのため、テーブルの固有の情報としてテーブル番号を扱うべきではないことに 注意してください。

テーブルのオープンモードは、 オープン時のオープンされたテーブルに異なったタイプの `ADMIN`ロックが置かれることによって 暗黙的ロックに影響します。 C プログラミングインターフェイスおよび 4GL もまた、ユーザーが指定した テーブルのオープンによります。

### 12.4.3 環境変数

ロック機構の動作に影響を与える多くの`MSxxx`環境変数があります。 これらのうちのいくつかの変数は、Empressの ロックの取得と解放のタイミング（順番）を変更することを 引き起こします。 また、`MSLKCOMMITADDEND`や`MSLOCKCRITKEEP`のような変数は、 わずかばかりですが最適化のスイッチとして見ることができます。 他の変数(`MSDBLOCKLEVEL`や`MSDBDICTLOCK`のような)は、 ロックの暗黙的な配置を変更します。

以下の表は、ロックに関連したEmpress変数の概略説明になります。 この表には変数名および通常、設定する場所とその概要説明が含まれます。 多くのEmpress変数は、1つ以上の場所で設定することができます。 （`$EMPRESSPATH/config/initfile`の設定を上書きすることになります。） 変数は、環境変数として、あるいは`$EMPRESSPATH/config/initfile`、 または、`tabzero`に設定されますが、通常、設定する場所をこの表では 示しています。

変数名 | 場所 | 説明
`MSDBDICTLOCK` | `tabzero` | `sys_dictionary`テーブルのための暗黙的ロックレベルを 設定し、"`DISPLAY sys_dictionary all`"コマンドで表示される ロックレベルを上書きします。 値として`NULL`, `RECORD`, `GROUP` `TABLE`を設定することができます。 この説明では、動的に変更できるように書かれていますが、 動的には変更できず $EMPRESSPATH/rdbms/custom/tabzero にあらかじめ設定してから データベースを作成しないと有効にはなりません。 詳しくは、管理者ガイドのCHAPTER 2: データ辞書2.3.1.9 MSDBDICTLOCKを参照してください。
`MSDBLOCKLEVEL` | `tabzero` | 新しく作成されたテーブルの暗黙的なロックレベルです。 値として`NULL`, `RECORD`, `GROUP` `TABLE`を設定することができます。
`MSDBLOCKSTATS` | `tabzero` | この変数に何か値が設定された場合、 ロックの統計情報を蓄積し、 `empadm database_name lockstats`コマンドを使用し、 リポートさせることができます。 デフォルトでは設定されていません。 動的に設定することはできず、一度、ロックマネージャを削除し、 この変数を設定後、ロックマネージャを再作成させることで統計情報 を蓄積することができます。
`MSEXCLRETRY` | `initfile` | ロックファイルのオープンするための試行回数を制御します。
`MSEXCLSLEEP` | `initfile` | ロックファイルをオープンするための試行の間のスリープ時間を指定します。 （時間は秒、およびマイクロ秒）
`MSFILELOCKMAXPROCS` | `initfile` | ファイルロックマネージャに同時にアクセスが許可される 最大プロセス数になります。 通常、この値をユーザーが上げることはできません。 その最大値（デフォルト）は、Empressのライセンスによって 決められます。
`MSFILELOCKNBUCKETS` | `tabzero`, `initfile` | ロックファイルへロック情報を格納するためにEmpressが使用する ハッシュバケット数になります。
`MSFILELOCKNLOCKS` | `tabzero`, `initfile` | 同時に格納できる最大ロック数になります。
`MSIAEXCLRETRY` | `tabzero`, `initfile` | `MSEXCLRETRY`の対話型バージョンです。
`MSIAEXCLSLEEP` | `tabzero`, `initfile` | `MSEXCLSLEEP`の対話型バージョンです。
`MSIALOCKRETRY` | `tabzero`, `initfile` | `MSLOCKRETRY`の対話型バージョンです。
`MSIALOCKSLEEP` | `tabzero`, `initfile` | `MSLOCKSLEEP`の対話型バージョンです。
`MSINDEXRETRY` | `tabzero`, `initfile` | インデックスファイルに対してのロックリトライの指定ですが、 唯一、読み込み操作の場合は インデックスクリティカルロックの取得に対しては適応しません。
`MSINDEXSLEEP` | `tabzero`, `initfile` | インデックスファイルに対してのロックスリープの指定ですが、 唯一、読み込み操作の場合は インデックスクリティカルロックの取得に対しては適応しません。
`MSLKCOMMITADDEND` | `tabzero` | ロックレベルがレコードであるテーブルに連続したレコードを挿入する場合、 ロック配置のタイミングに大きく影響します。
`MSLOCKPLAN` | environment | この変数に何か値が設定された場合、 ロックの取得と解放を表示します。 値として"`t`"が設定された場合、ロック配置の時間を合わせて表示します。
`MSLOCKRETRY` | `tabzero`, `initfile` | ロックの取得を試みる回数を制御します。
`MSLOCKSLEEP` | `tabzero`, `initfile` | ロックを取得する試行の間のスリープ時間を指定します。 （時間は秒、およびマイクロ秒）
`MSLOCKSTATS` | environment | この変数に何か値が設定された場合、 問い合わせするプロセスのロックの統計情報のレポートを そのプロセスが終了するまで 表示します。
`MSPARTLOCKNAME` | `tabzero` | シェアードメモリロックマネージャのパーティション名を設定します。
`MSPARTLOCKNBUCKETS` | `tabzero` | シェアードメモリロックマネージャのハッシュバケット数を設定します。
`MSPARTLOCKNLOCKS` | `tabzero` | シェアードメモリロックマネージャで有効なロックの合計数を設定します。
`MSTRANSTABLELOCK` | `tabzero`, `initfile` | この変数が設定された場合、 プロセスの同時性の減少を犠牲にして、トランザクションの連続性を保証します。 トランザクションが開始されたときに現在オープンされているテーブルすべてに `CRIT` と`ALLRECS`ロックを適用します。 トランザクション中にオープンされたテーブルもまたこれらロックが適用されます。 これらのロックは、トランザクションがコミットされたときに解放されます。
`MSTRANSUFNGFL` | `tabzero` | テーブルへレコードを登録するプロセスの場合、 テーブルのフリーリストから取得する空きレコードの数を設定します。 デフォルトでは 10 が設定されています。

上記の変数のいくつかを説明します。

`MSLKCOMMITADDEND`変数は、 ロックレベルがレコードであるテーブルへレコードを挿入する際に ロックを置くタイミングに影響します。 このロックの動作はグループレベルロックを連想させる シュミレート効果があります。 効果について以下のmrプログラムの一部で検討し、説明します。

         1    for (i=0; i N; i++)

         2    {
         3         mrputvi (rec_desc, attr_desc, i);
         4         mradd (rec_desc);
         5    }
         6
         7    mraddend (rec_desc);

`MSLKCOMMITADDEND`を設定した影響は、以下に示されます。 （`MSLOCKPLAN`を使った内容と同じです。）

       行番号.    MSLKCOMMITADDEND=x         MSLKCOMMITADDEND=

            4      [ALLRECS uu ロックが
                   存在しない場合、
                   それを取得します。:
                   . -> ALLRECS uu ]          . -> ALLRECS uu
                   . -> RECORD_n u            . -> RECORD_n u
                   RECORD_n-1 u ->> .

                   (レコード追加)               (レコード追加)

                                              RECORD_n u -> .

                                              ALLRECS uu -> .

           7       ALLRECS uu -> .

`MSLKCOMMITADDEND`変数を設定した場合、 Empressは、以下に作用します。

- ループを通じて唯一、`ALLRECS`ロックだけを取得します。 （`mradd()`が最初にコールされた時）
- 同じリクエスト内で 新しい`RECORD`ロックを取得し、 古い`RECORD`ロックが存在する場合は解放します。
- `mraddend()`がコールされた時にのみ `ALLRECS`ロックを解放します。

この変数の設定により、 送られた多くのロックリクエストを 半減させるという効果があり、 そのため、 `mraddend()`がコールされる前に 多くの挿入処理が行われる場合、より効果的です。

`MSTRANSUFNGFL`変数は、 挿入操作を行う際にテーブルのフリーリストから最初に確保された レコード数を制御する整数の値が設定されます。 Empressは、テーブルにレコードを挿入する場合、 `MSTRANSUFNGFL`によって指定された数のレコードを テーブルのフリーリストから取得し、挿入のために確保します。 このアイデアは、連続的な挿入をする場合、 1回のロックのリクエスト内で`MSTRANSUFNGFL`によって指定された レコード数を取得するために効果があり、 それから、各レコードに挿入されることで個別にロックを解放します。 `MSTRANSUFNGFL`のデフォルトの値は 10 です。

テーブルへレコードを挿入を行う場合、 最初にフリーリスト中の `MSTRANSUFNGFL`によって指定された 有効なレコードを取得し、1回のリクエストで それらをロックします。 フリーリスト中に空きレコードがない場合、 `.rel`ファイルを拡張します。 挿入が完了した場合、使用されなかった取得およびロック済みの 残ったレコードは他のプロセスよって使用するために解放されます。 挿入操作の開始は、`mradd()`および`mrtadd()`ルーチンによって 知らされ、挿入操作の終了は、`mraddend()`を呼び出すことにより知らされます。 これらのルーチンは、Empressのすべてのインターフェイスの中で 透過的に呼び出されます。

環境変数`MSTRANSTABLELOCK`は、 トランザクション中に`ALLRECS`ロックを仕掛けることで トランザクションの連続性を保証するために （データベースにアクセスするプロセスの 同時性の低下を犠牲にして）有効にすることができます。 このトランザクションが コミットあるいはロールバックされた場合に のみロックは解放されます。 この変数はデフォルトでは無効になっています。 詳細はこのマニュアルのロックとトランザクションを 参照してください。

### 12.4.4 ロックのクリア

ロックは、`empadm`および`empclrlk`コマンドを使って 明示的にクリアすることができます。 これらのコマンド構文は以下になります。

       empadm database_name lockclear [-f] [empress_id ...]

       empclrlk [-4gl] [-ag] [-recov] database_name [application ... ]

`empclrlk`コマンドは、単に`empadm`コマンドへのインターフェイス ですが、4GL または AG のロックをクリアすることができます。 すべての場合において、`empclrlk`コマンドは 通常のロックをクリアすることに留意してください。 これらのコマンドについては、 このマニュアルのデータベースの管理の章で 説明されています。

### 12.4.5 シェアードメモリロックマネージャの作成

シェアードメモリロックマネージャの作成のための手順は、 このマニュアルのシェアードメモリの章に詳しく 説明されています。

シェアードメモリロックマネージャは、 Empressのファイルベースのロックマネージャと 同様な概念になります。 しかし、以下の点に注意してください。

1. シェアードメモリロックマネージャは、 1つ以上のテーブルを管理することができます。 ファイルロックマネージャは、 １つのファイルロックマネージャファイルで １つのテーブルと関連付けられています。
2. シェアードメモリロックマネージャのロック数は、 シェアードメモリに置くことが可能なロックの合計数であり、 これらのロックはロックマネージャの使用する全てのテーブルに よって共有されます。

シェアードメモリロックマネージャの使用で一番の長所は、 ファイルベースのロックマネージャより、速度が速いことです。

## 12.5 ロックの監視

ユーザーは、ロックを監視するいくつかのメカニズムによって テーブル上にどのようにロック置かれるのかをモニタすることができます。 これらのメカニズムは、内部ロックモニタと外部ロックモニタの 2つのグループに分けることができます。 内部ロックモニタは、 Empressの１つのプロセスによって実行されたロックについての 情報を提供します。 外部ロックモニタは、１つのデータベースについてのロックの累積統計情報を 提供します。

### 12.5.1 内部ロックモニタ

環境変数`MSLOCKPLAN`を設定することにより、 テーブルにどのようにロックが置かれ、削除されるかの 状態を表示します。加えて、オプションを有効にすることで タイミング情報（累積した秒数）を表示します。 この出力は、それぞれのプロセス単位で出力されるため、 データベースに置かれているすべてのプロセスの ロックを動的にモニターするために使用することはできません。 このメカニズムの大量な出力は、 ロックのリクエストの観点から 一時的なロックの配置と解放を分類します。

環境変数`MSLOCKSTATS`は、ロックについての統計情報と ロックマネージャのアクセスについての情報を出力するために 使用することができます。 この情報は、 Empressのプロセスのロックの使用のパターンを リポートすることにより、ロックのボトルネックを調べるために使用されます。 `MSLOCKPLAN` 変数はロックが置かれるごとにユーザーに リポートしますが、`MSLOCKSTATS`はプロセスが終了したときに のみリポートします。

#### 12.5.1.1 MSLOCKPLAN

環境変数`MSLOCKPLAN`を設定することで、 ロックの配置と解放についてのレポートを出力します。 以下の例は、UNIX環境での`MSLOCKPLAN`変数の設定についてを示します。

       setenv MSLOCKPLAN x           (標準的なロックの情報)

       setenv MSLOCKPLAN t           (標準的なロックの情報 + タイミング情報)

以下はテーブル`t`のアトリビュート`a`の2レコードを 単純な`SELECT`文で検索した場合の `MSLOCKPLAN`の出力になります。 この例では、データディクショナリとユーザーテーブルの両方が レコードレベルのロックです。 各ロックのリクエストは、 `LOCKS: Table #n`タイトルヘッダ出力以下の セクションに含まれています。

       * SELECT * FROM t;

       LOCKS: Table #1
           ADMIN: . -> r       (sys_dictionaryを読むための要求を示します。)
         SUCCEEDED
       LOCKS: Table #1
           ADMIN: r            (ADMIN リードロックを保持し続けます。)
           CRIT: . -> r        (インデックス名 sysdidx にリードロックを置きます。)
                               (テーブル名 t をインデックスから探します。)
         SUCCEEDED
       LOCKS: Table #1
           ADMIN: r            (ADMIN リードロックを保持し続けます。)
           CRIT: r -> .        (テーブル名 t が見つかったため、インデックスのロックを解放します。)
         SUCCEEDED
       LOCKS: Table #1
           ADMIN: r            (ADMIN リードロックを保持し続けます。)
           ALLRECS: . -> rr    (sys_dictionary のレコードを読むための要求を示します。)
           RECORD 7: . -> r    (sys_dictionary の７番めのレコードをロックします。
    				このレコードはテーブル t の情報になります。)				)
         SUCCEEDED
       LOCKS: Table #7
           ADMIN: . -> r       (テーブル t のADMIN リードロックを取得します。
                                　rel file では 0007.rel)
         SUCCEEDED
       LOCKS: Table #1
           ADMIN: r            (sys_dictionaryのADMIN リードロックを保持し続けます。)
           ALLRECS: rr -> .    (sys_dictionaryのALLRECSロックを解放します。)
           RECORD 7: r -> .    (sys_dictionaryの7番目のレコードのロックを解放します。)
         SUCCEEDED

            a                  (アトリビュートヘッダーを出力します。)

                               (このテーブルにレコードが含まれていない場合は、
    				以下の区切りの線は出力されません。)
                               ------------------------------------------
       LOCKS: Table #7
           ADMIN: r            (テーブル t のADMIN リードロックを保持し続けます。)
           ALLRECS: . -> rr    (テーブル t のレコードを読むことを示すために
    				ALLRECS rr ロックを取得します。)
           RECORD 1: . -> r    (最初のレコードにリードロックを取得します。)
         SUCCEEDED
            1                  (見つかったレコードの内容を出力します。)
       LOCKS: Table #7
           ADMIN: r            (テーブル t のADMIN リードロックを保持し続けます。)
           ALLRECS: rr         (テーブル t の ALLRECS rr ロックを保持し続けます。)
           RECORD 1: r -> .    (最初のレコードのロックを解放します。)
           RECORD 2: . -> r    (次に一致したレコードをロックします。)
         SUCCEEDED
            2                  (見つかったレコードの内容を出力します。)
       LOCKS: Table #7
           ADMIN: r            (テーブル t のADMIN リードロックを保持し続けます。)
           ALLRECS: rr -> .    (テーブル t の ALLRECS rr ロックを解放します。
    				これ以上レコードがない場合、このロックは解放されます。)
           RECORD 2: r -> .    (レコードのロックを解放します。)

                                ------------------------------------------

       LOCKS: Table #7         (テーブル t に対してこれ以上読む必要がないことを示すため、
    				テーブル t のADMIN リードロックを解放します。)
           ADMIN: r -> .
         SUCCEEDED
       LOCKS: Table #1         (テーブル sys_dictionary に対してこれ以上読む必要がないことを示すため、
    				テーブル sys_dictionary のADMIN リードロックを解放します。)
           ADMIN: r -> .
           ADMIN: r -> .
         SUCCEEDED

この出力は、 単一のプロセスによるロックの配置と解放の順番を 明確に見ることが出来ます。 すべてのプロセスからのロックの情報を得る `empadm`コマンドとは異なりますが、 １つのプロセスの情報を即座に出力します。 繰り返しますが、この出力はまたロックのリクエストを示します。 （各ロックのリクエストは、`LOCKS: Table #n`のヘッダー 以下のセクション内に分けられています。） 各セクションは、現在のテーブル上の保持されたロックを示し、 加えてカレントリクエストに含まれるロックの配置と解放を示します。 （例えば、上の例の最初において、 それぞれのリクエストは`LOCKS: Table #1`によって ヘッダー付けされていることでわかるように `sys_dictionary`(Table #1)の `ADMIN`と`CRIT`ロックを得るために リクエストは2つに分けられています。)

#### 12.5.1.2 MSLOCKSTATS

`MSLOCKSTATS`変数は、変数の値として２つの値を設定することができます。

1. この変数に値として`a`（大文字または小文字）がセットされた場合、 Empressは、次の統計情報を収集します。
   - テーブルについてのロック情報
   - ロックタイプについてのロック情報
   - ロックマネージャについてのロック情報

2. この変数に他の値がセットされた場合、 Empressは、次の統計情報を収集します。
   - テーブルについてのロック情報
   - ロックマネージャによるロック情報

すべてのケースにおいて、 (UNIXの)標準エラーに出力され、 ロックアルゴリズム内の内側および外側のループに一致する、 2つのセクションに分けられ表示されます。 最初のセクションは、「ロックへのアクセス統計情報」 (`Access statistics to locks`)というタイトルで、 テーブルとロックタイプ(リクエストした場合)の統計情報が 提供されます。これはロックアルゴリズムの内側のループと一致します。 テーブルごとに以下の情報が収集されます。 ※ここでのループとは、集まりを意味しています。

- ロックリクエストの合計
- ロックリクエストの成功数
- ロックリクエストの失敗数
- ロックリクエストのリトライ数

これらの情報は、1テーブルつき1行で要約され出力されます。 ロックタイプの統計情報付きの収集を行った場合は、 テーブルごとにロックタイプの統計情報を出力します。 この場合、テーブルに置かれたロックタイプごと、 1行に統計情報が出力されます。

注意として

1. テーブルの要約された値は、 リストされたロックタイプのそれぞれの値の合計より 少ないかあるいは等しい場合にのみロックリクエストは、 要約されることができます。

2. リトライのリクエスト数は、最終的に成功した場合のみカウントされた数です。 失敗した場合は含まれません。

3. リクエストの成功数と失敗数の合計は、リクエストの合計に等しくなります。 これはテーブル全体および各ロックタイプでも同様です。

出力の 2番目のセクションは、「ロックマネージャへのアクセス統計情報」 (`Access statistics to Lock Manager`)というタイトルで、 ロックマネージャへのアクセスの統計情報が提供されます。 これはロックアルゴリズムの外側のループと一致します。 (詳細はロックの基本的側面を参照してください。)

それぞれのロックマネージャごと１行の要約に以下の情報を 出力します。

- ロックマネージャの名前
- ロックマネージャのタイプ (`F`はファイルロックマネージャ、 `P`はシェアードメモリロックマネージャのどちらか）
- ロックリクエスト数
- ロックリクエスト成功数
- ロックリクエスト失敗数
- ロックリクエストリトライ数
  - ロックリクエストのリトライ数は、最終的に成功した場合のリトライ数になります。
  - ロックのリクエスト数は、ロックリクエストの成功数と失敗数の合計数に等しくなります。

以下は、短いSQLセッションの統計情報の出力サンプルになります。

       Access statistics to locks
       --------------------------

               Table #   Lock Item      #reqsts   #succ   #fail   #retries
               -------   ---------      -------   -----   -----   --------
                     6      -                 6       6       0          0
                         ADMIN                2       2       0          0
                         CRIT                 0       0       0          0
                         ALLRECS              2       2       0          0
                         Rec #1               2       2       0          0
                         Rec #2               2       2       0          0
                         Rec #3               2       2       0          0

                    1       -                24      24       0          0
                         ADMIN                8       8       0          0
                         CRIT                 8       8       0          0
                         ALLRECS              8       8       0          0
                         Rec #6               2       2       0          0
                         Rec #8               6       6       0          0

       Access statistics to Lock Manager
       ---------------------------------

               Lock Man. Name    Type   #reqsts   #succ   #fail   #retries
               --------------    ----   -------   -----   -----   --------
               00006.lck         F            6       6       0          0
               00001.lck         F           24      24       0          0

### 12.5.2 外部ロックモニタ

`empadm データベース名 lockinfo`コマンドは、 データベース上のどのテーブルにどのプロセスによって どのようなロックが置かれているかのすべてのロック情報を表示します。 また、現在使用されているロックマネージャの情報と これらのパラメータについてを合わせてリポートし、これは シェアードメモリロックマネージャを調べるために有用です。 このコマンドは、その時点の瞬間的なロックのスナップショットを 提供します。

`empadm データベース名 lockstats`コマンドは、 データベースのロックマネージャへのアクセス全般についての 詳細な情報を表示します。 このコマンドは、 すべてのプロセスの終了時までの ロックマネージャへの アクセスについての累積情報を提供します。 ロック統計情報の収集の終了は、 統計情報のリセットコマンド `empadm database_name lockrststats` によってコントロールすることができます。

#### 12.5.2.1 ロック情報

コマンドの詳細はこのマニュアルのデータベース管理の章に 記述されています。

`empadm`のサンプルとしてトランザクションを開始し、 `t`テーブルに1レコード追加した場合の出力例を以下に示します。

       Lock Managers

       Table name             Lock Man. Name  Type     MAXPROCS  BUCKETS  NLOCKS
       sys_attr_privs         00005.lck       F              32       11     200
       sys_attrs              00003.lck       F              32       11     200
       sys_dictionary         00001.lck       F              32       11     200
       sys_privs              00004.lck       F              32       11     200
       sys_tables             00002.lck       F              32       11     200
       t                      00006.lck       F              32       11     200

       Active Locks

       Table name              Type       Record#      Status    Empress ID
       sys_dictionary          ADMIN          ---      r         1426877923
       sys_dictionary          RECORD           6      r         1426877923
       sys_dictionary          ALLRECS        ---      rr        1426877923
       t                       ALLRECS        ---      uu        1426877923
       t                       RECORD           3      u         1426877923
       t                       ADMIN          ---      r         1426877923

          Empress ID   User name       Process ID      Host ID
          1426877923   empress               3625      192.255.255.255

出力は3つのセクションに分けられリポートされます。

1. ロックマネージャの情報
2. 現在、アクティブなロック情報
3. 現在、ロックを保持しているプロセス情報

`empadm`コマンドのオプションを指定することにより、 様々な組み合わせの出力結果を得ることができます。

#### 12.5.2.2 ロック統計情報

データベースのロック統計情報の収集を有効にするためには、 データベースの`tabzero`ファイルを編集し、 `MSDBLOCKSTATS`の行を以下のように変更します。

       MSDBLOCKSTATS=x        (値はどのような値でも構いません。)

この設定を行った以降、統計情報は蓄積されます。 情報を表示する場合は`empadm database_name lockstats`コマンド を実行し、統計情報をクリアする場合は `empadm database_name lockrststats`コマンドを実行します。 `lockstats`オプションは、 テーブルごとにロック統計情報をリスト出力します。 それぞれのテーブルの統計情報は以下の４つのセクションに 分けられリポートされます。

1. ロックマネージャ情報

   ロックマネージャに定義されているパラメータが報告されます。

2. 最大使用量情報

   同時にそのテーブルにアクセスしたプロセスの最大数と 同時にそのテーブルに保持されたロックの最大数をリポートします。 効率(efficiency)は ハッシュ機能がどのように効果的に操作されているかを示します。 (よい状況は100% で終了します。)

3. ロックハッシュバケット統計情報

   各ハッシュバケットのヒット数が集計され、 ヒット数を基に分類され、 各ヒット数ごとのハッシュバケット数とそのハッシュバケットの 番号が出力されます。 例えば、すべてのヒットが含まれるバケットは 全部で11個中の5個（バケットは2, 5, 6, 7 と 9)、 すべてのヒットの 50%, 75% と 90%を持つバケットの最少数が 出力されます。 ロックのハッシュ機能の効率化のためには ロックはむらなく有効なハッシュバケット上に分けられるように する必要があります。 一般的に、有益な統計情報を得るためには 長い期間、監視する必要があります。

4. ロックハッシュバケットのチェーンの長さ

   使用された最大チェーン長で、 同じ最大チェーン長を持つバケット数ごとで分類されています。 このセットを構成している実際のバケット番号も出力されます。 より詳細な情報は、ロックのチューニングのセクションを参照してください。

以下はユーザーテーブル"`t`"のサンプル出力です。

       Table name: t

               Lock Man. Name  Type     MAXPROCS NBUCKETS   NLOCKS
               00006.lck       F              32       11      200

               NPROCS  MAXNPROCS       CURNLKS MAXNLKS EFFICIENCY
                    1          1             0       3       100%

               # buckets       % of hits
                       3             60%
                       4             80%
                       5            100%

               # hits          # buckets       bucket #
                    0                  6         0,   1,   3,   4,   8,
                                                10
                    2                  5         2,   6,   7,   5,   9

               Max. chain length       # buckets       bucket #
                               0               6         0,   1,   3,   4,  8,
                                                        10
                               1               5         2,   6,   7,   5,  9

### 12.5.3 検索クエリのリレーショナルレベルデフォルトロック

このセクションでは 様々な状態の下での共通 DML コマンドによるロックの発生の典型的な例を示します。

1. 暗黙的ロックスキーム
   - レコード、グループ、テーブル

2. 操作
   - 挿入、更新、検索、削除

3. アトリビュートインデックス
   - インデックスがあるか、あるいはインデックス無しのアトリビュート

これらのシナリオはトランザクションを対象外として考慮されていることに 注意してください。トランザクションのロックの効果は、このドキュメントの 様々なロックの側面のセクションで述べられています。

以下の操作でテーブル`t`が作成されます。

       CREATE TABLE t (a int);

以下においては、 テーブル`t`のロックマネージャ上のすべてのロックを報告しますが、 データ辞書のためのロックは、ここでは表示しません。 また、表示はロックが置かれる順にリポートされ、 それらが置かれた理由を注釈します。 最後にこれらのサンプルおいては`MSTRANSUFNGFL=10`に設定され、 すべての挿入は初期化された空のテーブルに行われるとします。

1. レコードレベルロック、インデックス有り

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         u       フリーリストのロック
                    ALLRECS      uu
                    RECORD_n     u
                                         レコードを挿入
                                         インデックスファイルの更新

         (登録レコードが追加されるごとに以下のセクションを繰り返す)

         解放       CRIT         u
                    ALLRECS      uu
                    RECORD_n     u
         取得       CRIT         u
                    ALLRECS      uu
                    RECORD_n     u
                                         レコードを挿入
                                         インデックスファイルの更新

         (繰り返しセクションの終了)

                                         挿入レコードがないため、ロックを解放する
         解放       CRIT         u
                    ALLRECS      uu
                    RECORD_n     u
         取得       CRIT         u       .relファイルヘッダーの更新
         解放       CRIT         u
         解放       ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r
                    CRIT         r       対象となるレコードを見つけるためにインデックスファイルを読む
         解放       CRIT         r
         取得       ALLRECS      rr

         (適合するすべてのレコードで繰り返し)

         取得       RECORD_n     r
                                         レコードを読む
         解放       RECORD_n     r

         (繰り返しセクションの終了)

         解放       ALLRECS      rr
         解放       ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      uu

         (適合するすべてのレコードで繰り返し)

         取得       RECORD_n     u
         取得       CRIT         u
                                         レコードとインデックスの更新
         解放       CRIT         u
         解放       RECORD_n     u

         (繰り返しセクションの終了)

         解放       ALLRECS      uu
         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         r
                                         インデックスを検索し、対象となるレコードを見つける
         解放       CRIT         r

         (適合するすべてのレコードで繰り返し)

         取得       CRIT         u
                    ALLRECS      uu
                    RECORD_n     u
                                         インデックスの更新とレコードの削除
         解放       RECORD_n     u
                    ALLRECS      uu
                    CRIT         u

         (繰り返しセクションの終了)

         取得       CRIT         u
                                         .relファイルヘッダーの更新
         解放       CRIT         u
         解放       ADMIN        r

2. レコードレベルロック、インデックス無し

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         u       フリーリストから有効な（空き）レコードを取得する。
         解放       CRIT         u

         (挿入するすべてのレコードで以下を繰り返す)

         取得       ALLRECS      uu
                    RECORD_n     u
                                         挿入の実行
         解放       ALLRECS      uu
                    RECORD_n     u

         (繰り返しセクションの終了)

         取得       CRIT         u
                                         フリーリストの更新
         解放       CRIT         u
         解放       ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
                                         ヘッダー情報の出力
         取得       ALLRECS      rr
                    RECORD_n     r

         (すべてのレコードで繰り返し)

         解放       RECORD_n     r
         取得       RECORD_n+1   r
                                         レコード n の内容を出力

         (繰り返しセクションの終了)

         解放       RECORD_n+1   r
         解放       ALLRECS      rr
         解放       ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      uu
                    RECORD_n     u

         (すべてのレコードで繰り返し)

                                         更新の実行
         解放       RECORD_n     u
         取得       RECORD_n+1   u

         (繰り返しセクションの終了)

         解放       RECORD_n+1   u
         解放       ALLRECS      uu
         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
                    ALLRECS      uu
                    RECORD_n     u

         (すべてのレコードで繰り返し)

                                         レコードの削除の実行
         解放       RECORD_n     u
         取得       RECORD_n+1   u

         (繰り返しセクションの終了)

         解放       RECORD_n+1   u
                    ALLRECS      uu
         取得       CRIT         u
                                         .relファイルのヘッダーの更新
         解放       CRIT         u
         解放       ADMIN        r

3. グループレベルロック、インデックス有り

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         u       フリーリストとインデックスのロック
         取得       ALLRECS      uu
                    RECORD_10    u
                    RECORD_9     u
             ...
                    RECORD_1     u
                                         フリーリストから MSTRANSUFNGFL(=10 がデフォルト)分の
                                         レコードを取得
                                         レコードの登録とインデックスの更新
         解放       CRIT         u       フリーリストの解放
         解放       RECORD_1     u       登録したレコードのロックを解放

         (適合するすべてのレコードで繰り返し)
                                        一度にMSTRANSUFNGFL数分のレコードが登録された場合、
                                        Empressは戻って、テーブル内へのレコードを挿入するための
                                        先取りとして、フリーリストから
                                        他のMSTRANSUFNGFL数分のレコードセットを取得する。

         取得       CRIT         u       フリーリストとインデックスのロック
                                         レコードの挿入とインデックスの更新
         解放       RECORD_2     u
         解放       CRIT         u

         (繰り返しセクションの終了)

                                         すべての未解決のレコードを解放
         解放       RECORD_3     u
                    RECORD_4     u
             ...
                    RECORD_10    u
         解放       CRIT         u
         解放       ALLRECS      uu
         解放       ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得        ADMIN        r       テーブルがオープンされたことを示すため

         (適合するすべてのレコードで繰り返し)

         取得        CRIT         r       インデックスを読むためのロック
         解放        CRIT         r
         取得        ALLRECS      rr
         取得        RECORD_2     r       レコードの読み込み
         解放        RECORD_2     r
         解放        ALLRECS      rr

         (繰り返しセクションの終了)

         解放        ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         r       インデックスを読むためのロック
         解放       CRIT         r

         (適合するすべてのレコードで繰り返し)

         取得       ALLRECS      uu
                    RECORD_2     u
                                         レコードの更新
         取得       CRIT         u
                                         インデックスとヘッダーの更新
         解放       CRIT         u
         解放       ALLRECS      uu
                    RECORD_2     u

         (繰り返しセクションの終了)

         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         r       適合したレコードを見つけるためにインデックスを読みためのロック
         解放       CRIT         r

         (適合するすべてのレコードで繰り返し)

         取得       ALLRECS      uu
         取得       RECORD_n     u
                                         レコードの更新
         取得       CRIT         u
                                         インデックスの更新
         解放       CRIT         u

         (繰り返しセクションの終了)

         解放       ALLRECS      uu

                    RECORD_n     u
         取得       CRIT         u       .rel ファイルヘッダーの更新
         解放       CRIT         u
         解放       ADMIN        r

4. グループレベルロック、インデックス無し

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       CRIT         u       フリーリストのロック
         解放       CRIT         u
         取得       ALLRECS      uu
                    RECORD_1     u
          ......

                    RECORD_10    u
                                         フリーリスト内の MSTRANSUFNGFL分のレコードをロックし、
                                         取得する。(フリーリストに存在しない場合はフリーリストを
                                         追加する。)

      　 (すべてのレコードでの繰り返し)
                                         MSTRANSUFNGFL数以上にレコードが挿入された場合、
                                         Empressは、次の有効なレコードセットに
                                          "u"ロックの取得を試みる。
                                         レコードとして挿入された場合、これらのロックは
                                         この例のように解放される。
                                         挿入の実行
         解放       RECORD_1     u

         (繰り返しセクションの終了)

         解放       RECORD_2     u       リスト内の次のレコードのロックを解放
         取得       CRIT         u       フリーリストと.rel ファイルヘッダーの更新
         解放       CRIT         u
         解放       ALLRECS      uu
         解放       RECORD_3     u

          ......

                    RECORD_10    u
                                         未解決なレコードロックを解放
         解放       ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      r
                                         レコードの検索
         解放       ALLRECS      r
         解放       ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u
                                         レコードの更新
         解放       ALLRECS      u
         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u
                                         レコードの削除
         解放       ALLRECS      u
         取得       CRIT         u
                                         フリーリストと.rel ファイルヘッダーの更新
         解放       CRIT         u
         解放       ADMIN        r

5. テーブルレベルロック、インデックス有り

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
                    ALLRECS      u       テーブル内のすべてのレコードのロック
         取得       CRIT         u       フリーリストをロックし、そこからレコードを取得する。
         解放       CRIT         u       フリーリストの解放
         取得       CRIT         u       インデックスファイルのロック
                                         レコードの挿入とインデックスの更新
         解放       CRIT         u
         取得       CRIT         u       フリーリストと.rel ファイルヘッダーのロック
                                         フリーリストとヘッダーの更新
         解放       CRIT         u
         解放       ALLRECS      u
         解放       ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
                    ALLRECS      r       テーブル内のすべてのレコードのロック
                    CRIT         r       インデックスにリードロックを掛ける
                                         インデックスを走査し、検索を行う
         解放       CRIT         r
         解放       ALLRECS      r
         解放       ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u       テーブル内のすべてのレコードのロック
         取得       CRIT         r       適合するすべてのレコードを見つけるためのインデックス検索
         解放       CRIT         r
         取得       CRIT         u
                                         レコードとインデックスの更新
         解放       CRIT         u
         解放       ALLRECS      u
         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u       テーブル内のすべてのレコードのロック
         取得       CRIT         r       適合するすべてのレコードを見つけるためのインデックス検索
         解放       CRIT         r
         取得       CRIT         u
                                         レコードの削除とインデックスファイルの更新
         解放       CRIT         u
         取得       CRIT         u
                                         フリーリストと.rel ファイルヘッダーの更新
         解放       CRIT         u
         解放       ALLRECS      u
         解放       ADMIN        r

6. テーブルレベルロック、インデックス無し

  i) 挿入

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
                    ALLRECS      u       テーブル内のすべてのレコードのロック
                    CRIT         u       フリーリストのロック
                                         レコードの挿入
         解放       CRIT         u
         取得       CRIT         u
                                         フリーリストと.rel ファイルヘッダーの更新
         解放       CRIT         u
                    ALLRECS      u
                    ADMIN        r

  ii) 検索

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      r
                                         レコードの検索
         解放       ALLRECS      r
         解放       ADMIN        r

  iii) 更新

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u       テーブル内のすべてのレコードのロック
                                         レコードの更新
         解放       ALLRECS      u
         解放       ADMIN        r

  iv) 削除

          動作      タイプ      モード    理由
         ------     ----         ----    ------

         取得       ADMIN        r       テーブルがオープンされたことを示すため
         取得       ALLRECS      u       テーブル内のすべてのレコードのロック
         取得       CRIT         u       フリーリストのロック
                                         レコードの削除
                                         フリーリストとヘッダーカウンタの更新
         解放       CRIT         u
         解放       ALLRECS      u
         解放       ADMIN        r

グループレベルロックでは、以下についてに留意してください。 テーブルレベルロックの場合、フリーリストのロックは 操作の間、維持されますが、グループレベルロックでは、 その操作の終了時点まで維持されます。

## 12.6 ロックのチューニング

Empress では、以下の組み合わせを行うことでデータベースの パフォーマンスを改善するためのロックの調整をすることができます。

1. データベースの各テーブルに適合した暗黙的なロックのスキームの選択
2. 全体を通してのロックのパラメータの調整
3. データベースのロックマネージャのタイプおよび構成の変更
4. データベースのロックマネージャの調整

ロック機構のチューニングは、以下のパフォーマンスの改善を目的とします。

- 1プロセスのロックの取得と解放の時間を減らす。
- ロックによるプロセス間の競合の数を減らす。

### 12.6.1 暗黙的なロックスキーム

データベースのテーブルの暗黙的なロックスキームの選択は、 テーブルがサポートすることを期待する操作によってしばしば指示されます。 例えば、テーブルが参照だけのために使用されている場合、 ヌルレベルのロックで十分であるかもしれません。 しかしながら、読み込みおよび書き込みをする複数のプロセスによって アクセスされるテーブルの場合は、レコードレベルロックが 最適な選択になります。

適切な暗黙的なロックスキームを選択する場合、 ロックのリクエスト数を可能であるならば最小にすべきです。 しかしながら、このことは概して同時プロセスが存在する場合の データ整合性とは反対の方向を意味します。

ロックレベル | ロックのリクエスト数 | 同時性 | 整合性
`null` | 最小 | 最大 | 最小
`table` | 少ない | より少ない | 最大
`group` | (中ぐらい) | (中ぐらい) | 最大
`record` | 多い | より多い | 最大

これらの２つの考慮すべきことのうち、 同時性は多くのユーザーにとって最も重大な関心事です。 （そのため null レベルロックは、通常は使用されません。）

### 12.6.2 ロックパラメータの調整

ロックパラメータは、ロックをすぐに獲得することができない状況において Empressの動作を制御し、また、ロックの取得および解放においては、 ロックのリクエストと一緒にバンドリングすることにより、 より有効に作用します。 ロックに直接的に影響を与える Empressの`MSxxx`変数は、 環境変数のセクションを参照してください。 特に重要なものは、

- 物理ロックスキームに影響するパラメータ： リトライ数およびリトライ間のウェイト秒数 (ロックの基本的側面のセクションを参照してください。）

- ロックマネージャ自身を設定するパラメータ： ロックマネージャに保存できる最大ロック数および同時にアクセス可能なプロセス数

物理的なロックパラメータの調整は、以下のようないくつかの効果があります。

1. リトライ数を増やすことで最終的には、ロックが要求された場合に それを保証するための助けになりますが、対話型のアプリケーション （例えば4GLアプリケーション)場合は、そのアプリケーションのユーザーは、 ロックを取得するために端末上で待つことになります。 このようなアプリケーションでは、リトライ回数を減らし、 ロックの取得の失敗時には、単純にメッセージを出力することで、 よりユーザーへの親和性を高めます。 （対話型と非対話型に適応するパラメータは、異なっていることに 注意してください。）

2. ロック取得の試行の間のスリープ時間は、アプリケーションに合わせた 適切な時間を設定すべきです。 単一のデータベースにいくつかのプロセスでアクセスしている場合、 異なったプロセス間でロックの衝突の繰り返しを可能な限り減らすために ロックの試行のスリープ時間をそれぞれのプロセスでほんの少しずらした値を 設定することは合理的です。 繰り返し時間もまた、平均的なロックで予想される プロセスの合計時間より、あまり短すぎず、また長すぎないことに 注意が必要です。

3. ロックマネージャへの同時アクセス可能な最大プロセス数および 保持できる最大ロック数はロックマネージャのサイズに直接的に影響します。 ファイルロックマネージャの場合、すべてのアクセスでロックマネージャを 読まなければならないため、１および2ディスクブロック以上 大きくなるロックファイルはなるべく避けるべきです。 この点は、シェアードメモリでは当てはまりません。

### 12.6.3 シェアードメモリ と ファイルロックマネージャ

最も効果的な変更の１つで デフォルトのファイルロックマネージャをシェアードメモリマネージャに置き換える ことでEmpressのロックのパフォーマンスを改善することができます。 (シェアードメモリロックマネージャは、Empressのすべてのバージョンで 有効ではないことに注意してください。） シェアードロックマネージャは、ファイルロックマネージャに比べ非常に高速です。 このことはプロセスがロックを保持する全体的な時間が少なくなることにより、 ロックの競合が緩和されます。 加えて、多くのロックの取得と解放が必要なプロセスでは、 個々のプロセスのパフォーマンスは劇的に改善することができます。

しかしながら、シェアードメモリロックマネージャのセットアップにおいては、 どのような値を指定したらよいか戸惑います。

最も効果的にシェアードメモリロックをインプリメントをするために 最初に以下の質問に答えてみてください。

1. 同時に各テーブルにアクセスするプロセスの最大数はいくつか?

2. 同時に各テーブルにロック可能な最大ロック数はいくつか？

これらの質問の回答から、ロックマネージャのソートで必要とされる値を 設定することが可能となりますが、 もちろん、最も簡単な方法は極端な値を設定をすることです。

- この場合、各テーブルに同じ特徴を持つロックマネージャを分けて割り当てます。 これはおそらくシェアードメモリを多分に浪費するでしょう。

- また、すべてのテーブルのために１つのロックマネージャを割り当てる。 これはおそらくロックマネージャの競合を引き起こすでしょう。

設定として中間のコースを推奨します。

1. 自身パーティション内に`sys_dictionary`のロックを置き、 そのパテｰィションには、他のどのようなロックも置かないようにします。 この場合、`sys_dictionary`は、常にテーブルはオープンされアクセスされていること に留意してください。

2. 最も頻繁に使用されるテーブルを見分け、 個別に適切に調整したサイズを持ったロックマネージャを そのテーブルに設定します。 また、特にトランザクションを通して、 大量のロックを維持するアプリケーションでは、 同じロックマネージャを使用する数個のテーブルで結合すること が役に立つことを見つけるかもしれません。

3. 使用頻度が低いテーブルは、 適切にサイズを調整した包括的なロックマネージャに一緒に ひとまとめにすることができます。

4. 滅多に使用されないテーブルは、ファイルロックマネージャとして残すことができます。

これらのステップを自動的に実行するスクリプトを作成することもまた推奨します。 これは、シェアードメモリが各システムの再起動の後に再度、設定する必要があるためです。

### 12.6.4 ロックマネージャのチューニング

ロックマネージャのチューニングはロックモニタリングのコマンドの出力を 使用することから始めます。 ロックメカニズムはロックマネージャ内のロックの配置と解放の働きであることを 思い出してください。（ファイルまたはシェアードメモリパーティション上での） この動作を行うために、まずロックの配置を決める必要があり、 この目的のためにハッシュスキームを使用します。 それぞれのロックマネージャは、ロックを配置するために いくつかのバケットを使用します。 バケットによってチェーンから得られるロックですが、 （１つのバケットは1つ以上ロックを持つことができます。） ロックマネージャが、（平均的に）短いチェーンから 探すことが最も効果的であることを明らかにする 必要があります。例えばすべてのロックのための バケットが`n`個あるうちの １つだけを使用しているロックマネージャがある場合、 効果は最小です。

加えて、ハッシュバケットを走査した ロックリクエストのより詳細な分布情報と シンプルなロックマネージャの効果インデックスが提供されます。 この数値は0%から100%までを表示し、 ロックのハシュ機能が、アプリケーションによって効果的に 使用されているかどうかを判断する簡単な方法です。 最適な効果は 100% です。

上記において、ロックリクエストが すべてのハッシュバケットを通して平均的に分布している状況が 理想的であることに留意してください。 効果のための計算方法は、 適切なロックリクエストの分布の変動値を決定する 調整パラメータ(`MSTHRESHCHAINLEN`)を含んでいます。 ロックリクエストがこのレベルを超えた場合、非効率として カウントされます。

`MSTHRESHCHAINLEN`変数のデフォルトは、1.5 で、 ロックリクエストの平均数より、50%以上含まれているバケットに 落ち込んだときに効率的ではないとするロックのリクエストの カウント数と一致します。 この変数はアプリケーションの時間を調査し、 最適な値を見つけ設定すべきですが、 この値自体はロックメカニズムの動作に影響せず、 むしろ、ロックの効果は計算よって影響されます。

このロックの効果の計算方法は以下のとおりです。

      効果 = (1 - a/b) * 100%

`a` | 時間`t`での チェーン長のしきい値を超えるハッシュバケットチェーン長が発生した ロック配置操作の数。
`b` | 時間`t`でのロック配置操作の合計数

チェーン長のしきい値は、以下によって決められます。

       チェーン長のしきい値 = MSTHRESHCHAINLEN * 理想的なチェーン長

       理想的なチェーン長 = (# 時間 t のロックの合計) / (# 有効なハッシュバケット)

ロックの効果的なインデックスと分布の統計を必要とするより詳細なロック情報は、 ロックが適正に振舞っているかどうかを判断するために調べることができます。 `lockstats`出力に基づき、ロックのパラメータを変更することを 決めた場合、ロックのハッシュ機能の動作の変更を調整できる これらの２つのパラメータが有効です。 これら２つの変数は、ロックマネージャが保持可能な ロックの最大数とそれを使用するための ハッシュバケット数を制御します。

ロックマネージャのその他のチューニング変数は、以下になります。

ファイルロックマネージャ | シェアードメモリ
`MSFILELOCKNBUCKETS MSFILELOCKNLOCKS` | `MSPARTLOCKNBUCKETS MSPARTLOCKNLOCKS`

実際は、`MSxxxNLOCKS`変数のロック数は データベースが利用される用途によって決める必要な場合があり、 そのため、この変数がチューニングのための変数ではない場合もあります。 その変数が調整された場合、常にその数で作成されます。 しかしながら、`MSFILELOCKNBUCKETS`を非常に大きな値を設定し、 作成した場合、すべてのブロックをロックファイルから読み込まなければならないために ファイル I/O のオーバーヘッドが大きくなることに注意が必要になります。 もちろん、この問題は`MSPARTLOCKNBUCKETS`変数（シェアードメモリ設定の変数）では 起こりません。

ハッシュバケットの数を決める`MSxxxNBUCKETS`は、チューニングパラメータ変数ですが、 Empress社では、コンサルテーションなしにこの値を調整することを 推奨しません。仮に調整が必要である場合、以下のガイドラインを留意してください。

- `MSxxxNLOCKS`の平方根とおおよそ等しい値を設定すべきです。
- 素数を設定すべきです。

ファイルロックマネージャの場合、`MSFILELOCKNBUCKETS`および `MSFILELOCKNLOCKS`の設定は、 テーブルを作成する前に必要な値を 設定しなくてはなりません。 テーブルが既に作成されている場合に設定する場合は、 テーブルを再作成するか、ロックファイルを削除する必要があります。 ロックファイルの削除は、管理ユーティリティempadm コマンドの "lockremove"オプションで ロックファイルを削除します。 削除した場合は、要求されたパラメータの値で自動的にロックファイル（ロックマネージャ）が 再作成されます。