「暗黙のアクセス・パス共有」でデータがおかしい?!

論理ファイルの作成順序や復元順序によって起きる事象に、予期しない暗黙のアクセス・パス共有があります。

暗黙のアクセス・パス共有という事象それ自体は、ムダなスペースの節約になりますし、メモリーの使用量や更新の負荷の低減にもつながりますし、効率の向上という観点からはとても有用なものです。

"予期しない"というのがポイントで、移行などのきっかけで全然変更も何もしていないプログラムがある日突然おかしな挙動をするようになるわけです。
その"移行"というのも、単なる新規区画への RSTLIB、なんていった特段問題が起きるなんて考えてもいない状況を含みます。

ときどき「プログラムの問題だ」「プログラムのバグだ」といった言われ方をすることがありますが、プログラムを変更していない状態で、ただ RSTLIB/RSTOBJ や LF の再作成を行っただけで起きてしまう事象なので、あまり実感として納得できるものではないでしょう。
それどころか、「システムのバグでは?」といった印象を引き起こすことが、ままあります。実際、「昔から有名な AS/400 のサイト関連記事」の方も一旦はそう疑ったようにも読めますよね。

プログラムの書き方の問題、というよりは、論理ファイルを使っていると不可避的に起きる問題と言ってもよさそうなので、守備範囲としてはやはり「インフラ」領域になってしまうことが多いでしょうね。(それで「アクセス・パスが暗黙共用されることによってプログラムの動作に影響を与えることがあります」なんていうお知らせが出てるんでしょうし)

事象と対策の理解をし、大問題にならないようにするのが大事ですね。

よくある事象その2

よくある事象1」のように「ループする」というのが得てしてよくある事象なのですが、これから見るように「正常終了しているように見えてデータがおかしい」という事象になることもあります。
ある意味、こちらの方が始末が悪いかもしれませんね。。


正常時の動き

今回も同じようなファイルを素材にして見てみましょう。

こちらでは更新のかかるデータは1桁の文字フィールドにしました。

こんなかんじのプログラムが例です。

     FLFK2    UF  E           K        DISK                                     
      *                                                                         
     C           KLIST1    KLIST                                                
     C                     KFLD           F1     10                             
     C                     KFLD           F2     10                             
      *                                                                         
     C                     MOVEL'1'       F1                                    
     C                     MOVEL'1'       F2                                    
      *                                                                         
     C           KLIST1    SETLLREC                                             
      *                                                                         
     C           *IN91     DOWEQ'0'                                             
     C                     READEREC                      10                     
     C           *IN10     IFEQ '0'                                             
     C                     ADD  1         COUNT   30                            
     C           K3        IFEQ '0'                                             
     C                     MOVEL'1'       K3                                    
     C                     ELSE                                                 
     C                     MOVEL'0'       K3                                    
     C                     ENDIF                                                
     C                     UPDATREC                                             
     C                     ELSE                                                 
     C                     MOVE '1'       *IN91                                 
     C                     ENDIF                                                
     C                     ENDDO                                                
      *                                                                         
     C           COUNT     DSPLY                                                
      *                                                                         
     C                     SETON                         LR                     
     C                     RETRN                                               

フラグを整理して入れ替えるような処理イメージにしてみました。
これもそれほど実は人工的な例ではありませんね。実際にこういう処理をすることもありますし、何か文字を入れ替える処理が順番にからんでくるようなものであれば同じことになります。

READ が成功するたびにカウントを取り、最後にその件数を表示させています。

物理ファイルが↓

     A          R REC                                                           
     A            K1            10                                              
     A            K2            10                                              
     A            K3             1                                              
     A          K K1  

プログラムで読み込む論理ファイルが↓

     A          R REC                       PFILE(PF)                           
     A          K K1                                                            
     A          K K2 

になります。

では、プログラムを動かしてみましょう。

0 のフラグが 1 になります。

読みこみ回数(READE を行った回数)は5回、ですね。READE の更新対象レコードが5件あるんだから当たり前でしょ!、と思ってますかね?!

念のため↑の状態でもう一度プログラムを動かしてみましょう。

予定通り今度はフラグが 1 から 0 になります。

こちらも対象が5件なので当然!ですかね?!

暗黙のアクセス・パス共有状態に

ここで、このフィールドをキーにした論理ファイルを追加してみましょう。

     A          R REC                       PFILE(PF)                           
     A          K K1                                                            
     A          K K2                                                            
     A          K K3                                                            

フラグだったとしても論理ファイルを作成するのはよくあることですし(実際 SQL の世界だったら BITMAP INDEX = EVI を使うところですね)、これがカナフィールドかなんかだったとしても今回紹介する事象は発生するので、特別人為的な例というわけではありません。

元の論理ファイルを削除してみましょう。
これで前回のように暗黙のアクセスパス共有が起きるような状況になっています。

実際、論理ファイルを再作成してみると、↓のように「アクセス・パスを共用している」というメッセージが表示されます。

事象発生

さて、この状態でプログラムを再度実行してみましょう。
データはこの記事の一番最初の状態と同じだとします。(lここまで順番にやってみていればそうなっていますね)

READ 件数が 10件になっていることがわかりますね?!

なぜ、データは最初の実行時と同じものでプログラムもまったく同じものなのに、READ の回数が違っているんでしょう??

しかも、初期状態が 0 だったので、プログラムの実行後は 1 になっていないとおかしいのですが … 0 のままですね。。
つまり"間違った結果"になっているわけです。

でも事象が起きないケースも?!

面倒なのは、この状態でも最初 K3 が 1 だった場合は結果が違う、ということなんですね。

初期条件が 1 の状態でプログラムを実行してみましょう。

このプログラムを実行しているだけではずっと 1 にはなりませんので、DFU で 1 をセットし、再度実行すると、、

READ の回数は 5回で、結果も正しく 0 に更新されているのが確認できます。

… 見つけにくいですよねぇ。。

対応策は、、

要するに「暗黙のアクセス・パスの共有」というのは、こうした事象の火種になるんですね。

前回のループのようにすぐわかればいいのですが、今回のように正常に終了してしまうとすぐに発見するのは難しいですよね。

しかも、今回のケースでは初期条件によって事象が出たり出なかったりしますので、なおさら発見はやっかいです。

対象になっているフィールドが(別の論理ファイルで)キーになっているために即時で並べ替えられてしまうから、なんですね。「論理ファイル」というもののスペックです。
処理を対象の集合でしか記述しないSQLでは当然起こり得ません。

「論理ファイル」を使っているプログラムであれば、対象の論理ファイルが「暗黙的なアクセス・パスの共有」をされてしまえば起きてしまう事象です。
プログラムでは対処のしようがありません。実際ロジックはまったく変えないままで、事象は起きたり起きなかったりするわけですから。
(SQL に書き換える、とか OPNQRYF に書き換える、という手段も考えればプログラムでの対処も可能、とは言えますが、、"移行"という範疇は超えてますね)

いまどきのコトバでいえば、まずは「インフラ」側で何とかしないといけない問題、になります。

解決策はこちらを参考にしてもらえばいいのですが、いずれにせよこういう考慮点がある、ということは忘れないようにしてくださいね。
失敗学の「失敗は伝わらない」になりそうで心配です。。

プログラムを変えなくても、呼び出す前に OPNQRYF

二度読みが行われ結果が正しくない状態でも、↓のように OPNQRYF を行ってからもう一度同じプログラムを呼ぶと、ちゃんと処理されるようになります。
(ライブラリーの名前が INPACC2 から INPACC に変わっていますが、実際には↑でテストしたファイル/プログラムとまったく同じものです。
ちなみに、「よくある事象1」もまったく同じやり方で事象(ループ)を回避できます)

RUNQRY で見てみても正しい結果が出ていることが確認できます。

SQL への書き替え

このケースではプログラムをまったく変更せずに対応していますが、埋め込み SQL か何かで書き換えてしまう、というやり方もあるでしょう。

そうしてしまえば、そもそも論理ファイルが必要なくなりますので、問題の火種そのものがなくなるわけですね。
そちらの方がパフォーマンスもよくなるケースがほとんどです(意外かもしれませんが)し、今後の心配から解放される、と考えるとそれはそれで選択肢に入ってくるのではないでしょうか?!

[Top Pageに戻る]

Ads by TOK2