O GDGBIAS é um parâmetro de JCL que pode passar despercebido à primeira vista mas que pode mudar o significado e comportamento de todo um Job.
Se um job cria e mais tarde reutiliza um data set referido através de MY.GDG(+1), podemos colocar a seguinte questão:
- Os steps posteriores devem continuar a usar o mesmo mapeamento relativo-para-absoluto estabelecido anteriormente no job?
- Ou o z/OS deve recalcular os mapeamentos, por exemplo, de
(0)e(+1)em cada novo job step?
Este artigo discute o efeito do GDGBIAS e mostra JCL que pode submeter para observar como GDGBIAS=JOB e GDGBIAS=STEP se comportam de forma diferente.
1. Objetivos do laboratório
No fim do artigo deverá ser capaz de:
- Explicar a diferença entre
GDGBIAS=JOBeGDGBIAS=STEP - Prever como
(0)e(+1)são resolvidos depois de um step anterior catalogar uma nova geração - Construir um pequeno GDG de teste e reproduzir a diferença em batch
- Reconhecer porque
VOL=REF, passed data sets e alterações de catálogo feitas por utilitários tornam esta escolha mais importante
2. Ambiente necessário
Para a parte prática, use:
- z/OS 2.1 ou posterior
- JES2 ou JES3
3. Introdução
O z/OS mantém um mapeamento interno entre uma referência relativa a um GDG e o nome absoluto da geração que será realmente alocada.
Se assumir que o catálogo contém atualmente a geração corrente
&SYSUID..GDGTEST.BASE.G0010V00então os nomes relativos são resolvidos da seguinte forma:
(0)é mapeado paraG0010V00(a menos que exista uma versãoVnncomnn > 00)(+1)é mapeado para a geração seguinte, por exemploG0011V00
A questão é: o que ´que acontece depois de um step do mesmo job catalogar a geração G0011V00? E aqui o valor de GDGBIAS passa a importar. GDGBIAS aceita dois valores (JOB e STEP) que produzem comportamentos diferentes:
| Atributo | GDGBIAS=JOB | GDGBIAS=STEP |
|---|---|---|
| Ponto de resolução | Primeira referência ao GDG no job | Início de cada step |
| Persistência do mapeamento | Preservado nos steps seguintes | Reconstruído em cada fronteira entre steps |
Significado de (0) no Step 2 depois de o Step 1 criar (+1) | Continua a ser a geração que era corrente antes do Step 1 | Passa a ser a geração acabada de criar no Step 1 |
Significado de (+1) no Step 2 depois de o Step 1 criar (+1) | Continua a ser a geração criada anteriormente no job | Passa a ser uma nova geração ainda não criada |
Isto significa que GDGBIAS=JOB mantém consistência entre steps dentro do mesmo job, enquanto GDGBIAS=STEP força uma nova avaliação contra o estado atual do catálogo em cada step.
4. Preparação prática: definir um GDG descartável para teste
Antes de comparar os dois modos de GDGBIAS, crie uma pequena base GDG e uma geração inicial. Copie e submeta o JCL abaixo (pode ser necessário ajustar o JOB card aos requisitos da sua instalação):
//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 com ISPF 3.4 ou LISTCAT. Nesta fase deverá ter exatamente uma geração corrente sob a 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. Comportamento de GDGBIAS=JOB
Submeta um job com dois steps que:
1. Cria uma nova geração (+1) 2. No step seguinte, tenta ler (+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 DUMMYO resultado esperado é que STEP1 catalogue uma nova geração e STEP2 termine com sucesso porque:
- Em
GDGBIAS=JOB, o mapeamento relativo construído anteriormente no job mantém-se em vigor - O
(+1)emSTEP2continua a mapear para a geração absoluta criada emSTEP1
Este é o comportamento clássico em que os mapeamentos são estabelecidos para o job e mantidos desde aí.
7. Comportamento de GDGBIAS=STEP
Submeta agora o mesmo JCL mas com GDGBIAS ao nível do 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 DUMMYDesta vez, STEP1 termina com sucesso e cataloga uma nova geração, mas STEP2 falhará a alocação. Porquê?
- Como
GDGBIAS=STEP, o z/OS limpa o mapeamento anterior ao transitar entre steps - Quando
STEP2começa, a geração criada emSTEP1passou a ser o novo(0) (+1)passa a significar a próxima geração ainda não criadaDISP=SHRsobre uma geração que ainda não existe provoca a falha
8. Vamos provar que (0) também muda com GDGBIAS=STEP
Os dois jobs anteriores mostram o efeito sobre (+1). O próximo par mostra o efeito sobre (0). Começa por criar a nova geração:
//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=SYSDADepois compare estes dois Jobs que efetuarão a leitura.
JCL com 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 com GDGBIAS=STEP num fluxo com vários 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 DUMMYO que observar:
- Em
JOB,(0)num step posterior continua a significar a geração que era corrente antes da primeira resolução da base no job - Em
STEP,(0)no step posterior passa a significar a geração criada porSTEP1
Esta distinção importa sempre que um job espera que “corrente” signifique “corrente quando o job começou” em vez de “corrente agora”.
9. Caso avançado 1: o paradoxo de VOL=REF
A cláusula VOL=REF pode surpreender, porque não se comporta como uma referência GDG DSN normal. O risco prático é este:
- Com
GDGBIAS=JOB, uma referênciaDSN=base(+1)pode continuar a referir a mesma geração absoluta criada antes no job - Mas uma referência
VOL=REFpode continuar a ser resolvida a partir do estado do catálogo no início do step, em vez do mapeamento GDG ao nível do job que esperava
Considere o seguinte 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=*.IN1Muitas pessoas assumem que IN1 está a reabrir a geração criada em STEP1 e que qualquer herança de volume baseada nessa intenção lógica deveria manter-se alinhada
Essa suposição não é, no entanto, garantida quando há GDGs envolvidos. A regra prática mais segura é:
- Se precisar de herdar o volume de um data set criado anteriormente no mesmo job, prefira uma referência concreta como
VOL=REF=*.stepname.ddname - Não assuma que
VOL=REF=MY.GDG(+1)se comportará como a referência de DSN estável entre steps que tinha em mente
10. Caso avançado 2: contaminação por concorrência entre jobs
Uma diferença arquitetural importante entre GDGBIAS JOB e GDGBIAS STEP aparece quando outro workload atualiza a mesma base GDG enquanto o seu job ainda está em execução.
Com GDGBIAS=JOB:
- O seu job trabalha efetivamente com um mapeamento interno “congelado” assim que a base é resolvida pela primeira vez
- Atualizações externas posteriores ao catálogo não impactam as referências relativas já estabelecidas
Com GDGBIAS=STEP:
- Cada transição entre steps inicia uma nova consulta ao catálogo
- Se outro job catalogar uma nova geração entre o seu
STEP1eSTEP2, o seuSTEP2pode herdar essa nova baseline
Isto significa que GDGBIAS=STEP não é apenas “mais atual”. O seu Job também fica exposto a atividade externa concorrente que modifique o catálogo.
Consequência prática:
- Se o seu JCL assume que as referências
(+1)devem ser estáveis, resolvendo para o mesmo data set, use GDGBIAS=JOB - Se o seu JCL pretende reflectir o estado atual do catálogo em cada step,
STEPserá a escolha correta
11. Caso avançado 3: perda de sincronização com o catálogo provocada por utilitários
Se um step usa um utilitário como IDCAMS para manipular diretamente entradas de GDG, pode alterar o catálogo de uma forma que não é equivalente à sequência normal de alocação JCL.
Por exemplo:
//FIXCAT EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE &SYSUID..GDGTEST.BASE(0)
/*Porque é que isto importa:
- Com
GDGBIAS=JOB, os steps JCL posteriores podem continuar a trabalhar a partir do mapeamento interno anterior, mesmo que o catálogo tenha sido entretanto mudado, o que poderá originar erros - Com
GDGBIAS=STEP, a transição para o step seguinte força uma nova pesquisa e reflete naturalmente o estado atual do catálogo
Este é um dos poucos casos em que GDGBIAS=STEP pode parecer “auto-corrigível”, enquanto JOB pode tornar-se desadequado. A mesma persistência que protege um job de interferência externa também pode preservar um mapeamento que já não coincide com o catálogo real depois de alterações feitas por utilitários.
12. Passed data sets: padrões seguros e inseguros
Quando a geração criada é passada para o step seguinte em vez de ser reaberta a partir do catálogo, o padrão mais seguro é usar VOL=REF em vez de usar o nome relativo no 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 DUMMYPorque é que é mais seguro:
- O step recetor usa diretamente o passed data set
- Não depende de recalcular a numeração relativa do GDG após uma fronteira entre steps
Alternativa menos segura sob GDGBIAS=STEP:
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE(+1),DISP=SHRSe a geração foi catalogada antes do início do step recetor, esse (+1) já não apontará para o ficheiro pretendido.
A regra prática é simples:
- Se estiver a passar uma geração GDG entre steps, prefira
*.step.ddem vez de voltar a derivar o alvo a partir de uma referência GDG relativa
13. Concatenações GDG ALL
Referenciar o nome base do GDG sem uma geração relativa explícita produz uma alocação GDG ALL.
Exemplo:
//READALL EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DSN=&SYSUID..GDGTEST.BASE,DISP=SHR
//SYSUT2 DD SYSOUT=*
//SYSIN DD DUMMYIsto diz ao z/OS para construir uma concatenação de gerações ativas da base.
Porque GDGBIAS importa aqui:
- Com GDGBIAS=
JOB, a lista lógica por trás dessa concatenação fica ligada à visão GDG estabelecida anteriormente no job - Em GDGBIAS=
STEP, a concatenação é reconstruída a partir da visão atual do catálogo no início do step
Assim, se um step anterior catalogar uma nova geração:
- GDGBIAS=
JOBtende a manter estável a visão anterior da concatenação - GDGBIAS=
STEPtende a incluir automaticamente a geração mais recente na visão GDG ALL do step seguinte
Isto importa em jobs de reporting ou replay onde um nome base sem geração explícita é usado como atalho para “todas as gerações correntes”.
14. Restarts diferidos de step
O comportamento em restart é outro ponto importante a ter em conta.
Com GDGBIAS=JOB:
- A execução reiniciada reconstrói a sua visão em memória a partir do estado do catálogo existente no momento do restart
- Se steps anteriores na execução inicial já catalogaram novas gerações, essa baseline no momento do restart pode diferir da baseline assumida pelo fluxo original não reiniciado
Com GDGBIAS=STEP:
- A entrada direta para um step já parte do princípio de um modelo de recálculo das referências
- O comportamento em restart fica por isso naturalmente mais alinhado com o desenho deste modo
Isto não significa que STEP seja sempre melhor para restart. Significa que STEP é normalmente mais intuitivo quando se espera que o restart siga o estado atual do catálogo sem exigência de cálculos manuais de offset.
15. Como escolher
Se tivermos de reduzir a decisão a uma frase:
- Escolha
JOBquando o job precisa de um snapshot interno estável - Escolha
STEPquando o job deve voltar a ligar-se ao catálogo vivo em cada fronteira entre steps
Use GDGBIAS=JOB quando:
- O job deve operar sobre um snapshot estável da numeração relativa do GDG dentro do próprio job
- Os steps posteriores têm de continuar a referir exatamente as mesmas gerações absolutas escolhidas antes no fluxo
- Atualizações externas concorrentes ao catálogo não devem mudar o significado das referências relativas a meio do run
Use GDGBIAS=STEP quando:
- Cada step deve refletir o estado atual do catálogo
- Processamento orientado a utilitários ou restart beneficia de uma reavaliação em cada fronteira entre steps
- Está preparado para que
(0)e(+1)mudem depois de atividade intermédia no catálogo
16. Codificação e âmbito
O GDGBIAS pode ser controlado a vários níveis:
- Valor por omissão do JES ou da job class (
JOBCLASS(n) GDGBIAS=...) - Override explícito na instrução
JOB
//DAILYJOB JOB (ACCT),'DATA PROCESSING',CLASS=A,GDGBIAS=STEPO operador pode alterar dinamicamente a configuração da job class no JES:
$T JOBCLASS(A),GDGBIAS=STEPSe omitir o parâmetro, aplica-se o valor por omissão do sistema ou da job class.
17. O que importa reter
A regra prática mais importante é simples:
GDGBIAS=JOBcongela o significado relativo do GDG dentro do jobGDGBIAS=STEPrecalcula o significado relativo do GDG em cada transição entre steps
É por isso que GDGBIAS deve fazer parte do desenho arquitetural de um fluxo de job batch, e não ser uma decisão de última hora de codificação do job card.
18. Documentação IBM útil
Estas referências são úteis para obter informação 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