With the technology advances of the last few years, our AS/400s have become more and more forgiving. By adding a faster processor here and a little more memory there, we are able to cover up some pretty inefficient code.
But take a minute to think about what would happen if you took the advancements in technology and combined them with clean, efficient code. Instead of using the technology to hide our weaknesses, we should focus on using it to exploit our strengths.
Let’s start with record blocking. It is a good way to enhance performance, but too few programmers take advantage of the technique.
Putting All Your Eggs in One Basket
Why do you usually stop to get a shopping cart when you make your weekly visit to the grocery store? Can you imagine doing the weekly shopping for a family of five without a cart? You would have to bring the items to the front counter one or two at a time. It would take you forever! As ridiculous as this idea sounds, that is precisely what many AS/400 programmers are asking their systems to do when they do not take advantage of record blocking.
Record blocking is an effective tool anywhere you are performing sequential read operations on a file. Record blocking is simply how you tell the system to put more than one item in the cart (a euphemism for the I/O buffer) before you return to the front counter (your program). The trick is to figure out how many items you can put in the cart before they start falling all over the floor.
The system performs a limited amount of record blocking whether you specify it or not. When your program performs a read operation, the system checks the I/O buffer to see if it needs to go read some records. If so, the system reads enough records to fill the I/O buffer (the default size or block is usually 4 KB) and then returns control to your program. How many records it reads to fill the buffer depends on the physical size of your
records as well as the size of the buffer. In many cases, performance may be enhanced by selecting a buffer size that is closer to the amount of memory the system uses for an open data path (ODP)—32 KB prior to V3R1, 64 KB thereafter.
To calculate the optimal blocking factor for the file you are copying, divide the physical record length of the file into the size of the ODP for the job (32 KB prior to V3R1, or 64 KB for V3R1 and after).
Putting Too Many Eggs in One Basket
At this point, you may be asking yourself why you shouldn’t just use a really big blocking factor and be done with it. We have seen this technique before, and it seems as though it should work well. The problem with the technique is that the system is prepared to deal only with a buffer size that is less than or equal to the size of the ODP. Any additional overflow is automatically written out to disk. The result is that the records would really have to be read twice, once from the database file and then a second time from the overflow buffer.
As you can see, the best possible solution is to calculate a blocking factor that is close to the size of the ODP without creating an overflow condition. You apply the newly calculated blocking factor using the Override Database File (OVRDBF) command.
Let’s take a look at the example in Figure 1. We calculated the optimal blocking factor by dividing the record length of the CUST file, which was 58, into 65,535 (64 KB minus 1). The result was 1,129.91, so our optimal blocking factor was 1129. We then issued the OVRDBF command to set our blocking factor and call our RPG program.
When a Good Egg Goes Bad
Those of you who have been paying close attention are now probably saying to yourselves, “Cool! But what happens when I need to add a field to that file? I’ll have to find the CL programs where I used a blocking factor and update them with the new blocking factor.” You are correct! But we can help you by giving you a shortcut.
As software developers, we change database files in our standard system all the time. As software vendors, we sometimes are asked to customize our clients’ database files, too. This poses an interesting challenge. How do we ensure that our applications are using the correct blocking factor without having to constantly monitor the programs? What we really needed was a way to dynamically set the blocking factor and tell our programs which blocking factor to use. That way would have to always be correct, regardless of how many times our database files changed.
Eggsactly the Right Solution
In Figure 2, we see the BLOCK001RG RPG IV program, which was designed to calculate a dynamic blocking factor. It calls the QDBRTVFD API to retrieve the file description and determine the record length of the file in question. It then calculates the optimal file blocking factor and passes it back to the calling program.
The GETBLOCK command in Figure 3 is the command interface used to call the GETBLKRG program and return the optimal blocking factor. In Figure 4, we see an example of how the GETBLOCK command can be implemented into your CL programs. The &OUTBLOCK variable returned from the GETBLOCK command is used as the blocking factor on the OVRDBF command. The Delete Override (DLTOVR) command is then used to delete the override once the RPG program is done reading the file.
You Are Now a Blocking Eggspert
Technology is changing our AS/400 at an unbelievable pace. But software has lagged behind. Thousands of applications run on the AS/400, but many of them are outdated and inefficient. The best way to extend the life of these systems is to improve the efficiency of the software and to take advantage of the technology advances as they happen.
Record blocking is a simple way to improve the performance of existing applications. Take advantage of what you know, and look good doing it!
/*===================================================================*/
/* To compile: */
/* */
/* CRTCLPGM PGM(XXX/BLOCKCL) SRCFILE(XXX/QCLSRC) + */
/* TEXT(‘To apply blocking factor’) */
/*===================================================================*/
PGM
OVRDBF FILE(CUST) SEQONLY(*YES 1129)
CALL MYPROGRAM
DLTOVR FILE(CUST)
ENDPGM *===============================================================
* To compile:
*
* CRTBNDRPG PGM(XXX/BLOCK001RG) SRCFILE(XXX/QRPGLESRC) +
* TEXT(‘Calculate blocking factor’)
*
*===============================================================
d error ds inz
d bytprv 1 4b 0
d bytava 5 8b 0
d msgid 9 15
d err### 16 16
d msgdta 17 116
d rcvvar ds 4096
d MaxRcdLen 305 306b 0
d Ar s 1 dim(4096)
d FileLib s 20
d Filfmt s 8
d Fmttyp s 10
d InPhysical s 6 0
d OutBlock s 5 0
d Ovrrid s 1
d Rcdfmt s 10
d RcvLen S 4b 0
d SFileLib s 20
d System s 10
d TstTyp s 1
C *entry Plist
C Parm FileLib
C Parm InPhysical
C Parm OutBlock
c eval bytprv = 116
c eval SFileLib = FileLib
c call ‘QDBRTVFD’
c parm RcvVar
c parm 4096 RcvLen
c parm FileLib
c parm ‘FILD0100’ FilFmt
c parm SFileLib
c parm RcdFmt
c parm ‘0’ Ovrrid
c parm ‘*LCL’ System
c parm ‘*EXT’ FmtTyp
c parm Error
c movea rcvvar ar(1)
c move ar(9) tsttyp
c testb ‘2’ tsttyp 01
c If *in01 = *off
c InPhysical Div MaxRcdLen OutBlock
Figure 1: CL program to apply an optimal blocking factor
c endif
c eval * inlr = *on /*==================================================================*/
/* To compile: */
/* */
/* CRTCMD CMD(XXX/GETBLOCK) PGM(XXX/BLOCK001CL) + */
/* SRCFILE(XXX/QCMDSRC) ALLOW(*BPGM *IPGM) + */
/* TEXT(‘Calculate blocking factor’) */
/* */
/*==================================================================*/
CMD PROMPT(‘Get Blocking Factor’)
PARM KWD(FILELIB) TYPE(FL1) CASE(*MONO) +
CHOICE(‘Name’) PROMPT(‘File name’) MIN(1)
PARM KWD(PHYSICAL) TYPE(*DEC) DFT(65535) +
PROMPT(‘Physical Divisor’) LEN(6 0)
PARM KWD(BLOCKAT) TYPE(*DEC) LEN(5 0) RTNVAL(*YES) +
PROMPT(‘Blocking Factor’)
FL1: QUAL TYPE(*NAME) LEN(10)
QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) SPCVAL((*LIBL +
*LIBL)) PROMPT(‘Library’) /*===================================================================*/
/* To compile: */
/* */
/* CRTCLPGM PGM(XXX/TESTPGM) SRCFILE(XXX/QCLSRC) + */
/* TEXT(‘To apply blocking factor’) */
/*===================================================================*/
PGM
DCL VAR(&OUTBLOCK) TYPE(*DEC) LEN(5 0)
GETBLOCK FILELIB(MYLIB/CUST) BLOCKAT(&OUTBLOCK)
OVRDBF FILE(CUST) SEQONLY(*YES &OUTBLOCK)
CALL MYPROGRAM
DLTOVR FILE(CUST)
ENDPGM
LATEST COMMENTS
MC Press Online