Ошибка чтения набора данных (Sysout) после выполнения программы на языке COBOL
В программе rexx вызывается программа COBOL, и ее SYSOUT записывается с использованием временного выделения набора данных (TSO alloc), а затем с использованием чтения EXECIO. Работает обычно без проблем.
Один из наших пользователей (используя другую машину) сообщил о проблеме при чтении EXECIO.
IRX0562E Abnormal completion of the GET Data Management macro.
IRX0565E SG0 ,$LOGON ,3420,D,SYSOUT ,GET ,WRNG.LEN.RECORD,0000003500000 0,QSAM.
IEC020I 001-4,SG0,$LOGON,SYSOUT,3420,BWS858,
IEC020I SYS15089.T170858.RA000.SG0.R0278041
IEC020I DCB EROPT=ABE OR AN INVALID CODE, AND/OR NO SYNAD EXIT SPECIFIED
IRX0250E System abend code 001, reason code 00000004.
IRX0255E Abend in host command EXECIO or address environment routine MVS.
Я обнаружил, что эта проблема возникла именно тогда, когда программа COBOL имеет некоторые выходы на SYSOUT. Я мог воссоздать аналогичную ситуацию в моей системе z/OS, указав атрибут "VB" в распределении TSO. В этом случае выделенный набор данных не отображается в ISPF. Следующее сообщение об ошибке отображается при попытке просмотреть его в ISPF.
'I/O error occurred reading the edit data'
Если эти поврежденные данные распределяются в режиме SHARED/OLD, проблема решается. Таким образом, такая проблема возникает при новом размещении и во время выполнения программы на языке COBOL.
После выполнения программы на языке COBOL дальнейшее распределение режима SHR/OLD исправило эту проблему. Есть идеи, что именно пошло не так?
для тестовой версии я использую каталогизированный файл следующим образом. Ниже приведено распределение SYSOUT непосредственно перед выполнением программы на языке COBOL. Обратите внимание, что проблема возникает только тогда, когда я изменяю формат записи как "VB" (что является воссозданием той же ошибки, о которой сообщил пользователь на другом компьютере zos).
if (existDSN(tmpDS)), затем выполните ADDRESS TSO, /* Здесь это работает */ "ALLOC DS('"tmpDS"') F(SYSOUT) SHR REUSE" конец, иначе выполните ADDRESS TSO /* ошибка создания ds здесь */ "ALLOC DS('"tmpDS"') F(SYSOUT) NEW DSORG(PS)", "BLKSIZE(121) SPACE(5,15) TRACKS RECFM(F B A) DIR(0)"конец
обратите внимание, что каталогизированный набор данных SYSOUT даже не читается в режиме просмотра ISPF.
Ниже приведен вывод программы COBOL, упомянутой в bill, однако первая запись появляется дважды (т.е. всего 4 строки сообщения) в SYSOUT.
0000000121
4FFFFFFFFFF
00000000121
' ` expected message text
4070007004
00D0009000
2 ответа
Итак, вот что говорится в руководствах о вашей ситуации:
Enterprise COBOL Руководство по программированию
По умолчанию диагностические сообщения DFSORT отправляются в набор данных SYSOUT. Если вы хотите изменить это значение по умолчанию, используйте параметр MSGDDN карты управления DFSORT OPTION или специальный регистр SORT-MESSAGE.
Enterprise COBOL Language Reference
Вы можете использовать специальный регистр SORT-MESSAGE для указания ddname набора данных, который утилита сортировки должна использовать вместо набора данных SYSOUT. Имя dd, указанное в SORT-MESSAGE, эквивалентно имени, указанному в операторе управления "MSGDDN=" в файле управления сортировкой.
Руководство по программированию приложений DFSORT (мой акцент)
// SYSOUT DD
Идентифицирует набор данных сообщения DFSORT. По умолчанию ddname - это SYSOUT, но вы можете указать альтернативное ddname для набора данных сообщения, используя установку MSGDDN или опцию времени выполнения. Всегда предоставляйте оператор DD для набора данных сообщения, если каталогизированная процедура не используется. (Если вы вызываете DFSORT из программы COBOL и используете ddname SYSOUT для набора данных сообщения, использование DISPLAY в вашей программе COBOL может привести к неопределенным результатам печати.)
DFSORT использует RECFM=FBA, LRECL=121 и указанный BLKSIZE для набора данных сообщения. Если указанный вами BLKSIZE не кратен 121, DFSORT использует BLKSIZE=121. Если вы не укажете BLKSIZE, DFSORT выбирает размер блока в соответствии с параметром установки SDBMSG (см. Установка и настройка z/OS DFSORT). Если вы используете временный или постоянный набор данных сообщений, лучше всего указать расположение MOD, чтобы убедиться, что вы видите все сообщения и операторы управления в наборе данных сообщений.
А также:
MSGDDN
MSGDDN= DDNAME
Временно переопределяет параметр установки MSGDDN, в котором указывается альтернативное имя dd для набора данных сообщения. MSGDDN должен действовать, если:
v Программа, которая вызывает DFSORT, использует SYSOUT (например, COBOL использует SYSOUT), и вы не хотите, чтобы сообщения DFSORT смешивались с программными сообщениями.
v Ваши подпрограммы E15 и E35 написаны на языке COBOL, и вы не хотите, чтобы сообщения DFSORT смешивались с программными сообщениями.
v Программа вызывает DFSORT более одного раза, и вам нужны отдельные сообщения для каждого вызова DFSORT.
Ddname может быть любым именем от 1 до 8 символов, но должно быть уникальным на шаге задания; не используйте имя, которое используется DFSORT (например, SORTIN). Если указанное имя ddname недоступно во время выполнения, вместо него используется SYSOUT. Подробные сведения об использовании набора данных сообщений см. В Руководстве по сообщениям, кодам и диагностике z/OS DFSORT. Примечание. MSGDDN обрабатывается только в том случае, если он передан в оператор управления OPTION в расширенном списке параметров или в DFSPARM.
Что бы вы ни делали, несмотря на рекомендации в руководствах, это смешанный вывод SYSOUT из COBOL и DFSORT (в действительности, множественные вызовы DFSORT). Вы сделали это, направив SYSOUT в последовательный набор данных с характеристиками, отличными от тех, которые использует DFSORT. Поскольку DFSORT всегда будет выводить сообщения, ваш набор данных гарантированно будет поврежден, если программа COBOL использовала хотя бы на DISPLAY во время выполнения.
Если бы вы направили SYSOUT DD в набор данных SYSOUT= (спул) в любой момент во время тестирования (я бы предположил, что примерно 100% людей так делают), вы бы заметили смешанный вывод в наборе данных SYSOUT для этот шаг. Я не уверен, как бы это выглядело (никогда бы не сделал этого или не знал, что это будет сделано), но вы смогли бы по крайней мере определить источник многократного использования (та же самая программа на языке COBOL, выполняющая свои собственные ДИСПЛЕИ, а также делает несколько внутренних сортировок).
Вы решили свою проблему с помощью MSGDD = DFSORT, чтобы изменить вывод DD по умолчанию (SYSOUT).
Стоит отметить, что вы также можете изменить имя DD, используемого для COBOL DISPLAY, с его значения по умолчанию (SYSOUT) на другое, с опцией компилятора OUTDD(somedd).
Языковая среда также использует SYSOUT по умолчанию, но вы можете использовать опцию времени выполнения MSGFILE, чтобы изменить это (параметры времени запуска LE могут быть установлены различными способами, обратитесь к документации по языковой среде (я считаю, что проще всего //CEEDOPT DD
в JCL для пакетной программы).
Обеспечение того, чтобы файлы, которые выделены для одного выполнения программы из программы Rexx, затем впоследствии перераспределялось, а имена наборов данных не использовались повторно - это то, что нужно наблюдать каждый раз. Убедитесь, что вы всегда проверяете RC, всякий раз, когда что-то может установить RC. Не указывайте параметры для заявлений, которые не требуются.
Вот ваши данные, показанные вами до того, как я вставил их в ваш вопрос из предоставленной мною программы:
0000000121
4FFFFFFFFFF
00000000121
' ` expected message text
4070007004
00D0009000
Вторая попытка:
ожидаемый текст сообщения
44
00
Я не уверен, что означает "ожидаемый текст сообщения", ни "первая запись появляется дважды", ни "всего 4 строки сообщения".
Данные не выстроены в очередь. В вашем вопросе я исправил часть 0000000121, но не другую запись.
Игнорируя "ожидаемый текст сообщения", вы показываете две записи данных в "шестнадцатеричном" формате (установите HEX ON в SDSF, если вы используете это для просмотра вывода спула).
Первый пробел может быть артефактом SDSF. Когда вы впервые посмотрите на файл спула, если вы посмотрите на COLS, вы увидите, что данные начинаются со второго столбца. Если вы переместите свой экран влево, вы увидите первый столбец, который не является данными.
Итак, мы можем догадаться, что у вас на самом деле есть две записи. Тот, который состоит из 10 зонно-десятичных цифр (или "символа"), и тот, который совершенно определенно не совпадает.
Первая запись выглядит как запись фиксированной длины, 10 байтов. Второй выглядит живой записи переменной длины. Фактически это блок данных переменной длины.
Этот файл, с абсолютной уверенностью, даст вам "запись неправильной длины".
Однако, даже учитывая это, есть что-то не совсем правильное в том, что вы показываете. Я думаю, что то, что вы сделали, не скопировало все конечные пробелы.
Мы знаем, что у вас LRECL 121, а для записей фиксированной длины это означает, что записи будут иметь длину 121 байт, а вы покажете 10 байт. ОК, можно написать что-то переопределив длину до 10.
Однако для данных переменной длины это выглядит так
X'007D' = длина блока, 125 байтов, первая половина слова дескриптора блока (BDW), включая длину (четыре) BDW. X'0000' = вторая половина BDW X'0079' = длина записи, 121 байт, первая половина слова дескриптора записи (RDW), включая длину (четыре) RDW. 121 байт данных, которые вы показываете как X'40'. Итак, давайте предположим 121 байт пространства.
Поэтому давайте вернемся и предположим, что запись фиксированной длины составляет 121 байт с конечными пробелами. Видя, что в вашем "ответе" первая "строка" не была выровнена, мы можем предположить, что вы внесли корректировку для первого пробела, а также для второй записи.
Откуда еще не ясно, но ваш файл определенно "смесь". У вас есть одна запись фиксированной длины, а затем один блок переменной длины (содержащий только одну запись). Вам нужно вставить именно то, что вы видите, как только вы выбрали буферный файл, выход выводится в шестнадцатеричном режиме. Весь путь слева направо от вашего экрана. Копировать / вставить, а не скринпринт.
Как вы думаете, это правильная линия? Заготовки или 0000000121?
ОК, работать еще не над чем:-)
Ваша проблема с tmpDS
, Не могу увидеть содержание этого, но это проблема.
У него есть название, которое выглядит очень временным, но контент делает вещи намного более постоянными, чем вы ожидаете.
В то время, когда пользователь, получивший ошибку, находится в вашей системе и запускает программу COBOL, файл, набор данных с таким точным именем, уже существует в системе. COBOL просто блефует, вероятно, с помощью FBA 121. Если файл, который использовался ранее, был чем-то отличным от того, с чем это связано с COBOL, вы получите точную ситуацию, которую вы детализируете.
Есть несколько возможностей, как это произошло. Использовать одно и то же имя в разных программах rexx проще всего. Префикс его с помощью идентификатора пользователя TSO может частично помочь, но вам нужно либо позволить системе выбрать имя, либо сгенерировать его самостоятельно, чтобы оно не могло дублироваться.
Не могу быть уверен в этом, не увидев ваш код. Только на 99,3% уверен, пока не скажешь иначе:-)
Вот короткая программа, которую вы можете использовать, чтобы прочитать файл и посмотреть, что там находится:
ID DIVISION.
PROGRAM-ID. STOB26.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO INFILE
FILE STATUS IS W-FILE-STATUS.
DATA DIVISION.
FILE SECTION.
FD IN-FILE
RECORD IS VARYING
DEPENDING ON W-REC-LENGTH
RECORDING MODE U.
01 IN-REC.
05 FILLER OCCURS 1 TO 32760 TIMES
DEPENDING ON W-REC-LENGTH PIC X.
WORKING-STORAGE SECTION.
01 W-FILE-STATUS PIC XX.
88 FILE-STATUS-GOOD VALUE "00".
88 FILE-STATUS-OK-FOR-INPUT VALUE "00" "10".
88 END-OF-FILE VALUE "10".
01 W-REC-LENGTH PIC 9(8) COMP.
PROCEDURE DIVISION.
DISPLAY 'Start of program'
OPEN INPUT IN-FILE
IF NOT FILE-STATUS-GOOD
DISPLAY
'OPEN FAILED'
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
PERFORM UNTIL END-OF-FILE
READ IN-FILE
IF NOT FILE-STATUS-OK-FOR-INPUT
DISPLAY
"READ FAILED"
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
DISPLAY
'Record length is>'
W-REC-LENGTH
'<'
DISPLAY
'Data is>'
IN-REC
'<'
END-PERFORM
CLOSE IN-FILE
IF NOT FILE-STATUS-GOOD
DISPLAY
'CLOSE FAILED'
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
DISPLAY 'End of program'
GOBACK
.
JCL очень прост и может быть основан на этом:
//RUNIT EXEC PGM=VARA,TIME=(,2)
//STEPLIB DD DSN=loadlibrary,DISP=SHR
//SYSOUT DD SYSOUT=*
//INFILE DD DSN=yourbusteddsn,LRECL=32760,RECFM=U,DISP=SHR
Как я и подозревал, это как-то связано с сообщениями sysout DFSORT. После перенаправления сообщений DFSORT в другой набор данных с помощью параметра DFSPARM эта проблема была решена. Я мог бы сделать это, выделив DFSPARM ddname, которое соответствует набору данных, который содержит
MSGDDN=dfsoutdd
Эта проблема возникает и в пакетном режиме, т. Е. Не имеет ничего общего с программой TSO alloc или rexx. Подводя итог, проблема возникает, когда
- Программа COBOL имеет внутренние SORTS и, таким образом, выдает сообщения DFSORT на SYSOUT
- Сама программа COBOL имеет один или несколько текстовых дисплеев
- Когда SYSOUT направляется на DSN с DISP=NEW(SYSOUT на спуле SDSF в порядке)
Еще одно наблюдение состоит в том, что DFSORT вызывает изменение атрибута набора данных после выполнения программы. До
Organization . . . : PS Used tracks . . . . : 1
Record format . . . : VB Used extents . . . : 1
Record length . . . : 121
Block size . . . . : 27998
1st extent tracks . : 1
После
Organization . . . : PS Used tracks . . . . : 1
Record format . . . : FBA Used extents . . . : 1
Record length . . . : 121
Block size . . . . : 121
1st extent tracks . : 1
Secondary tracks . : 1