|
To retrieve a specific member from a PDS, you can use either BSAM
or QSAM, as follows (see Figure 1):
- Code DSORG=PS or DSORG=PSU in the DCB macro.
- In the DD statement specify that the data is a member of an existing
PDS by coding DSNAME=name(membername) and DISP=OLD,
DISP=SHR or DISP=MOD.
- Process the member with an OPEN macro, a series of GET or READ
macros, and the CLOSE macro.
Figure 1. Retrieving One Member of a PDS //PDSDD DD ---,DSN=MASTFILE(MEMBERK),DISP=SHR
...
OPEN (INDCB) Open for input, automatic FIND
...
GET INDCB,INAREA Read member record
...
CLOSE (INDCB)
...
INAREA DS CL80 Area to read into
INDCB DCB ---,DSORG=PS,DDNAME=PDSDD,MACRF=GM
When your program is run,
OPEN searches the directory automatically and positions the DCB to
the member.
To process several members without closing and reopening, or to
take advantage of additional data in the directory, use the procedure
described in Figure 2 or Figure 3.
The system
supplies a value for NCP during OPEN. For performance reasons, the
example shown in Figure 3 automatically
takes advantage of the NCP value calculated in OPEN or set by the
user on the DD statement. If the FIND macro is omitted and DSORG on
the DCB changed to PS, the example shown in Figure 3 works
to read a sequential data set with BSAM. The logic to do that is summarized
in Using Overlapped I/O with BSAM.
To retrieve a member of a PDS using the NOTE and POINT macros,
take the following steps. Figure 2 is an
example that uses note lists, which should not be used with PDSEs.
- Code DSORG=PO or POU in the DCB macro.
- In the DD statement specify the data set name of the PDS by coding
DSNAME=name.
- Issue the BLDL macro to get the list of member entries you need
from the directory.
- Repeat the following steps for each member to be retrieved:
- Use the FIND macro to prepare for reading the member records.
If you use the POINT macro it will not work in a partitioned concatenation.
- The records can be read from the beginning of the member, or a
note list can be read first, to obtain additional locations that point
to subcategories within the member. If you want to read out of sequential
order, use the POINT macro to point to blocks within the member.
- Read (and check) the records until all those required have been
processed.
- Your end-of-data-set (EODAD) routine receives control at the end
of each member. At that time, you can process the next member or close
the data set.
Figure 2 shows the technique for processing
several members without closing and reopening. This demonstrates synchronous
reading.
Figure 2. Retrieving Several Members and Subgroups of
a PDS without Overlapping I/O Time and CPU Time //PDSDD DD ---,DSN=D42.MASTFILE,DISP=SHR
...
OPEN (INDCB) Open for input, no automatic FIND
...
BLDL INDCB,BLDLLIST Retrieve the relative disk locations
* of several names in virtual storage
LA BLDLREG,BLDLLIST+4 Point to the first entry
Begin a member possibly in another concatenated data set
MEMBER FIND INDCB,8(,BLDLREG),C Position to member
...
Read the NOTE list:
LA NOTEREG,NOTELIST Load address of NOTE list
MVC TTRN(4),14(BLDLREG) Move NOTE list TTRN
* to fullword boundary
POINT INDCB,TTRN Point to the NOTE list record
READ DECBX,SF,INDCB,(NOTEREG) Read the NOTE list
CHECK DECBX
...
Read data from a subgroup:
SUBGROUP POINT INDCB,(NOTEREG) Point to subgroup
READ DECBY,SF,INDCB,INAREA Read record in subgroup
CHECK DECBY
LA NOTEREG,4(NOTEREG) Increment to next subgroup TTRN
...
Repeat from label "SUBGROUP" for each additional subgroup
AH BLDLREG,BLDLLIST+2
Repeat from label "MEMBER" for each additional member
...
CLOSE (INDCB)
...
INAREA DS CL80
INDCB DCB ---,DSORG=PO,DDNAME=PDSDD,MACRF=R
TTRN DS F TTRN of the NOTE list to point at
NOTEREG EQU 4 Register to address NOTE list entries
NOTELIST DS 0F NOTE list
DS F NOTE list entry (4 byte TTRN)
DS 19F one entry per subgroup
BLDLREG EQU 5 Register to address BLDL list entries
BLDLLIST DS 0F List of member names for BLDL
DC H'10' Number of entries (10 for example)
DC H'18' Number of bytes per entry
DC CL8'MEMBERA' Name of member
DS CL3 TTR of first record (created by BLDL)
DS X K byte, concatenation number
DS X Z byte, location code
DS X C byte, flag and user data length
DS CL4 TTRN of NOTE list
... one list entry per member (18 bytes each)
The example in Figure 3 does not use
large block interface (LBI). With BPAM there is no advantage in the
current release to using LBI because the block size cannot exceed
32 760 bytes. You can convert the example to BSAM by omitting the
FIND macro and changing DSORG in the DCB to PS. With BSAM LBI you
can read tape blocks that are longer than 32 760 bytes.
The technique shown in Figure 3 is
more efficient than the technique shown in Figure 2 because
the access method is transferring data while the program is processing
data that was previously read. Figure 3. Reading a Member
of a PDS or PDSE using Asynchronous BPAM OPEN LIBDCB Open DCB, setting RECFM, LRECL, BLKSIZE
USING IHADCB,LIBDCB
USING DCBE,MYDCBE DCB addressability (needs HLASM)
TM DCBOFLGS,DCBOFPPC Branch if open
BZ --- failed
FIND LIBDCB,MEMNAME,D Position to member to read
SR R3,R3 GET NCP calculated by OPEN or
IC R3,DCBNCP coded on DD statement
(1) LH R1,DCBBLKSI Get maximum size of a block
ROUND LA R1,DATAOFF+7(,R1) Add length of DECB (READ MF=L) and pointer
SRL R1,3 and round up to a
SLL R1,3 doubleword length
LR R4,R1 Save length of DECB + pointer + block size
MR R0,R3 Calculate length of area to get
* Get area for DECB's, a pointer to the next DECB for each DECB and a data area
* for each DECB. Each DECB is followed by a pointer to the next one and the
* associated data area. The DECB's are chained in a circle. DECB's must be
* below line; data areas can be above line if running in 31-bit mode, however,
* they will be retrieved below the line in this example.
ST R1,AREALEN Save length of area
GETMAIN R,LV=(R1),LOC=(BELOW,64)
* DECB virtual addr below the line, but real above
ST R1,AREAAD
LR R5,R1
* Loop to build DECB's and issue first READ's.
BLDLOOP MVC 0(NEXTDECBOFF,R5),MODELDECB Create basic DECB
LA R1,0(R4,R5) Point to next DECB
ST R1,NEXTDECBOFF(,R5) Set chain pointer to next DECB
READ (R5),SF,,DATAOFF(R5) Store data address in DECB, issue READ
AR R5,R4 Point to next DECB
BCT R3,BLDLOOP Branch if another READ to issue
SR R5,R4 Point back to last DECB
L R1,AREAAD Point to first DECB
ST R1,NEXTDECBOFF(,R5) Point last DECB to first DECB
LR R5,R1 Point to first (oldest) DECB
* Loop to read until end-of-file is reached.
MAINLOOP CHECK (R5) Wait for READ, branch to EODATA if done
L R1,16(,R5) Point to status area
LH R0,DCBBLKSI Get length of read attempted
(2) SH R0,14(,R1) Subtract residual count to read length
RECORD1 LA R1,DATAOFF(,R5) Point to first record in block
.
. (Process records in block)
.
READ (R5),SF,MF=E Issue new read
L R5,NEXTDECBOFF(,R5) Point to next DECB
B MAINLOOP Branch to next block
* End-of-data.
* CHECK branched here because DECB was for a READ after the last block.
EODATA CLOSE LIBDCB
L R0,AREALEN
L R1,AREAAD
FREEMAIN R,LV=(0),A=(1)
.
.
.
AREAAD DC A(0) Address of gotten storage
AREALEN DC F'0' Length of gotten storage
LIBDCB DCB DSORG=PO,DCBE=MYDCBE,MACRF=R,DDNAME=DATA
MYDCBE DCBE MULTSDN=2,EODAD=EODATA,MULTACC=1 Request OPEN to supply NCP
READ MODELDECB,SF,LIBDCB,MF=L
NEXTDECBOFF EQU *-MODELDECB Offset to addr of next DECB
DATAOFF EQU NEXTDECBOFF+4 Offset to data
MEMNAME DC CL8'MASTER' Name of member to read
DCBD DSORG=PS,DEVD=DA
IHADCBE ,
Tip: You can convert Figure 3 to use LBI by making the following
changes: - Add BLKSIZE=0 in the DCBE macro. Coding a nonzero value also requests
LBI, but it overrides the block size.
- After
line (1), test whether the access method supports LBI. This is in
case the type of data set or the level of operating system does not
support LBI. Insert these lines to get the maximum block size:
TM DCBEFLG1,DCBESLBI Branch if access method does
BZ ROUND not support LBI
L R1,DCBEBLKSI Get maximum size of a block
- After line (2) get the size of the block:
TM DCBEFLG1,DCBESLBI Branch if
BZ RECORD1 not using LBI
SH R1,=X'12' Point to size
L R0,0(,R1) Get size of block
|