こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといった他の言語をバリバリ書いてきた方にとって、IBMメインフレームの世界、そして「PL/I(ピーエルアイ)」という言語は、どこか要塞のような、近寄りがたい雰囲気をまとって見えるかもしれませんよね。
「なんだか古い言葉みたいだし、ルールも厳しそう……」
そんな風に身構えてしまうお気持ち、とてもよく分かります。でも、大丈夫ですよ。一つひとつの仕様が生まれた「理由」を紐解いていけば、PL/Iは非常に合理的で、かつての開発者たちの工夫が詰まった愛すべき言語なんです。
今回は、そんなPL/Iの数ある特徴の中でも、基幹システムのパフォーマンスを語る上で避けて通れない「ENVIRONMENT属性のRECSIZE」と「可変長レコード(V/VB形式)の裏側の仕組み」について、一緒にじっくり見ていきましょう。
—
1. 他言語出身者が驚く、PL/Iの「予約語がない」という懐の深さ
まず最初に、PL/Iのユニークなルールを一つご紹介させてください。
JavaやC言語、COBOLには「予約語(Keyword)」というものがありますよね。例えば、`if` や `return`、`data` といった言葉は、システムがあらかじめ意味を予約しているため、変数名として使うことはできません。
ところが、PL/Iには原則として「予約語」という概念がありません。
どういうことかと言うと、プログラムの中で `IF` という名前の変数を作ることすらできてしまうのです(コンパイラは前後の文脈から「あ、これは変数だな」「ここは命令だな」と驚異的な洞察力で判断してくれます)。
……とはいえ、後からコードを読む人間のメンタルヘルスを考えると、そんなトリッキーな真似は絶対におすすめしませんが!笑
この「プログラマの自由度を最大限に尊重する」という設計思想は、これからお話しするデータ管理の領域でも色濃く反映されています。
—
2. 可変長レコード(V/VB)と「見えないおまけ」RDWの正体
基幹システムのバッチ処理では、顧客ごとの取引履歴など、レコードの長さが1件ごとにバラバラなデータを扱うことがよくあります。この「長さが可変のデータ形式」を、メインフレームの世界では V形式(Variable-length) や VB形式(Variable-blocked) と呼びます。
ここで、JavaやCOBOLしか触ったことがない方が必ずハマる、最初の「おや?」というポイントがあります。
「あれ? 宣言したレコード長より、実際のデータサイズが4バイト大きいぞ?」
この「謎の4バイト」の正体が RDW(Record Descriptor Word:レコード記述子ワード) です。
図解:レコードの構造イメージ
ファイルに書き出された可変長レコードの物理的な姿は、こんな風になっています。
+——————-+—————————————+
| RDW (4バイト) | 実際のデータ (Nバイト) |
| [LL][LL][xx][xx] | (PL/Iで宣言した変数など) |
+——————-+—————————————+
↑
この2バイトの整数値(LL)が「このレコード全体の長さ」を主張しています。
先頭の4バイトのうち、最初の2バイト(LL)が「このレコード(RDW自身を含む)の全長」を表すバイナリ数値です。残り2バイトは予備領域(通常はゼロ)となっています。
つまり、OSやディスクから見ると、可変長レコードとは「自分の長さが書かれた名札(RDW)を先頭につけた荷物」なのです。
—
3. RECSIZEとPL/Iランタイムの内部ポインタ操作
さて、ここからが本題です。PL/Iでこの可変長ファイルを読み書きするとき、私たちは `ENVIRONMENT(RECSIZE(…))` という属性をファイル定義(DECLARE文)に指定します。
「ファイルを読むだけなのに、なんでわざわざ最大サイズを教えなきゃいけないの?」
そう思ったあなたは鋭いですね。
実は、PL/Iのランタイム(実行環境)がファイルを読み込むとき、裏側では次のようなドラマが繰り広げられています。
1. OSへのバッファ要求: ランタイムは、指定された `RECSIZE`(最大長)に基づいてメモリ上にバッファを確保します。
2. RDWの自動剥離(はくり): 入出力命令(`READ`など)が実行されると、ランタイムはOSから渡された物理レコードの先頭から「4バイトのRDW」をこっそり読み取ります。
3. ポインタの調整: ランタイムは、RDWに書かれている長さを確認した上で、純粋なデータ部分の先頭を指す内部ポインタを調整し、アプリケーション(私たちの書いたコード)にデータを渡します。
つまり、私たちがPL/Iのプログラム内で扱う変数(ストラクチャーなど)には、原則としてこのRDWは含まれません。ランタイムが黒衣(くろご)のように、RDWをキレイに取り除いて渡してくれているからこそ、私たちはデータの構造だけに集中できるというわけです。
—
4. 実践!PL/Iでの可変長ファイル定義とコード例
百聞は一見に如かず。実際にV形式のファイルを扱うPL/Iのコード例を見てみましょう。
実務のマイグレーションや保守でそのまま参考にしていただけるよう、丁寧なコメントを添えています。
/ —————————————————- /
/ 可変長レコード(V形式)ファイルを処理するサンプルプログラム /
/ —————————————————- /
V_FILE_SAMPLE: PROC OPTIONS(MAIN);
/ 1. ファイルの論理的な性質と最大レコード長を定義する /
/ RECSIZEには「データ最大長 + RDWの4バイト」を含めた値を指定します /
DECLARE INFILE FILE RECORD
ENV(FBKS V RECSIZE(104) BLKSIZE(1040));
/ 2. 可変長データの内部構造(ストラクチャー)の宣言 /
/ PL/Iでは、可変長項目の先頭に「2バイトの長さフィールド」を置くのがお約束です /
DECLARE 1 CUST_RECORD,
3 CUST_LEN FIXED BINARY(15), / レコード長(2バイト) /
3 CUST_DATA,
5 CUST_ID CHAR(5), / 顧客ID /
5 CUST_NAME CHAR(505) CHAR; / 顧客名(可変部分の最大) /
DECLARE EOF_FLAG CHAR(1) INIT(‘0’);
/ ファイルのオープン(入力モード) /
OPEN FILE(INFILE) INPUT;
/ ファイル終了(EOF)を検知するための条件ハンドラ /
ON ENDFILE(INFILE) EOF_FLAG = ‘1’;
/ 3. レコードの読み込みループ /
DO WHILE (EOF_FLAG = ‘0’);
/ READ文によって、ランタイムがRDWを処理し、CUST_RECORDにデータを展開します /
READ FILE(INFILE) INTO(CUST_RECORD);
IF EOF_FLAG = ‘1’ THEN LEAVE;
/ 4. データの処理 /
/ CUST_LENには、ランタイム(またはJCL)が解釈した実データ長が入っています /
PUT SKIP EDIT (‘顧客ID: ‘, CUST_ID, ‘ / 実データ長: ‘, CUST_LEN)
(A, A, A, F(5));
END;
/ ファイルのクローズ /
CLOSE FILE(INFILE);
END V_FILE_SAMPLE;
ここがポイント!
コード中の `CUST_LEN FIXED BINARY(15)` に注目してください。
PL/Iで可変長(V形式)のレコードを `INTO` で受け取る場合、構造体の先頭に「長さを格納する2バイトの整数領域」を用意しておく必要があります。ランタイムは、先ほどのRDWから読み取ったデータの長さを、この先頭のフィールドに自動的にセットしてくれます。
「あ、裏側でちゃんと連携して動いてるんだな」とイメージできると、エラーが起きた時も怖くありませんよね。
—
5. 可変長レコードの「オーバーヘッド」と実務上の注意点
最後に、パフォーマンス(オーバーヘッド)の観点について少しだけ触れておきます。
可変長レコードや `RECSIZE` を扱う際、システムには少なからず次のような負荷(オーバーヘッド)がかかります。
- CPUの計算コスト: 固定長(F形式)であれば「何バイト目から何バイト」と機械的に計算できるところを、可変長では毎回RDWの長さを参照・計算してポインタを動かすため、わずかですがCPUサイクルを消費します。
- I/Oの断片化: レコードの長さがバラバラであるため、ブロック(VB形式のブロック化)の効率が悪いと、パディング(隙間)が生じたり、物理的な入出力回数が増えたりします。
「じゃあ、全部固定長(F形式)にした方が速いんじゃないの?」と思われるかもしれませんが、現代のメインフレームのハードウェアやコンパイラの最適化技術は非常に優秀です。
ディスク容量の節約効果や、データ構造の柔軟性を考慮すると、可変長レコードを採用するメリットは今なお絶大です。
大切なのは、「ランタイムが裏で何をやっているか(RDWの存在とポインタの移動)」をしっかりと頭に入れておくこと。これさえ分かっていれば、ストレージ容量の計算ミスや、思わぬデータ化け(オフセットズレ)といったトラブルを華麗に回避できるようになります。
—
レガシーな世界は、一見すると呪文のように難解なルールが多いですが、紐解いていけばどれも「当時のハードウェアの制約の中で、いかに効率よく正確にデータを処理するか」という先人たちの知恵の結晶です。
「怖くないですよ、一つずつ紐解けば簡単です」。
この言葉を胸に、ぜひ自信を持ってメインフレームのプログラミングを楽しんでくださいね!
