Search code examples
splitmainframe

Why SPLIT to multiple members belonging to the same PDS makes clone members?


I'm currently learning JCL and I'm playing with the SORT program. As an exercise, I wanted to split some input records into multiple members belonging to the same PDS. Here my JCL code:

//FAILJ    JOB
//STEP1    EXEC PGM=SORT
//SORTIN   DD *
I
B
D
A
E
F
G
C
H
//SORTOUT  DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//MEMA     DD DSN=MY.PDS(MEMA),DISP=OLD
//MEMB     DD DSN=MY.PDS(MEMB),DISP=OLD
//SYSIN    DD *
 SORT FIELDS=(1,1,CH,A)
 OUTFIL FNAMES=(MEMA,MEMB),SPLIT

This code produces two members called MY.PDS(MEMA) and MY.PDS(MEMB) containing the same set of records, which is unexpected to me:

B
D
F
H

The expected result for MY.PDS(MEMA) was:

A
C
E
G
I

My question is not "How to fix?", but why this behaviour and how it works internally? I'm using the Hercules mainframe emulator. Is it different on a real mainframe?


Solution

  • I think it's always good to try to isolate a particular problem, especially when learning, so let's take SORT out of the picture and write a short ASM program, such as this snip:

              OPEN  (MEMA,OUTPUT)
              OPEN  (MEMB,OUTPUT)
              PUT   MEMA,RECA    
              PUT   MEMB,RECB    
              CLOSE (MEMA)       
              CLOSE (MEMB)
    ...
    MEMA     DCB   DDNAME=MEMA,LRECL=80,RECFM=FB,MACRF=PM,DSORG=PS
    MEMB     DCB   DDNAME=MEMB,LRECL=80,RECFM=FB,MACRF=PM,DSORG=PS
    RECA     DC    CL80'A'                                        
    RECB     DC    CL80'B'
    

    Which ends up with "B" in each member [1], as described by Glenn. To fix that we could open/put/close each member separately, such as:

             OPEN  (MEMA,OUTPUT)
             PUT   MEMA,RECA    
             CLOSE (MEMA)       
             OPEN  (MEMB,OUTPUT)
             PUT   MEMB,RECB    
             CLOSE (MEMB)       
    

    But from the SORT output, it seems clear SORT is opening both DD's at once.

    [1] And I should say it just looks like "B" in each member. In reality, the TTR pointers of MEMA and MEMB both end up pointing to the same data.

    Notes below added after reading comment from original poster.

    Yes, Glenn mentioned the same thing really, just in a different way. I "believe" the way it works is this:

    1. We OPEN MEMA. That reads into memory the next available TTR from the PDS directory or VTOC (I forgot the name of that field, but I think that's how it works). Directory entry for MEMA is not updated or created yet.
    2. We OPEN MEMB. That reads the SAME TTR into memory for the second DCB.
    3. We PUT records for both MEMA and MEMB. This is where it gets a little weird because with a small number of records QSAM is going to just buffer them and not write anything to disk. So in your case it may make little difference if SORT writes all the MEMA records followed by all the MEMB records, or if they are interspersed, MEMA, MEMB.
    4. We CLOSE MEMA. That writes out the MEMA I/O buffer to disk at the TTR we obtained at OPEN time. Then I believe a STOW is issued to create or update the directory entry for MEMA with the new TTR. We look good at this point.
    5. We CLOSE MEMB. That writes out the MEMB I/O buffer at the same TTR as MEMA, which in your case includes ALL the MEMB records. And of course we then STOW that same TTR in the MEMB directory entry. Oops.

    This is all just my theory of course until tested. But at this point I should also say, "Just don't do this" :) While PDS members can easily be used as PS datasets, I don't think this training example is anything the PDS designers had in mind.