1

これが私が約1週間熱心に攻撃してきた仕事上の問題ですが成功しませんでした。

apache commonsnetFTPClientライブラリを使用してファイルをメインフレームに送信するレガシーJavaコードがあります。このコードは、86Mb未満のファイルに対して完全に機能します。ただし、86Mbを超えるファイルが検出されると、CopyStreamExceptionで失敗します(他の有用な情報はありません)。タイムアウトとCopyStreamListenerを追加しましたが無駄になりました。リスナーは、FTPが86Mbに達するまでデータのバッファーをメインフレームに正常にアップロードしていることを示すいくつかのメッセージを出力します(サンプルログ出力は以下に含まれています)。

当初、問題はネットワーク/ファイアウォールに関連していると思っていましたが(コードに非常に多くのタイムアウト操作が表示される理由です)、メインフレームに送信するスペース割り当てコマンドに関係していることがわかりました。私はここでメインフレームの専門家から支援を受けており、彼はBLKSIZE、SPACE、LRECLなどのさまざまな組み合わせについて多くの提案をしました。しかし、それらのどれもうまくいきませんでした。転送を一度完了させましたが、メインフレームの担当者から、メインフレームで作成されたファイルのブロックサイズとフォーマットのパラメーターが正しくないことが通知されたため、それを破棄する必要がありました(これについて説明します)この場合、以下で機能しました)。

まず、Javaコードは次のとおりです。

public static boolean copyFileThruFTP(
    String srcFileName, String remoteFileName, Properties exportProps) {
    boolean success = true;
    String serverUserName = exportProps.getProperty(WebUtil.FTP_SERVER_USER);
    String serverPwd = exportProps.getProperty(WebUtil.FTP_SERVER_PWD);
    String serverIp = exportProps.getProperty(WebUtil.FTP_SERVER_IP);
    File f = new File(srcFileName);
    FTPClient ftpClient = null;
    try {
        String errorMessage = null;
        FileInputStream input = new FileInputStream(f);
        ftpClient = new FTPClient();

        ftpClient.setDataTimeout(6000000); // 100 minutes
        ftpClient.setConnectTimeout(6000000); // 100 minutes
        ftpClient.connect(serverIp);
        int reply = ftpClient.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)) {
            errorMessage = "FTP server refused connection: " + ftpClient.getReplyString();
        } else {
            if (!ftpClient.login(serverUserName,serverPwd)) {
                errorMessage = "Failed to copy file thru FTP: login failed.";
            } else {
                ftpClient.setBufferSize(1024000);
                ftpClient.setControlKeepAliveTimeout(30); // sends a keepalive every thirty seconds

                if (ftpClient.deleteFile(remoteFileName)) {
                    log.warn("Deleted existing file from remote server: " + remoteFileName);
                }
                ftpClient.setFileTransferMode(FTP.ASCII_FILE_TYPE);
                ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
                ftpClient.sendSiteCommand("RECFM=FB");
                ftpClient.sendSiteCommand("LRECL=2000");
                ftpClient.sendSiteCommand("BLKSIZE=27000");
                //ftpClient.sendSiteCommand("DCB=(RECFM=FB,LRECL=2000,BLKSIZE=26000)");
                ftpClient.sendSiteCommand("SPACE=(TRK,(500,500),RLSE)");

                OutputStream ftpOut = ftpClient.storeFileStream(remoteFileName);
                if (ftpOut == null) {
                    errorMessage = "FTP server could not open file for write: " + ftpClient.getReplyString();
                } else {
                    OutputStream output = new BufferedOutputStream(ftpOut);

                    log.warn("copyFileThruFTP calling copyStream() for file: " + f.getAbsolutePath());
                    Util.copyStream(input, output, ftpClient.getBufferSize(), f.length(),
                        new CopyStreamAdapter() {
                            public void bytesTransferred(
                                long totalBytesTransferred, int bytesTransferred, long streamSize) {
                                    log.warn(bytesTransferred + " bytes written; total: " + totalBytesTransferred + " of " + streamSize);
                            }
                        });
                    input.close();
                    output.close();
                    if (!ftpClient.completePendingCommand()) {
                        errorMessage = "Failed to copy file thru FTP: completePendingCommand failed.";
                    }
                }
            }
            ftpClient.logout();
            ftpClient.disconnect();
            ftpClient = null;
        }
        if (!StringUtils.isEmpty(errorMessage)) {
            log.error(errorMessage);
            System.out.print(errorMessage);
            success = false;
        }
    } catch (CopyStreamException cse){
        cse.printStackTrace();
        log.error("Failed to copy file thru FTP (CopyStreamException).", cse);
        success = false;
    } catch (IOException e){
        e.printStackTrace();
        log.error("Failed to copy file thru FTP (IOException).", e);
        success = false;
    } finally {
        try {
            if (ftpClient != null) {
                ftpClient.logout();
                ftpClient.disconnect();
            }
        } catch (IOException ignore) {}
    }

    return success;    
}

さて、私が言ったように、このコードは86Mb未満のすべてのファイルで非常にうまく機能するので、知識の観点からは役立つかもしれませんが、Javaコーディングスタイルなどのヒントは本当に必要ありません。このメソッドを投稿して、コメントと無関係なコードを削除したので、これをeclipseにコピーして戻したときに何も表示されませんでしたが、構文エラーが1つか2つある可能性があります。私が解決しようとしているのは、このコードが小さなファイルでは機能するが、大きなファイルでは機能しない理由です。

大きなファイルのログ出力のサンプルを次に示します(見た目を良くするために少し変更しました)。


2012-02-29 11:13 WARN - copyFileThruFTP calling copyStream() for file: C:\data\mergedcdi\T0090200.txt
2012-02-29 11:13 WARN - 1024000 bytes; total: 1024000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 2048000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 3072000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 4096000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 5120000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 6144000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 7168000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 8192000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 9216000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 10240000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 11264000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 12288000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 13312000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 14336000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 15360000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 16384000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 17408000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 18432000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 19456000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 20480000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 21504000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 22528000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 23552000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 24576000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 25600000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 26624000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 27648000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 28672000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 29696000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 30720000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 31744000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 32768000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 33792000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 34816000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 35840000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 36864000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 37888000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 38912000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 39936000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 40960000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 41984000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 43008000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 44032000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 45056000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 46080000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 47104000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 48128000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 49152000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 50176000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 51200000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 52224000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 53248000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 54272000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 55296000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 56320000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 57344000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 58368000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 59392000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 60416000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 61440000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 62464000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 63488000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 64512000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 65536000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 66560000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 67584000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 68608000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 69632000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 70656000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 71680000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 72704000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 73728000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 74752000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 75776000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 76800000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 77824000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 78848000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 79872000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 80896000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 81920000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 82944000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 83968000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 84992000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 86016000 of 96580484
2012-02-29 11:17 ERROR- Failed to copy file thru FTP (CopyStreamException).
org.apache.commons.net.io.CopyStreamException: IOException caught while copying.
    at org.apache.commons.net.io.Util.copyStream(Util.java:130)
    at org.apache.commons.net.io.Util.copyStream(Util.java:174)
    at com.pa.rollupedit.util.WebUtil.copyFileThruFTP(WebUtil.java:1120)
    at com.pa.rollupedit.util.CdiBuilder.process(CdiBuilder.java:361)
    at com.pa.rollupedit.controller.ExportCDI.doGet(ExportCDI.java:55)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at com.pa.rollupedit.controller.LoginFilter.doFilter(LoginFilter.java:90)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at com.pa.rollupedit.util.RequestTimeFilter.doFilter(RequestTimeFilter.java:18)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3496)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)


では、メインフレームで何が起こるかを見てみましょう。不完全な送信によって生成されたファイルに関して、メインフレームの担当者から提供された情報は次のとおりです。

    Data Set Name . . . . : BSFP.ICEDCDI.SPC10.T0090200

General Data Current Allocation Management class . . : MCDFLT Allocated tracks . : 1,650 Storage class . . . : SCSTD Allocated extents . : 32 Volume serial . . . : SMS217 + Device type . . . . : 3390 Data class . . . . . : DCDFLT Organization . . . : PS Current Utilization Record format . . . : FB Used tracks . . . . : 1,650 Record length . . . : 2000 Used extents . . . : 32 Block size . . . . : 26000 1st extent tracks . : 100 Secondary tracks . : 50 Dates Data set name type : Creation date . . . : 2012/02/29 SMS Compressible. . : NO Referenced date . . : 2012/02/29 Expiration date . . : None

レコード長、レコード形式、およびブロックサイズは、私が送信したサイトコマンドに基づいていると予想されるとおりであることに注意してください。ただし、1次トラックと2次トラックは、私には正しくないように見えます。メインフレームの担当者から、約10種類のSPACEコマンドを試してもらいました(ブロックサイズの変更もあります)。レコードサイズは間違いなく2000文字なので、一貫性が保たれています。しかし、これまでのところ、彼の提案はどれもうまくいきませんでした。

私自身、パラメータを設定する別の方法を発見し、ある時点でそれを試しました。これは、コメント化された行としてコードで確認できます。

 //ftpClient.sendSiteCommand("DCB=(RECFM=FB,LRECL=2000,BLKSIZE=26000)");

これについて興味深いのは、このコマンドを使用したとき(そして、RECFM / LRECL / BLKSIZEコマンドをコメントアウトしたとき)、ftp送信が成功したことです!! しかし、メインフレームの担当者は、次のリモートファイル情報を共有しました。これは、さまざまなパラメータが正しく設定されていないことを示しています。DCBコマンドがまったく機能しなかったように見えます。


    Data Set Name . . . . : BSFP.ICEDCDI.SPC10.T0090200

General Data Current Allocation Management class . . : MCDFLT Allocated tracks . : 230 Storage class . . . : SCSTD Allocated extents . : 4 Volume serial . . . : SMS195 Device type . . . . : 3390 Data class . . . . . : DCDFLT Organization . . . : PS Current Utilization Record format . . . : VB Used tracks . . . . : 230 Record length . . . : 256 Used extents . . . : 4 Block size . . . . : 27000 1st extent tracks . : 100 Secondary tracks . : 50 Dates Data set name type : Creation date . . . : 2012/02/28 SMS Compressible. . : NO Referenced date . . : 2012/02/29 Expiration date . . : None

言うまでもなく、それは本当に物事にダンパーを置きます。

今朝からの更新:メインフレームの人が他のメインフレームの専門家に連絡しました。そのうちの1人は、SPACEコマンドで「TRK」が正しくないことを伝え、代わりに次を使用しました。


    ftpClient.sendSiteCommand("SPACE=(TRA,(PRI=500,SEC=500))");

私はこれを(PRI=やSEC=なしなどの他のバリエーションと一緒に)試しましたが、結果はまったく同じです(つまり、86Mbで失敗します)。

ご覧のとおり、これは些細な質問ではありません。これがネットワークの問題ではないことを確認するために経験した多くの旋回についても詳しく調べていません。この時点で、この問題の原因はメインフレームのサイトコマンドであると約98.6%確信しています。

何かお手伝いいただければ幸いです!!

4

2 に答える 2

4

特定のサイズで失敗しているので、それがメインフレーム スペース コマンドです。

メインフレーム ファイルには、16 個のエクステント、1 つのプライマリ割り当て、15 個のセカンダリ割り当てのみを含めることができます。ディスク パックが満杯またはほぼ満杯の場合、プライマリ割り当てを取得できない可能性があります。

現在の割り当てでは、500 のプライマリ トラックと 15 * 500 のセカンダリ トラック、合計 8,000 のトラックを要求しています。トラックは、ディスク ドライブのトラック サイズに応じて、26,000 バイトの 2 つまたは 3 つのブロックを保持します。ブロック サイズに 0 を指定すると、IBM オペレーティング システムは最も効率的なブロック サイズを計算します。

少し計算すると、208,000 レコード (最悪の場合) を割り当てたことがわかります。

おそらく、スペースをシリンダーで指定し、小さなプライマリーと大きなセカンダリーを用意する必要があります。何かのようなもの:

ftpClient.sendSiteCommand("SPACE=(CYL,(30,300),RLSE)"); 

メインフレーム ショップがトラックの指定を要求する場合は、次の方法を試してください。

ftpClient.sendSiteCommand("SPACE=(TRK,(450,4500),RLSE)");

どちらの数も 15 で割り切れるようにしました。私の記憶が正しければ、シリンダーには 15 のトラックが含まれているからです。

追加するために編集:

IBM Web サイトでIBM FTP コマンドのページを見つけました。DCB コマンドと同様に、スペース コマンドの各部分を個別に送信する必要があるようです。

ftpClient.sendSiteCommand("TR");
ftpClient.sendSiteCommand("PRI=450");
ftpClient.sendSiteCommand("SEC=4500");
于 2012-02-29T18:29:21.000 に答える
4

Gilbert Le Blanc による優れた回答にいくつかコメントを追加したいと思います。

小さなプライマリ スペースと大きなセカンダリ スペースを指定する理由は、少し直感に反しています。プライマリ スペースの割り当てでは、常に連続したスペース (つまり、1 つの大きなチャンク) が要求されます。ボリューム (ディスク) がその量の連続したスペースで見つからない場合、ジョブは B37 リターン コードで失敗します。1 次スペース割り振りがボリュームのかなりの割合を占める状況 (3390 DASD デバイスは実際にはかなり小さい - 10Gb 程度) では、必要なスペースを持つボリュームが見つからない可能性が高くなります。したがって、仕事はB37で爆発します。

二次割り当ては、連続したブロックを割り当てる必要はなく、複数のボリュームにまたがることができます。かなり小さい 1 次量を要求することにより、データセットが 2 次スペースを割り振って合計スペース要件を満たすことができるようになり、B37 異常終了を回避できます。このアプローチの問題点は、ボリュームごとに 15 の 2 次エクステントしか取得できないことです (これは人為的ではあるが歴史的な制限であり、ショップの DASD 管理によって解除できます)。エクステント制限を超えて E37 異常終了が発生しないようにするには、大きなエクステント サイズを要求します。

最後に、データセットがまたがることができるボリュームの数を設定できる FTP VCOUNT パラメーターを指定できます (各ボリュームは最大 15 のエクステントを持つことができます)。これにより、非常に巨大なデータセットが作成される可能性があります。

これはすべて、IBM メインフレームでの従来のデータセットの割り当てを理解するには、ちょっとした魔法が必要であることを示しています。

ストレージ管理システム (SMS) を利用して計算を行うことで、生活を大幅に簡素化できます。ほとんどのショップで SMS が導入されます。プライマリ/セカンダリ エクステントのサイズを計算するためにすべての計算を行う代わりに、適切な SMS DATACLAS を求めることができます。ほとんどのインストールには、あなたのような大規模なデータ セットに適したものがあります。インストールごとに独自の DATACLS 名が定義されているため、メインフレーム担当者がそれらを掘り起こす必要があります。SMS DATACLAS は、FTP LOCSITE オプションを使用して指定されます。DATAC=xxx ここで、xxx は適切な DATACLAS 名です。

于 2012-03-01T16:37:21.683 に答える