古典的大型計算機のファイルシステム

 1990年ごろまで、本格的な計算機システムと言えば メインフレーム(汎用計算機)と呼ばれる古典的な大型計算機に限られていました。 この計算機のファイルシステムを扱うには unix・MS-DOS・MacOS・Windowsといった最近のシステムとは 随分違った感覚が必要です。

 今どき、メインフレームが残っているところは限られるでしょう。 しかし、メインフレーム用のデータファイルは 意外と残っている可能性があります。この考えに基づき 「unixでメインフレームの磁気テープを使うためのユーティリティ」 を公開したところ、実際にユーティリティを取得する (説明文を読むだけではない)アクセスが、 この文書の初稿を書くまでの約400日間に 38件(うち21件はロボットと思われる)ありました。 それなりの需要はあるようです。

 ところで、メインフレーム用のデータファイルを扱うには、当然ながら メインフレームのファイルシステムを理解している必要があります。 ところが、上述のページで提供しているアーカイブの中の説明文書は、 ファイルシステムをそこそこ理解している読者を対象に書いているにもかかわらず、 提供ページの説明文ではそのことに気付かずに、 中の文書が「1/2インチテープの利用方法一般について 知りたいという方にも役立つかもしれません。」と 安易に書いてしまっていました。

 そこで、遅ればせながら、メインフレームのファイルシステムについて 簡単に説明する文章を作ってみました。 なお、筆者はFACOMとHITAC(共にIBM互換)についてしか 深い利用経験が無いので、基本的にこれらの機種についての説明になります。 ACOSなど非互換系のメインフレームについては、 部分的にしか当てはまらないということに留意してください。

ファイルの構造を常に意識する必要がある

 unix・MS-DOS・Windowsのファイルシステムでは、 各ファイルは1個の「バイトストリーム」から構成されています。 (WindowsNTでは複数のバイトストリームの組み合わせというのもあるらしい)。 つまり、システムのレベルでは、ファイルは「バイト」データが 順番に並んでいるだけで、それ以上の構造がありません。 データを利用する際の都合で構造を持たせる必要がある場合には、 アプリケーション(プログラム)が利用法に応じて設定するのです。 こうしておけば、今までに無い新しい考え方のファイル構造が 必要になった場合にでも、それに対応するアプリケーションだけを 作れば良く、システムは何も変えなくて済みます。 つまり、この方式は拡張性が高く、柔軟なのです。

 MacOSのファイルシステムにはo 「データフォーク」「リソースフォーク」 という構造があります。そして「リソースフォーク」には システムのレベルで制御する構造があり、その一部は システムがどのように利用するか決まっています。 しかし、「データフォーク」は全くの「バイトストリーム」です。 つまり、MacOSは構造のある部分と構造の無い「バイトストリーム」を 併用することによって、システムが高度な操作を行えるようにしつつ、 拡張性も確保しようとしているわけです。

 それに対して、メインフレームのファイルは 「バイトストリーム」ではありません。 「システムが管理する一定の構造」を必ず有しています。 IBM互換系メインフレームでは ファイル(file)とデータセット(dataset)を区別します。 即ち、外部記憶媒体に保存されているデータの集合体の実体のことは 「データセット」と呼び、それとアプリケーションとの間を媒介する システムの中の論理的な存在を「ファイル」と呼びます。 しかし、メインフレーム以外の計算機では、 むしろ「実体」のことを「ファイル」と呼ぶのが普通なので、 この文章ではメインフレーム以外での語法に従います。

 現実的には、ファイルを格納する媒体には、 ハードウェア的な都合による構造があるのが普通です。例えば、 ディスク媒体には「セクタ(sector)」というアクセス単位があります。 しかし、unix・MS-DOS・MacOS・Windowsなどのファイルシステムは、 セクタ単位がアプリケーションから見えないように隠蔽しています。 例えば、実際にはセクタ全体を一旦読み出し、その一部分を書き換えて 再度そのセクタ全体を書出すという処理をしている場合でも、 アプリケーションからは、書き換えた部分のみを読み書きして 他の部分は全く触れていないように見えるわけです。

 それに対して、メインフレームのファイル構造は、 このようなハードウェアの都合による構造と密接に関連しており、 利用者はこの構造を理解せねばならないのです。

磁気テープのイメージから理解しよう

 メインフレームのファイルシステムは、 磁気テープ上のファイルを扱う場合に 最も自然に理解できるような設計になっています。 一方のunix・MS-DOS・MacOS・Windowsなどでは、 ディスク媒体にファイルを作ることを前提にしています。 まず、この違いに注意しながら、 磁気テープのファイルについて考えてみましょう。

 ディスク媒体は、実際の記憶領域が短く閉じる円の上に並んでいるうえ、 媒体全体を一斉に回転させて使うという構造上の理由で、 「セクタ」の長さをあまり自由に変えることはできません。 通常は、各々の媒体の中で「セクタ」の長さを一定とします。

 ところが、テープ媒体では、構造的な制約は原理的にはありません。 テープ媒体では「セクタ」ではなく「ブロック(block)」と呼びますが、 1本のテープの中で「ブロック」の長さが一定でなくても 読み書きの構造上の都合としては何の問題もありません。 最近のテープ媒体は、unix等のシステムによる構造隠蔽を前提に、 ブロック長を一定の長さに規格化してあるものが多いのですが、 伝統的な1/2inchテープでは、 「ブロック」の長さは(上限はあるものの)不定です。

 そして、最も伝統的な方式では 「ブロック」と「レコード(record)」が一致します。 「レコード」を正確に定義しようとすると少々厄介ですが、 とりあえずは、テキストファイルでは「行」のことであり、 バイナリファイルでは「1個の入出力命令で扱うデータ単位」だと 理解しておいてください。

レコードのブロック化

 最も伝統的な方式では、アプリケーションで1個のバイナリ入出力命令か 1行分のテキスト入出力命令を実行する毎に、 磁気テープ装置が駆動して1ブロック分のデータを読み書きします。 読み書きに際しては、テープ媒体が所定の速度で動いている必要があります。 そこで、その所定の速度まで加速し、 読み書きの後はブレーキをかけて停止するために、 ブロックとブロックの間に何も記録されない間隙が必要になります。 この間隙のことをIBG(Inter-Block Gap)と呼びます。

 IBGの存在はテープ媒体に無駄な部分を作ることになるうえ、 テープの加速やブレーキの時間だけファイルアクセスの実時間が 余計にかかります。そこで、計算機が発達してメモリ搭載量が増えると共に、 複数のレコードを1個のブロックにまとめ、ブロック1個分の情報を 収容できるメモリ(バッファメモリ)を確保しておく、 「ブロック化」という方法が考え出されました。 即ち、読む時はブロック1個をまとめてバッファメモリに読み込んで、 アプリケーションの入出力命令は このバッファメモリからレコード1個ずつ読み出し、 書く時はバッファメモリにレコード1個ずつ書き溜めておいて ブロック1個分溜まってからまとめて書出すわけです。

 ブロックのことを物理レコード(physical record)、 それに対してアプリケーションで認識するレコードのことを 論理レコード(logical record)と呼ぶことがあります。 ブロックは実際に媒体に物理的に書込まれる情報単位であり、 論理レコードはそれをメモリ上で論理的に分離したものだという考え方です。

固定長・不定長・可変長

 テープ上には長さの異なるブロックを置くことができますし、 読み込んだブロックの長さをアプリケーション側で知ることも原理的には可能です。 しかし、一般には論理レコードの長さをいろいろ変化させるのは プログラミング技法として高度になりますし、 プログラミング言語等の環境によっては 論理レコードの長さが動的に変わる状況に適切に対応できない場合もあります。 そこで、1つのファイルの中では論理レコードの長さを一定とする方式が よく用いられることになりました。この方式で扱われるファイルは、 「レコード形式」が「固定長」であると呼びます。

 固定長以外のレコード形式で、最も原始的なものは、 論理レコードの長さを、実際に記憶媒体に存在する データの長さで識別する「不定長」です。 つまり、テープ媒体の場合には、テープ上のブロックの長さが 論理レコードの長さということになります。

 ということは、不定長のファイルはブロック化できないことになります。 固定長であれば決められた長さにブロックを切断して 論理レコードに分けることができますが、 不定長だと何処で切れば良いかわかりません。 unix等の発想で「アプリケーションが約束事に従って切る」 というのはダメです。メインフレームは基本的に「論理レコードの一部だけを アプリケーションに読み込ませる」ということは許していません。 それは、メインフレームの発想では、 システムの領分をアプリケーションが犯すことになります。

 そこで、長さが一定でない論理レコードの各々に 「記述語」と呼ばれる情報を付加し、 それを読めばレコード長がわかるようにする、 「可変長」と呼ばれるレコード形式が考え出されました。 実際には「記述語」の長さは4バイトに規格化されています。 論理レコード長は「記述語」を含めて数えるので、 アプリケーションで入出力の対象になっている 「1レコード分」のデータの長さよりも4バイト長くなります。 また、ブロック全体にも「記述語」が付加されるので、 ブロックの長さは論理レコード長の合計より4バイト大きくなります。

ラベルの必要性

 さて、システムがファイルを正しく読み込むためには、 レコード形式・論理レコード長・ブロック長 (可変長や不定長では、レコード長やブロック長の上限値) を正しく知っている必要があります。 固定長の論理レコード長を誤ると正しくレコードに区切れませんし、 レコード形式を誤った場合もレコードを正しく取り出せません。 ブロック長を短く誤れば、ブロックを読み込むのに必要な バッファメモリが適切に用意されず、エラーが起ります。

 ディスク媒体などの場合には、媒体の特定部分にディレクトリを準備しておいて レコード形式などの情報を集中的に管理することができます。 この仕組を利用すれば、ファイルに名前をつけて名前で識別することも 可能になり、ファイル管理が楽になります。 ファイルの作成日付などの情報も併せて管理すれば便利でしょう。

 しかし、テープ媒体では、そのような集中管理ができません。 そこで、ファイルの前後に「ラベル(label)」を付加して そのような情報を管理するということが考えられました。

 伝統的な1/2inchテープでは、「テープマーク(Tape Mark)」と呼ばれる 特殊な記録でファイルを区切ります。 「ラベル付きテープ」では、各ファイルの前後に テープマークで区切られた「ラベル」を置きます。 つまり、ラベルというものを知らないシステムでラベル付きテープを読むと、 ラベルも1つの独立したファイルと認識してしまい、 実際の3倍の数のファイルがあるように見えることになります。

 ラベルは80バイトの固定長で2レコードからなるというのが標準です。 80バイトというのは、メインフレームの伝統的な標準で、 紙カードは80バイト=80桁ですし、 FORTRANも1行80桁という前提で文法が決められています。

ディスク媒体などでのブロックの扱い

 最初に述べたように、ディスク媒体には「セクタ」という 記憶媒体の物理構造に依存するアクセス単位があります。 テープ系でない、自由な順序でアクセスできる記憶媒体 (かつては「磁気ドラム」なんていうものがありました)には、 必ずこのようなアクセス単位があります。

 このアクセス単位はハードウェアの都合で前もって決まっていますから、 これを「ブロック」として扱うと、 アプリケーションで必要とする論理レコード長に整合しないのが普通です。 そこで、媒体の中に「ここにはどんな長さのブロックがある」という 情報を記録することによって、ブロックを論理的に存在させます。 この場合に、セクタなどのアクセス単位を 複数個にわたって跨るブロックというものは存在できません。 それどころか、ブロックがどんなに短くても 1セクタの中には1ブロックしか納めないという流儀もあるのですが、 流石にこの流儀は、フロッピーディスクなどで 「どんなシステムでも確実に読める」ことを目指して ファイル形式を選択する場合にしか使われません。

 一般には、セクタ等の中に入るだけのブロックを入れていくのが普通です。 そうすると、例えばブロック長がセクタ等の長さの半分よりも少し長い場合、 半分近くが使われないという非常に無駄の多い状況になります。 1/3よりも少し長いとか1/4よりも少し長いとかいう場合にも、 かなりの無駄が出ます。つまり、納める媒体のセクタ等の長さに応じて、 ディスク領域の利用効率が良くなるようなブロック長を 選択せねばならないということになるわけです。

スパン形式

 このように、特にディスク媒体などにおいて、 ハードウェア的な都合でブロック長を選ばねばならないということになると、 そのブロック長とプログラミング上好都合な論理レコード長とが 整合しないという事態が生じる可能性が高くなります。

 そこで、論理レコードが複数のブロックに跨がることができる というスパン(span)またはスパンド(spanned)形式 と呼ばれるレコード形式が考え出されました。 英語ではspanとspannedは文法的位置付けに応じて 使い分ければ良いのですが、日本語ではそういうわけには行かないので、 どちらを用いるかが若干混乱しています。

 スパン形式は可変長形式の応用であり、 正確には「可変長スパン形式」と呼ばれます。 具体的には、論理レコードをブロックに納まる長さに分割した 「セグメント(segment)」を作り、各々に「記述語」を付加して ブロックに納めて行くというものです。

 スパン形式にも「ブロック化形式」と「非ブロック化形式」があります。 これは、ブロックに複数のセグメントが入ることを許すかどうかという違いです。 同じレコードの同じブロックに入る部分をわざわざ複数のセグメントに 切ったりはしませんから、これは要するに、 ブロックが複数のレコードに跨がることができるかどうかということです。 即ち、「ブロック化スパン形式」はレコードを順に全部並べて、 元のレコードの区切りに全くお構い無しに頭からブロック長毎に切って 納めて行きます。それに対して、「非ブロック化スパン形式」で ブロック長毎に切って行く対象はあくまで各々のレコードであり、 余りが出たらそれは短いブロックにして、 次のレコードは新しいブロックに収めるわけです。

 FORTRANのバイナリファイルは、 COBOLなどと違って「レコード長」を明確に意識する文法になっていないため、 スパン形式で扱うのが標準になっていました。 実際には固定長ファイルを使ったバイナリ入出力というのがありましたが、 これは古いシステムとの互換のためと思われます。 FORTRANのライブラリが独自の方式で 「スパン」に相当する作業を行ってしまうため、 FORTRAN以外の言語では簡単に扱えないという厄介な代物でした。 また、磁気テープなどで提供される「汎用の固定長バイナリファイル」を FORTRANで簡単に読み込むことができず、 「テキストファイル扱いで読み込み、通常なら文字列を数字として解釈して 数値データに変換するところを、バイナリ表現が同じ数値データに“変換”する」 (メモリ上に格納されている情報の実体が同一で、 そのデータとしての意味が変わるという、妙な“変換”) という変則技を使わねばならない副作用も起こしました。

テキストファイルの扱い

 さて、このように「論理レコード」という構造が明確に意識されている ファイルシステムでは、テキストファイルの「行」と 論理レコードとを一致させるのが通例です。 つまり、メインフレームのテキストファイルには「改行文字」という概念が無く、 その代わりに「論理レコードの区切り」という壁のような存在があるのです。

 ということは、メインフレームのテキストファイルを unix等のバイトストリーム系のファイルシステムへ転送する場合は、 論理レコード毎に改行文字を入れるという作業が必要になります。

 また、可変長ファイルなら単純に改行文字を入れれば良いのですが、 ラベルの説明のところでも触れたように、 伝統的に論理レコード長80バイトの固定長ファイルに テキストファイルを保存するのが標準的です。 固定長ファイルにテキストを収録する場合、 行末には「残った桁数」だけの空白が入ることになり、 行末空白の数には意味がありません。 従って、unix等のファイルシステムへ転送する場合は、 行末空白を適宜除去するのが適切と考えられる場合が多いのですが、 その除去の仕方に任意性があることになります。

 逆にバイトストリームのテキストファイルを メインフレームに転送する場合、 論理レコード長を越える行(=改行文字から次の改行文字までの区間)が 出現した場合にどう扱うかに任意性が発生します。

 テキストファイルを扱う場合には、このような少々厄介な問題が ついて回るということを意識しておく必要があります。 メインフレーム用のフロッピーディスクを読み書きする MS-DOS用のユーティリティなどでは、この行末空白の扱いを 「パック/アンパック」と呼んでいる場合があります。 unix標準コマンドの「dd」では、「conv=block」「conv=unblock」という オプションで、この行末空白を扱います。

 なお、バイナリファイルについてはファイルの内容にもよるので 一概には言えませんが、一般には単純に論理レコードをつなげば良い ような形に作ることが多いようです。

ファイル編成

 以上では、個々のレコードの形式に注目して考えてきましたが、 メインフレームのシステムが認識するファイル構造は、 レコードにアクセスする順序の制御にまで及んでいます。

 unix等のファイルシステムでは、先頭から順に読み書きする 「順アクセス(sequential access)」が基本ではありますが、 シーク操作によって前に戻ったり後の方へ飛んだりして、 アクセスする順番を変える 「ランダムアクセス(乱アクセス:random access)」を行うことも アプリケーションで自由に行うことができ、 そのためにファイルに特別の細工をする必要はありません。

 ところが、メインフレームでは、標準的な「順編成」ファイルでは 順アクセスしかできず(「1つ戻る」と「巻戻す」は可能)、 ランダムアクセスを行うには、対象のファイルを最初に作る段階で、 「直接編成(相対編成)」と呼ばれる構造にしておく必要があります。

 また、アプリケーションによっては、 レコードにキー(鍵となるデータ)をつけて このキーでレコードを探し出すという操作を行うことがあります。 unix等では、この作業はアプリケーションがファイルの中に構造を作ることで 実現するものであり、システムの預り知らない話です。 しかし、メインフレームでは「索引編成」という キー操作用のファイル構造が準備されています。

 更に、1つのファイルの中に多数の順編成ファイルが存在する ように見える「区分編成」と呼ばれる構造も準備されています。 これは、メインフレームにはunix等のような階層ディレクトリが無く、 またファイル容量の確保単位(unix等で 「クラスタ(cluster)」と呼ばれている単位に相当するもの)が大きいため、 細かいファイルを「ひとまとめ」にすることが管理上有用だからです。

 このように、メインフレームでは、システムのレベルで 多種多様なファイル構造を準備し、システムがファイルアクセス方法まで サービスするという発想でファイルシステムが設計されているのです。



2000年11月21日初稿/2004年5月6日最終改訂/2014年1月23日ホスト移転

戸田孝の雑学資料室へ戻る
Copyright © 2000 by TODA, Takashi