日本-日本語
日本HPホーム 製品 & サービス OpenVMS製品情報
≫  お問い合わせ


OpenVMS マニュアル


 

OpenVMS
ドキュメント・ライブラリ

タイトルページ
目次
まえがき
リファレンス・セクション
    ≫ コマンド一覧
    ≫ レキシカル関数
付録 A:廃止されたコマンド
付録 B:DCL整数表現の範囲を超える数値の処理
索引
PDF    Vol.1   Vol.2
OpenVMS ホーム

HP OpenVMS
DCL ディクショナリ


目次 索引

付録 B
DCL の整数表現の範囲を超える数値の処理



OpenVMS Version 8.4 で,最大 1.98 TB のサイズのストレージ・デバイスのサポートが導入されています。 1 TB を超えるデバイスを使用するユーザあるいはアプリケーションがこれまでと同様に DCL プロシージャを適切に機能させるためには,いくつか変更が必要になります。 1 TB を超えるサイズのストレージ・デバイスを使用する計画がない場合は,ディスクの値の読み取りや変更に関連する DCL コードの変更は必要ありません。

ここでは,大規模ディスク・サポートに関する問題を解決するための方法について説明していますが,使用される方法は大規模ディスク・サポート固有のものではありません。

B.2 概要

ここで示すのは, DCL シンボル整数の上限を超える整数値の検索や計算を扱ういくつかの DCL の例です。ここでは,DCL の $GETDVI レキシカル関数からの戻り値の処理に内容を限定して説明しています。これらの例は,特定のニーズに対するガイドラインとして使用できます。ここに示す例で,すべての個々の要求を満たすわけではありません。ディスク・ストレージのサイズと空きストレージの計測処理について例示していますが,ここで使用する方法はより一般的に適用できます。

例で示すプロシージャは,方法を説明するためのものです。個々の操作は,より複雑な単一文の DCL コマンドで実行した方が効率的な場合もありますが,ここでは実行時の効率よりも説明の分かり易さを重視しています。

B.2.1 問題の概要

OpenVMS システムの構成および管理のためのプロシージャでは,ほとんどすべてのシステム・リソース値を符号付き 32 ビットロングワード整数として更新処理あるいは監視することができます。長い期間を経て,リソースの最大値はサイン付きロングワードの制限を超えています。たとえば,OpenVMS Alpha および Integrity システム上のプロセスで利用可能な仮想メモリ・ページ数は,最大値には 64 ビット整数のストレージを必要とします。しかしながら DCL コマンド言語は,32 ビットの符号付きロングワードで値の保管や計算を行います。

『OpenVMS ユーザーズ・マニュアル』の第 12 章「シンボル,コマンド,式の定義」で次のように説明しています。

"12.7.2 数値の内部ストレージ

数値は,内部的には符号付きの 4 バイト整数,すなわちロングワードで保管されます。正の数値は 0 〜 2147483647 の値に,負の数値は 4294967296 から数値の絶対値を引いた値になります。たとえば値 -15237 は 4294952059 として保管されます。負の数値は,ASCII や 10 進表示の場合は,マイナス符号形式に変換されますが, 16 進や 8 進表示の場合は変換されません。たとえば値 -15237 は 16 進の -00003B85 ではなく, 16 進の FFFFC47B (10 進の 4294952059) として表示されます。 "

この DCL の動作は,OpenVMS システムで大きな値のリソース設定の監視および修正のためのスクリプトを実行すると問題を引き起こします。 OpenVMS version V8.4 で導入された最大 1.98 テラバイトの大規模ディスクのサポートにより,ディスク・ブロック数が符号付き最大値を超えるので多くの DCL プロシージャが悪影響を受け, DCL 整数シンボルで負の数値として表示されると予想されます。ディスク情報を返すのに,F$GETDVI レキシカル関数項目 MAXBLOCK,FREEBLOCKS, EXPSIZE および VOLSIZE が良く使用されます。 V8.4 ではこれらの F$GETDVI 項目が負の数値を返す可能性があります。

B.2.2 前提条件

ある程度の DCL プログラミングの知識が必要です。また,1 TB 以上のサイズのディスクが必要です。

B.3 DCL の例

ここでは,サイズの大きなディスクを持つ Version 8.4 システムで,範囲の確認とパーセンテージの計算を実行する方法を説明するためのいくつかの例とプロシージャを示します。

B.3.1 0 〜 2147483647 の範囲の値をチェックする DCL コード

最小値あるいは2147483647 より小さな最大値で範囲を確認する簡単な方法です。

変更前:

  IF F$GETDVI(device,"FREEBLOCKS") .GT. 100000 
 THEN 
   ... 

変更後:

 IF F$GETDVI(device,"FREEBLOCKS") .LT. 0 .OR. - 
           F$GETDVI(device,"FREEBLOCKS") .GT. 100000 
        THEN 
        ... 



B.3.2 0 〜 4294967295 の範囲の値をチェックする DCL コード

符号付きロングワードの最大値を超える範囲あるいはサイズ値を確認する 1 つの方法は,値をゼロ埋め込みの ASCII 文字列に変換することです。変換後,DCL の文字列論理演算子 (.eqs.,.nes.,.les.,.ges.,.lts.,.gts.) を使用して比較することができます。

$! Begin Example 
$! 
$ disk = P1 
$ if disk .EQS. "" then disk = "SYS$LOGIN_DEVICE" 
$ length        = f$length("4294967296")  ! string length of 2TB in blocks 
$ maxblocks     = f$fao("!''length'ZL",F$GETDVI(disk,"MAXBLOCK")) 
$ freeblocks    = f$fao("!''length'ZL",F$GETDVI(disk,"FREEBLOCKS")) 
$ expsize       = f$fao("!''length'ZL",F$GETDVI(disk,"EXPSIZE")) 
$ volsize       = f$fao("!''length'ZL",F$GETDVI(disk,"VOLSIZE")) 
$ MinBlocks     = f$fao("!''length'ZL",500000) 
$! 
$ write sys$output "Results for Freeblocks=''freeblocks' .comparison. MinBlocks=''MinBlocks'" 
$ write sys$output  ".eqs. "  + F$string((freeblocks .eqs. MinBlocks)) 
$ write sys$output  ".nes. "  + F$string((freeblocks .nes. MinBlocks)) 
$ write sys$output  ".les. "  + F$string((freeblocks .les. MinBlocks)) 
$ write sys$output  ".ges. "  + F$string((freeblocks .ges. MinBlocks)) 
$ write sys$output  ".lts. "  + F$string((freeblocks .lts. MinBlocks)) 
$ write sys$output  ".gts. "  + F$string((freeblocks .gts. MinBlocks)) 
$ write sys$output "" 
$ write sys$output "Results for maxblocks=''maxblocks' .comparison. volsize=''volsize'" 
$ write sys$output  ".eqs. "  + F$string((maxblocks .eqs. volsize)) 
$ write sys$output  ".nes. "  + F$string((maxblocks .nes. volsize)) 
$ write sys$output  ".les. "  + F$string((maxblocks .les. volsize)) 
$ write sys$output  ".ges. "  + F$string((maxblocks .ges. volsize)) 
$ write sys$output  ".lts. "  + F$string((maxblocks .lts. volsize)) 
$ write sys$output  ".gts. "  + F$string((maxblocks .gts. volsize)) 
$! 
$! End example 



B.3.3 ディスク上の空きブロックの割合の確認

共通ディスクの管理操作として,ディスクの未使用領域のパーセンテージの計算や対象ディスクにコピーあるいはバックアップするのための十分な空き領域があるかどうかの確認があります。ここでは,大きなディスクでこれらの特別な機能を扱う例を示します。

1 つのアプローチとして,FREEBLOCKS チェックで負の値が返されたら,ストレージ操作に必要な十分な空きブロックがあると判断するという方法があります。

 IF F$GETDVI(device,"FREEBLOCKS") .LT. 0 THEN GOTO SUCCESS 

この例では,システム・デバイスの空きブロックが残り 5% 以上あるかどうかをチェックする方法を示しています。チェックのために PERCENT_FREE サブルーチンを呼び出しています。このサブルーチンは,符号付きの計算ができるようにディスクの値の単位を変換しています。

$! begin Example 
$! 
$ percent_free == -1 
$! 
$ CALL percent_free "sys$sysdevice" 
$ IF $status .AND. percent_free .gt. 0 
$ then 
$  if percent_free .ge. 5 
$  then 
$        write sys$output "Sufficient freeblocks on disk" 
$  else 
$        write sys$output "Warning Insufficient freeblocks on disk" 
$ endif 
$ else 
$ write sys$output "Problem obtaining information for disk" 
$ endif 
$! 
$ EXIT 
$ 
$! 
$   percent_free: subroutine 
$ ! 
$ !   This subroutine will return, as an integer, the percentage of free 
$ !   disk blocks for a given volume.  The percentage free is given by: 
$ ! 
$ !                       (number of free blocks on the volume) 
$ !     Percentage Free = ------------------------------------- * 100 
$ !                              (volume size in blocks) 
$ ! 
$ !   The volume name is passed in P1 and the result is returned in the 
$ !   global symbol PERCENT_FREE.  For example: 
$ ! 
$ !     $ call percent_free "disk$test" 
$ !     $ write sys$output "Free space is ", percent_free, "%" 
$ ! 
$ !   Since DCL does signed 32 bit arithmetic, all calculations and results 
$ !   are done with the sign bit (bit 31) clear.  So, for values of free 
$ !   blocks and volume size larger than %x7FFFFFFF we first clear the sign 
$ !   bit, divide by two (shift right one bit) and then turn on bit 30. 
$ ! 
$     freeblocks = f$getdvi(p1,"freeblocks") 
$     volsize = f$getdvi(p1,"volsize") 
$ ! 
$     if (freeblocks .lt. 0) 
$     then pipe freeblocks[31,1] = 0 ; freeblocks = freeblocks / 2 ; freeblocks[30,1] = 1 
$     else freeblocks = freeblocks / 2 
$     endif 
$ ! 
$     if (volsize .lt. 0) 
$     then pipe volsize[31,1] = 0 ; volsize = volsize / 2 ; volsize[30,1] = 1 
$     else volsize = volsize / 2 
$     endif 
$ ! 
$     if ((volsize / 100) .gt. 0) 
$     then percent_free == freeblocks / (volsize / 100) 
$     else percent_free == 0 
$     endif 
$ ! 
$   endsubroutine 



B.3.4 F$CUNITS() レキシカル関数の説明

V8.4 より前の F$CUNITS() レキシカル関数は,ブロック値をそれに対応するバイト値へ変換することができました。このレキシカルの出力は,結果の値の大きさに応じて KB,MB などの単位表記を自動的に切り換えていました。 V8.4 では,バイトからブロックへの変換もサポートするようにこのレキシカルが拡張されています。さらに,単位のキーワード値が導入され,結果の値の単位表記をユーザが指定できるようになっています。 F$CUNITS レキシカル呼び出しの形式は下記のとおりです。

 result = F$CUNITS(value, from-units, to-units) 

value には,1 〜 4294967295 の範囲で値を指定します。

V8.4 より前のバージョンの場合:

 from-units:  "BLOCKS"  ! オプション, デフォルトは BLOCKS 
   to-units:   "BYTES"  ! オプション, デフォルトの BYTES で単位が自動変換される 

V8.4 の場合:

    from-units:  unit      ! オプション, デフォルトは BLOCKS 
      to-units:  unit      ! オプション, デフォルトの BYTES で単位が自動変換される 

単位は次のいずれかを使用します。

  "BYTES","BLOCKS","KB","MB","GB","TB"  

大きなディスクに対しては,BLOCKS 以外の単位で処理および表示を行う方が便利です。

次の例では,F$CUNITS 関数を使用してブロックからバイトへ値を変換する方法を示しています。 F$CUNITS レキシカルの実行中,空きディスク容量のパーセンテージが計算されます。この例には,パーセンテージを概算する簡単な方法も含まれています。

$! 
$ if p1 .nes. "" Then GOTO show_device_info 
$ thisproc = f$environment("procedure") 
$Loop: 
$ disk = F$DEVICE("*","DISK") 
$ if disk .eqs. "" then EXIT 
$ @'thisproc' 'disk' 
$ goto Loop 
$show_device_info: 
$! Example: 
$! 
$!   Demonstrate the use of the F$CUNITS() lexical and 
$!   calculate the percent free of a disk 
$! 
$ disk = P1 
$ if P1 .eqs. "" then disk = "sys$sysdevice" 
$ if .NOT.  ( f$getdvi(disk,"EXISTS") .AND.  - 
              f$getdvi(disk,"AVL")    .AND.  - 
              f$getdvi(disk,"MNT")   ) then  EXIT 
$ write sys$output "Results for disk : ''disk'" 
$ line = f$fao("!4(16AS)","Units","Total", "FREE", "Percent") 
$ write sys$output line 
$! 
$! do direct calculation or approximation first  (BLOCKS) 
$! 
$ TotalSize = f$fao("!UL",f$getdvi(disk,"MAXBLOCK")) 
$ FreeSize = f$fao("!UL",f$getdvi(disk,"FREEBLOCKS")) 
$ TotalDisplay = TotalSize 
$ FreeDisplay = FreeSize 
$ if f$length(TotalSize) .lt. 7 then GOTO No_approximation 
$ TotalSize =  f$extract(0,7,f$fao("!10ZL",f$getdvi(disk,"MAXBLOCK"))) 
$ FreeSize  =  f$extract(0,7,f$fao("!10ZL",f$getdvi(disk,"FREEBLOCKS"))) 
$! 
$No_approximation: 
$ uindex = -1 
$ units = "BLOCKS,KB,MB,GB,TB" 
$! 
$! show approximation 
$! 
$ unit = "Approx" 
$! 
$ GOTO Compute_Percent 
$! 
$Fcunits_display: 
$! 
$Get_Unit: 
$!-------- 
$ unit = f$element(uindex,",",units) 
$ if unit .eqs. "," then EXIT 
$! 
$ TotalSize  =  f$cunits(f$string(f$fao("!UL",f$getdvi(disk,"MAXBLOCK"))),"BLOCKS",unit)  - "''unit'" 
$ FreeSize   =  f$cunits(f$string(f$fao("!UL",f$getdvi(disk,"FREEBLOCKS"))),"BLOCKS",unit) -  "''unit'" 
$! 
$ TotalDisplay = TotalSize 
$ FreeDisplay = FreeSize 
$! 
$! for unit >= gigabytes retain the fractional value 
$! 
$ if uindex .lt. 4 then goto Edit_Units_002 
$! 
$ if f$locate(".",TotalSize) .eq. f$length(TotalSize) 
$ then 
$       TotalSize = TotalSize + "00" 
$ else 
$       TotalSize = TotalSize - "." 
$ endif 
$ if f$locate(".",FreeSize) .eq. f$length(FreeSize) 
$ then 
$       FreeSize = FreeSize + "00" 
$ else 
$       FreeSize = FreeSize - "." 
$ endif 
$! 
$ GOTO Compute_Percent 
$! 
$Edit_Units_002: 
$! 
$! For units < Gigabytes truncate any fraction 
$! 
$ if f$locate(".",TotalSize) .lt. f$length(TotalSize) 
$ then 
$       TotalSize = f$extract(0,f$length(TotalSize)-3,TotalSize) 
$ endif 
$! 
$ if f$locate(".",FreeSize) .lt. f$length(FreeSize) 
$ then 
$       FreeSize = f$extract(0,f$length(FreeSize)-3,FreeSize) 
$ endif 
$! 
$Compute_Percent: 
$! 
$! check for overflow on percentage calculation 
$! 
$ PCTfree = -1 
$ if (((f$integer(FreeSize)*100)/100) .ne. f$integer(FreeSize)) .OR. - 
      f$length(FreeSize) .gt. 8 .OR f$length(TotalSize) .gt. 8 
$ then 
$       PCTfree = "Overflow" 
$ else 
$       if TotalSize .eq. 0 .OR. FreeSize .eq. 0 
$       then 
$               PCTfree = 0 
$       else 
$               PCTfree = f$integer( (FreeSize*100) / TotalSize) 
$       endif 
$ endif 
$! 
$ line =   f$fao("!4(16AS)",Unit, TotalDisplay, FreeDisplay, f$string(PCTfree)) 
$ write sys$output line 
$! 
$ uindex = uindex + 1 
$ GOTO Get_Unit 
$! 
$ EXIT 
$! 



B.4 疑わしい DCL コードの特定

ここでは,1 TB を超えるデバイスにアクセスする場合に正しく機能しない可能性のある DCL コードおよびソース・コード・モジュールを識別するための方法を説明します。

B.4.1 DCL コードの検索例

この例では,明らかに対処が必要な DCL コード行を特定するための簡単な検索を示します。 DCL コードでレキシカル項目をシンボルとして提供したり,レキシカル呼び出しを複数行に分割するような場合がありますが,このプロシージャはこのようなコードは特定しません。

$ search := search/numbers/wind=1/MATCH=AND/statistics 
$ filespec = 'your_filespec' 
$! 
$! The results of the search command on the next 3 lines 
$! show DCL command lines that MUST be addressed on systems 
$! accessing disks over 1tb. 
$ search  'filespec'  "F$GETDVI","MAXBLOCK" 
$ search  'filespec'  "F$GETDVI","VOLSIZE" 
$ search  'filespec'  "F$GETDVI","EXPSIZE" 
$! 
$! The results of the search command on the next line 
$! show DCL command lines that should be changed on 
$! systems accessing disks over 1tb. 
$! The DCL command is likely to return a value that will 
$! not fit in a signed longword. 
$ search  'filespec'  "F$GETDVI","FREEBLOCKS" 
 


索引 目次

© 2012 Hewlett-Packard Development Company, L.P.