Java Apache Commons FTPClient는 대상 메인 프레임 파일의 공간 할당을 실패합니다.

StackOverflow https://stackoverflow.com/questions/9504331

문제

여기에 성공하지 않고 약 1 주 동안 부지런히 공격하는 작업 문제가 있습니다.

i Apache Commons Net FTPClient 라이브러리를 사용하여 메인 프레임에 파일을 보낼 수있는 레거시 Java 코드가 있습니다. 이 코드는 86MB 미만의 파일에 완벽하게 작동합니다. 그러나 86MB 이상의 파일을 만나면 CopyStreamException (다른 유용한 정보 없음)에서 실패합니다. 시간 초과와 CopyStreamListener를 사용하지 않아도됩니다. 청취자는 FTP가 86MB (샘플 로그 출력이 아래에 포함될 때까지) 메인 프레임에 데이터 버퍼를 성공적으로 업로드한다는 것을 나타내는 일부 메시지를 출력합니다.

나는 원래이 문제가 네트워크 / 방화벽과 관련된 (코드에서 많은 시간 초과 조작을 보는 이유)이기 때문에, 이제는 메인 프레임에 보내는 공간 할당 명령과 관련이 있다는 것을 이해합니다. 나는 여기에서 메인 프레임 전문가로부터 도움을 받았으며 그는 blksize, space, lrecl 등의 다른 조합에 대한 수많은 제안을했지만 그들 중 누구도 효과가 없었습니다. 그러나 한 번 완성되기 위해 일하기 위해 이전을 얻었습니다. 그러나 메인 프레임 녀석은 메인 프레임에서 생성 된 파일의 BlockSize와 형식 매개 변수가 잘못되었음을 알려 줬습니다. 그래서 나는 그것을 스크랩해야했습니다 (그것이 무엇인지 설명 할 것입니다. 이 경우 아래에 일했습니다).

첫째, 여기에 자바 코드가 있습니다.

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에 다시 복사했을 때 아무런 구문 오류가있을 수 있습니다. 이 해결을 시도하는 것은이 코드가 작은 파일에 대해 작동하지만 큰 파일을위한 것이 아닙니다!

여기에 큰 파일에 대한 로그 출력 샘플 (미적 측정을 위해 약간 수정) :


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

레코드 길이, 레코드 형식 및 블록 크기는 내가 보낸 사이트 명령을 기반으로 할 것으로 예상하는 것처럼 보입니다. 그러나 첫 번째 범위와 2 차 트랙은 잘못 될 것입니다. 메인 프레임 녀석은 10 개의 다른 공간 명령을 시도 할 수있는 10 개의 다른 공간 명령을주었습니다 (블록 크기에 대한 수정과 함께 수정). 레코드 크기는 확실히 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

. 말할 필요도없이, 그건 정말로 댐퍼를 댐퍼를 넣습니다.

오늘 아침부터 업데이트 : 메인 프레임 녀석이 다른 메인 프레임 전문가에게 도달했는데, 그 중 하나는 공간 명령에서 "TRK"가 잘못되었고 다음을 사용하는 것으로 알려줍니다.


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


나는 이것을 시도했다 (pri=와 sec= 없이는 다른 변형들과 함께)이지만 결과는 정확히 동일합니다 (즉, 86MB에서 실패합니다).

보시다시피, 이것은 경솔한 질문이 아닙니다. 나는 이것이 이것이 네트워크 문제가 아니라는 것을 확인할 때 내가 겪은 많은 Grations에 깊이 있지 않다. 이 시점 에서이 문제가 메인 프레임 사이트 명령으로 인해 발생하는 것은 약 98.6 %입니다.

도움을 제공 할 수있는 경우 가장 크게 감사드립니다!

도움이 되었습니까?

해결책

Since you're failing at a certain size, it's your mainframe space command.

A mainframe file can only have 16 extents, 1 primary allocation and 15 secondary allocations. If the disk pack is full or nearly full, you might not get your primary allocation.

In your current allocation, you're asking for 500 primary tracks and 15 * 500 secondary tracks, for a total of 8,000 tracks. A track will hold either 2 or 3 blocks of 26,000 bytes, depending on the disk drive track size. If you specify a block size of 0, the IBM operating system will calculate the most efficient block size.

A bit of math indicates you've allocated for 208,000 records (worst case).

You probably should specify your space in cylinders, and have a small primary and larger secondary. Something like:

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

If your mainframe shop insists on you specifying tracks, try this:

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

I made both numbers divisible by 15, because if I recall correctly, a cylinder contains 15 tracks.

Edited to add:

I just found the IBM FTP commands page on the IBM web site. It appears you have to send each part of the space command separately, just like the DCB command.

ftpClient.sendSiteCommand("TR");
ftpClient.sendSiteCommand("PRI=450");
ftpClient.sendSiteCommand("SEC=4500");

다른 팁

I would like to add a few comments to the excellent answer given by Gilbert Le Blanc

The reason for specifying a small primary and large secondary space is a little counter intuitive. Primary space allocations always request contiguous space (i.e. in one big chunk). The job will fail with a B37 return code when a volume (disk) cannot be found with that amount of contiguous space on it. In situations where the primary space allocation represents a significant percentage of a volume (3390 DASD devices are actually fairly small - on the order of 10Gb or so), the probability of not finding a volume with the required space can be significant. Hence the job blows up on a B37.

Sencondary allocations do not have to be allocated contiguous blocks and may span multiple volumes. By requesting a fairly small primary quantity you avoid the B37 abend by allowing the dataset to allocate secondary space to fulfill the total space requirement. The catch with this approach is that you may only get 15 secondary extents per volume (this is an artificial but historical limit that can be lifted by the DASD management in your shop). To avoid blowing the extent limit, causing an E37 abend, you request a large extent size.

Finally, you can specify an FTP VCOUNT parameter that can set the number of volumes a dataset may span (each volume can have up to 15 extents). This can make for absolutely huge datasets.

All this to point out that understanding traditional dataset allocation on an IBM mainframe involves a bit of witch-craft.

Life can be made a lot simpler by relying on Storage Management System (SMS) to do the figuring for you. Most shops will have SMS in place. Instead of having to do all the math to calculate primary/secondary extent sizes, you can probably just ask for the appropriate SMS DATACLAS. Most installations will have something appropriate for large data sets such as yours. Each installation defines its own DATACLS names so your mainframe guys will have to dig them up for you. The SMS DATACLAS is specified using the FTP LOCSITE option: DATAC=xxx where xxx is the appropriate DATACLAS name.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top