GDGBIAS es un parámetro de JCL que puede pasar desapercibido a primera vista, pero que puede cambiar el significado y el comportamiento de todo un job.
Si un job crea y más tarde reutiliza un data set referido como MY.GDG(+1), podemos plantear la siguiente cuestión:
- ¿Los steps posteriores deben seguir usando el mismo mapeo relativo-a-absoluto establecido anteriormente en el job?
- ¿O z/OS debe recalcular los mapeos, por ejemplo de
(0)y(+1), en cada nuevo job step?
Este artículo analiza el efecto de GDGBIAS y muestra JCL que puede enviar para observar cómo GDGBIAS=JOB y GDGBIAS=STEP se comportan de forma diferente.
1. Objetivos del laboratorio
Al final del artículo debería poder:
- Explicar la diferencia entre
GDGBIAS=JOByGDGBIAS=STEP - Predecir cómo se resuelven
(0)y(+1)después de que un step anterior catalogue una nueva generación - Construir un pequeño GDG de prueba y reproducir la diferencia en batch
- Reconocer por qué
VOL=REF, los passed data sets y los cambios de catálogo realizados por utilidades hacen más importante esta elección
2. Entorno necesario
Para la parte práctica, use:
- z/OS 2.1 o posterior
- JES2 o JES3
3. Introducción
z/OS mantiene un mapeo interno entre una referencia relativa a un GDG y el nombre absoluto de la generación que realmente se asignará.
Si asumimos que el catálogo contiene actualmente la generación corriente
&SYSUID..GDGTEST.BASE.G0010V00entonces los nombres relativos se resuelven de la siguiente forma:
(0)se asigna aG0010V00(a menos que exista una versiónVnnconnn > 00)(+1)se asigna a la generación siguiente, por ejemploG0011V00
La cuestión es: ¿qué ocurre después de que un step del mismo job catalogue la generación G0011V00? Ahí es donde el valor de GDGBIAS pasa a importar. GDGBIAS acepta dos valores (JOB y STEP) que producen comportamientos distintos:
| Atributo | GDGBIAS=JOB | GDGBIAS=STEP |
|---|---|---|
| Punto de resolución | Primera referencia al GDG en el job | Inicio de cada step |
| Persistencia del mapeo | Se conserva en los steps siguientes | Se reconstruye en cada frontera entre steps |
Significado de (0) en el Step 2 después de que el Step 1 cree (+1) | Sigue siendo la generación que era corriente antes del Step 1 | Pasa a ser la generación recién creada en el Step 1 |
Significado de (+1) en el Step 2 después de que el Step 1 cree (+1) | Sigue siendo la generación creada anteriormente en el job | Pasa a ser una nueva generación aún no creada |
Esto significa que GDGBIAS=JOB mantiene consistencia entre steps dentro del mismo job, mientras que GDGBIAS=STEP fuerza una nueva evaluación contra el estado actual del catálogo en cada step.
4. Preparación práctica: definir un GDG desechable para pruebas
Antes de comparar los dos modos de GDGBIAS, cree una pequeña base GDG y una generación inicial. Copie y envíe el JCL siguiente (puede ser necesario ajustar la JOB card a los requisitos de su instalación):
//GDGPREP JOB ,'GDG PREP',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//DELETE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE &SYSUID..GDGTEST.BASE GDG FORCE
IF LASTCC LE 8 THEN SET MAXCC = 0
/*
//DEFINE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE GDG (NAME(&SYSUID..GDGTEST.BASE) LIMIT(5) NOEMPTY SCRATCH)
/*
//SEED EXEC PGM=IEFBR14
//G0001 DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDAVerifique con ISPF 3.4 o LISTCAT. En este punto debería tener exactamente una generación corriente bajo la base:
//GDGLIST JOB ,'GDG LIST',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//LISTCAT EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES(&SYSUID..GDGTEST.BASE) ALL
/*6. Comportamiento de GDGBIAS=JOB
Envíe un job con dos steps que:
1. Cree una nueva generación (+1) 2. En el step siguiente, intente leer (+1) como data set catalogado
//GDGJOB JOB ,'GDG JOB BIAS',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=JOB
//STEP1 EXEC PGM=IEFBR14
//NEWGEN DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDA
//STEP2 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(+1),DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYEl resultado esperado es que STEP1 catalogue una nueva generación y que STEP2 termine correctamente porque:
- En
GDGBIAS=JOB, el mapeo relativo construido anteriormente en el job se mantiene vigente - El
(+1)enSTEP2sigue mapeando a la generación absoluta creada enSTEP1
Este es el comportamiento clásico en el que los mapeos se establecen para el job y se mantienen a partir de ahí.
7. Comportamiento de GDGBIAS=STEP
Envíe ahora el mismo JCL pero con GDGBIAS a nivel de step:
//GDGSTEP JOB ,'GDG STEP BIAS',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=STEP
//STEP1 EXEC PGM=IEFBR14
//NEWGEN DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDA
//STEP2 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(+1),DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYEsta vez, STEP1 termina correctamente y cataloga una nueva generación, pero STEP2 fallará la asignación. ¿Por qué?
- Como
GDGBIAS=STEP, z/OS limpia el mapeo anterior al pasar de un step a otro - Cuando
STEP2empieza, la generación creada enSTEP1ya se ha convertido en el nuevo(0) (+1)pasa a significar la siguiente generación aún no creadaDISP=SHRsobre una generación que todavía no existe provoca el fallo
8. Vamos a demostrar que (0) también cambia con GDGBIAS=STEP
Los dos jobs anteriores muestran el efecto sobre (+1). El siguiente par muestra el efecto sobre (0). Empiece creando la nueva generación:
//GDGMAKE JOB ,'GDG MAKE',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//STEP1 EXEC PGM=IEFBR14
//NEWGEN DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDADespués compare estos dos jobs que efectuarán la lectura.
JCL con GDGBIAS=JOB:
//READJOB JOB ,'READ JOB',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=JOB
//STEP1 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(0),DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYJCL con GDGBIAS=STEP en un flujo con varios steps:
//READSTEP JOB ,'READ STEP',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=STEP
//STEP1 EXEC PGM=IEFBR14
//NEWGEN DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDA
//STEP2 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(0),DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYQué debe observar:
- En
JOB,(0)en un step posterior sigue significando la generación que era corriente antes de la primera resolución de la base en el job - En
STEP,(0)en el step posterior pasa a significar la generación creada porSTEP1
Esta distinción importa siempre que un job espere que “corriente” signifique “corriente cuando empezó el job” en lugar de “corriente ahora”.
9. Caso avanzado 1: la paradoja de VOL=REF
La cláusula VOL=REF puede sorprender, porque no se comporta como una referencia GDG DSN normal. El riesgo práctico es este:
- Con
GDGBIAS=JOB, una referenciaDSN=base(+1)puede seguir refiriéndose a la misma generación absoluta creada antes en el job - Pero una referencia
VOL=REFpuede seguir resolviéndose a partir del estado del catálogo al principio del step, en lugar del mapeo GDG a nivel de job que usted esperaba
Considere el siguiente job:
//GDGVREF JOB ,'VOL REF',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=JOB
//STEP1 EXEC PGM=IEFBR14
//OUT1 DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDA
//STEP2 EXEC PGM=IEFBR14
//IN1 DD DSN=&SYSUID..GDGTEST.BASE(+1),DISP=SHR
//VOLX DD DSN=&SYSUID..GDGTEST.WORK,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(TRK,(1,1)),
// VOL=REF=*.IN1Mucha gente asume que IN1 está reabriendo la generación creada en STEP1 y que cualquier herencia de volumen basada en esa intención lógica debería mantenerse alineada.
Sin embargo, esa suposición no está garantizada cuando hay GDGs implicados. La regla práctica más segura es:
- Si necesita heredar el volumen de un data set creado anteriormente en el mismo job, prefiera una referencia concreta como
VOL=REF=*.stepname.ddname - No suponga que
VOL=REF=MY.GDG(+1)se comportará como la referencia de DSN estable entre steps que tenía en mente
10. Caso avanzado 2: contaminación por concurrencia entre jobs
Una diferencia arquitectónica importante entre GDGBIAS JOB y GDGBIAS STEP aparece cuando otro workload actualiza la misma base GDG mientras su job todavía está en ejecución.
Con GDGBIAS=JOB:
- Su job trabaja efectivamente con un mapeo interno “congelado” en cuanto la base se resuelve por primera vez
- Las actualizaciones externas posteriores del catálogo no impactan las referencias relativas ya establecidas
Con GDGBIAS=STEP:
- Cada transición entre steps inicia una nueva consulta al catálogo
- Si otro job cataloga una nueva generación entre su
STEP1y suSTEP2, suSTEP2puede heredar esa nueva baseline
Esto significa que GDGBIAS=STEP no es solo “más actual”. Su job también queda expuesto a actividad externa concurrente que modifique el catálogo.
Consecuencia práctica:
- Si su JCL asume que las referencias
(+1)deben ser estables y resolver al mismo data set, use GDGBIAS=JOB - Si su JCL pretende reflejar el estado actual del catálogo en cada step,
STEPserá la opción correcta
11. Caso avanzado 3: pérdida de sincronización con el catálogo provocada por utilidades
Si un step usa una utilidad como IDCAMS para manipular directamente entradas de GDG, puede cambiar el catálogo de una forma que no equivale a la secuencia normal de asignación JCL.
Por ejemplo:
//FIXCAT EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE &SYSUID..GDGTEST.BASE(0)
/*¿Por qué importa esto?
- Con
GDGBIAS=JOB, los steps JCL posteriores pueden seguir trabajando a partir del mapeo interno anterior, aunque el catálogo haya sido cambiado entretanto, lo que puede originar errores - Con
GDGBIAS=STEP, la transición al step siguiente fuerza una nueva búsqueda y refleja de forma natural el estado actual del catálogo
Este es uno de los pocos casos en los que GDGBIAS=STEP puede parecer “autocorrectivo”, mientras que JOB puede volverse inadecuado. La misma persistencia que protege un job de interferencia externa también puede conservar un mapeo que ya no coincide con el catálogo real después de cambios realizados por utilidades.
12. Passed data sets: patrones seguros e inseguros
Cuando la generación creada se pasa al step siguiente en lugar de reabrirse desde el catálogo, el patrón más seguro es usar VOL=REF en lugar de usar el nombre relativo del GDG.
//PASSJOB JOB ,'PASS GDG',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID,
// GDGBIAS=STEP
//STEP1 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD *
STEP1 WRITES THIS RECORD
/*
//SYSUT2 DD DSN=&SYSUID..GDGTEST.BASE(+1),
// DISP=(NEW,PASS,DELETE),
// SPACE=(TRK,(1,1)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0),
// UNIT=SYSDA
//SYSIN DD DUMMY
//STEP2 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=*.STEP1.SYSUT2,DISP=OLD
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMY¿Por qué es más seguro?
- El step receptor usa directamente el passed data set
- No depende de recalcular la numeración relativa del GDG después de una frontera entre steps
Alternativa menos segura bajo GDGBIAS=STEP:
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(+1),DISP=SHRSi la generación fue catalogada antes del inicio del step receptor, ese (+1) ya no apuntará al archivo pretendido.
La regla práctica es simple:
- Si está pasando una generación GDG entre steps, prefiera
*.step.dden lugar de volver a derivar el destino a partir de una referencia GDG relativa
13. Concatenaciones GDG ALL
Referenciar el nombre base del GDG sin una generación relativa explícita produce una asignación GDG ALL.
Ejemplo:
//READALL EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE,DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYEsto indica a z/OS que construya una concatenación de generaciones activas de la base.
Por qué GDGBIAS importa aquí:
- Con GDGBIAS=
JOB, la lista lógica detrás de esa concatenación queda ligada a la visión GDG establecida anteriormente en el job - En GDGBIAS=
STEP, la concatenación se reconstruye a partir de la visión actual del catálogo al inicio del step
Así, si un step anterior cataloga una nueva generación:
- GDGBIAS=
JOBtiende a mantener estable la visión anterior de la concatenación - GDGBIAS=
STEPtiende a incluir automáticamente la generación más reciente en la visión GDG ALL del step siguiente
Esto importa en jobs de reporting o replay donde un nombre base sin generación explícita se usa como atajo para “todas las generaciones corrientes”.
14. Restarts diferidos de step
El comportamiento en restart es otro punto importante que conviene tener en cuenta.
Con GDGBIAS=JOB:
- La ejecución reiniciada reconstruye su visión en memoria a partir del estado del catálogo existente en el momento del restart
- Si steps anteriores de la ejecución inicial ya habían catalogado nuevas generaciones, esa baseline en el momento del restart puede diferir de la baseline asumida por el flujo original no reiniciado
Con GDGBIAS=STEP:
- La entrada directa a un step ya parte de un modelo de recálculo de referencias
- El comportamiento en restart queda por ello naturalmente más alineado con el diseño de este modo
Esto no significa que STEP sea siempre mejor para restart. Significa que STEP suele ser más intuitivo cuando se espera que el restart siga el estado actual del catálogo sin exigir cálculos manuales de offset.
15. Cómo elegir
Si tuviéramos que reducir la decisión a una frase:
- Elija
JOBcuando el job necesite una instantánea interna estable - Elija
STEPcuando el job deba volver a enlazarse con el catálogo activo en cada frontera entre steps
Use GDGBIAS=JOB cuando:
- El job deba operar sobre una instantánea estable de la numeración relativa del GDG dentro del propio job
- Los steps posteriores deban seguir refiriéndose exactamente a las mismas generaciones absolutas elegidas antes en el flujo
- Las actualizaciones externas concurrentes del catálogo no deban cambiar el significado de las referencias relativas a mitad de la ejecución
Use GDGBIAS=STEP cuando:
- Cada step deba reflejar el estado actual del catálogo
- Un procesamiento orientado a utilidades o restart se beneficie de una reevaluación en cada frontera entre steps
- Esté preparado para que
(0)y(+1)cambien después de actividad intermedia en el catálogo
16. Codificación y alcance
GDGBIAS puede controlarse a varios niveles:
- Valor por omisión de JES o de la job class (
JOBCLASS(n) GDGBIAS=...) - Override explícito en la sentencia
JOB
//DAILYJOB JOB (ACCT),'DATA PROCESSING',CLASS=A,GDGBIAS=STEPEl operador puede cambiar dinámicamente la configuración de la job class en JES:
$T JOBCLASS(A),GDGBIAS=STEPSi omite el parámetro, se aplicará el valor por omisión del sistema o de la job class.
17. Qué conviene retener
La regla práctica más importante es simple:
GDGBIAS=JOBcongela el significado relativo del GDG dentro del jobGDGBIAS=STEPrecalcula el significado relativo del GDG en cada transición entre steps
Por eso GDGBIAS debe formar parte del diseño arquitectónico de un flujo de job batch, y no ser una decisión de última hora al codificar la job card.
18. Documentación útil de IBM
Estas referencias son útiles para obtener información adicional:
- z/OS JCL Reference: JOB statement
- z/OS JCL parameter field summary
- z/OS JES2 command reference:
$T JOBCLASS - z/OS JES2 command reference:
$ADD JOBCLASS - z/OS JES2 job class overview
- z/OS DFSMS: Creating a non-SMS-managed generation data set
- z/OS DFSMS Access Method Services: DEFINE GENERATIONDATAGROUP
- z/OS basic concepts: What is a generation data group?
- z/OS message reference: IEFA111I