Get the best response time with Open List APIs.
This is the sixth, and final, article in a series that discusses how to find all *PGMs and *SRVPGMs that have a specific *MODULE bound into them. And to think this series started with one simple question from a reader!
Before reading this article, you may find it beneficial to review the previous articles:
•· "Module, Module, Who's Got My Module?"
•· "Finding Modules in a *SRVPGM"
•· "Finding All *SRVPGMs on the System"
•· "Take Advantage of Open List APIs"
•· "Finding Modules in a *PGM"
While the stated intent is to find all uses of a given module, the actual purpose of this series of articles is to introduce the concepts and proper use of two types of system APIs: List and Open List.
Today, we're adding parallelism to the function provided by the MODUSAGE program, cleanup processing in the event of an unexpected error, and, as a minor enhancement, a command interface to call MODUSAGE that allows for module library qualification. As this series of articles is intended as an introduction to Open List and List API processing, the previous articles strove to keep the logic as straightforward as possible. In this article, we'll add a few twists and turns....
With that said, the latest level of code for MODUSAGE, with new and changed source in bold, can be downloaded here.
What Did We Change?
The first change we have made is in the prototype and procedure interface to MODUSAGE. MODUSAGE now supports a 20-byte qualified module name, QModNam, for its first parameter. Previously, the first parameter, ModNam, was a simple 10-byte module name. Related to this change, we also defined the Display Module Usage (DSPMODUSG) command. Here's the command definition for DSPMODUSG:
CMD PROMPT('Display Module Usage')
PARM KWD(MODULE) TYPE(QUALNAME) MIN(1) +
PROMPT('Module')
PARM KWD(SRCHLIB) TYPE(*NAME) LEN(10) +
DFT(*ALLUSR) SPCVAL((*ALLUSR) (*USRLIBL) +
(*ALL) (*CURLIB) (*LIBL)) PROMPT('Library +
to search')
QUALNAME: QUAL TYPE(*NAME) MIN(1)
QUAL TYPE(*NAME) DFT(*ALL) SPCVAL((*ALL)) +
PROMPT('Library')
The command is created with CRTCMD CMD(DSPMODUSG) PGM(MODUSAGE). In a production environment, you would of course want to use a message file for the DSPMODUSG prompt text (not to mention the text DSPLYed by the MODUSAGE program), but the above approach is sufficient for our purposes.
We have also now defined a MONITOR group with the initial statement in the main procedure. This monitor is to allow MODUSAGE to gain control in the event of an unexpected error situation--specifically if one of the APIs that is called, using the QUSEC error-code structure, sends an escape message back to MODUSAGE. We will discuss the associated ON-ERROR group later in this article.
Following the execution flow of the program, our next changes are in the Setup procedure. Within Setup, we are now creating two open lists where the creation of these lists is performed asynchronously in a separate server job. By default, a job can have only one server job associated with it, so in Setup we call the Change Server Job (QGYCHGSJ) API, documented here, to change the maximum number of server jobs to two. Having changed the maximum to two, we now start the creation of the two open lists. To have the open lists created entirely asynchronously to our job, we change the fourth parameter of the QGYOLOBJ API call from a Number of records to return value of 50 to a value of 0. Though not necessary, as QGYOLOBJ will not be returning any list entries per the above change, we also changed the second parameter, Length of receiver variable, to 0. After each call to QGYOLOBJ, we now also save the request handle provided by the API in the returned list information data structure QGYLI. As we will now have two open lists existing concurrently, we need to retain the request handle associated with each. MODUSAGE also sets an indicator for both the *SRVPGM and *PGM open lists to indicate that the lists have been opened. We will see the reason for these indicators when we discuss the ON-ERROR processing later in this article.
We have also had an indirect impact on the subsequent processing of the Setup procedure. As we are building the two open lists asynchronously in the two background server jobs, Setup is also now (in the current job) concurrently creating the *USRSPC for later use by the QBNLSPGM and QBNLPGM APIs. We effectively have three jobs working concurrently to prepare the environment for MODUSAGE to run in!
After Setup returns to the main procedure, we now call the Get List Entries API rather than the Open List of Objects API that was used in the previous version of MODUSAGE. When calling the API, we ask for the first 50 *SRVPGM list entries. The key parameter values used are these:
•· Length of receiver variable--This is the %size of the Receiver variable, which is adequate to return 50 list entries into.
•· Request handle--We use SrvPgmHdl; this was initialized in Setup as the handle returned when opening the *SRVPGM-related open list and identifies the list we want to read from.
•· Number of records to return--We use 50 in our example.
•· Starting record--We set this to 1 so that we start with the first entry in the list.
•· Error code--We use the ErrCde data structure, rather than QUSEC, so that the API will not send escapes in the case of an error.
Whether or not the background server job has finished building the list of *SRVPGMs is not material when we call the Get List Entries API. The API will not return to MODUSAGE until one of the following occurs:
•· 50 or more *SRVPGMs are found--As soon as 50 are found, the API will return to MODUSAGE (and continue finding more *SRVPGMs in the server job) with the first 50 list entries. Note that this can cause MODUSAGE to go into a wait state while the necessary Number of records to return is collected. This parameter value, Number of records to return, can obviously be used for some limited tuning: the smaller the value, the quicker the return from the API, with the tradeoff being the cost of calling the API more times in order to access the same total number of records in the list.
•· Greater than 0 but less than 50 *SRVPGMs are found--The API will return the number of entries that do exist in the list and set the List status indicator of QGYLI to '2', indicating that the list has been completely built.
•· 0 *SRVPGMs are found--The API will return the error GUI0006, indicating that a Starting record of 1 is invalid.
•· Some other error is encountered by the API and returned to MODUSAGE.
Following the call to QGYOLOBJ, we start a SELECT group in order to determine which of the above four conditions occurred.
If there is no error, then one or more list entries are available in the variable RcvVar, and we run the same type of processing logic we have in past versions of MODUSAGE: process each list entry by calling ChkSrvPgmMod and, after analyzing all list entries, calling OpnLstDone. One change is in the call to the OpnLstDone procedure. As there can now be multiple open lists active in MODUSAGE, we have added a parameter providing the list request handle. This allows OpnLstDone to know which open list is to be tested and/or processed. A second change is if OpnLstDone indicates that the list is indeed done. If this is the case, we set off the indicator associated with the open list (the list itself was closed in the OpnLstDone procedure). This is done so that later, in the ON-ERROR logic we've added, we can see if the list needs to be closed as part of program cleanup.
If there was an error returned, we check to see if it's GUI0006 as this would indicate an empty list. If that is the case, we close the list, turn off the indicator associated with the open list, and DSPLY that no *SRVPGMs were found in the requested search library(ies). If the error is not GUI0006, we call SndErrMsg to send the error message (as right now the error message is only in the ErrCde data structure--not a real good place if we want someone to know that an error has been encountered).
Following the above processing of the *SRVPGM open list, we do the same type of processing (with appropriate field name changes) for the *PGM open list.
Within the ChkSrvPgmMod and ChkPgmMod procedures, we've also made a small change. This change is related to the library qualification of the module we are searching for. Rather than simply comparing module names, we AND that comparison with a check for either the searched-for module library name being the special value '*ALL' or the searched-for module library name being equal to the module library name for the module bound into the *SRVPGM and *PGM, respectively. Only when the module name and one of the module library name comparisons are both true do we DSPLY the *SRVPGM/*PGM name and increment the Hit variable.
In the OpnLstDone procedure, we made a minor change in support of the open list Request handle now being passed as a parameter to the procedure. This impacted OpnListDone's calls to the Close List and Get List Entries APIs.
Having completed our review of the functional changes related to list processing, now let's visit the ON-ERROR logic we've added to the main procedure. Whenever an unmonitored exception is detected in MODUSAGE (which would be any API error when using the QUSEC error code data structure), the ON-ERROR group associated with our MONITOR will gain control. This allows us to do additional processing, such as First Failure Data Capture (FFDC), application cleanup, application recovery, and the like. FFDC and application recovery are beyond the scope of the current article, but some application cleanup is certainly possible. In a previous article, we discussed how important it is to close open lists when you no longer need them. If you don't close them, they will linger on the system, consuming storage (and in the case of large lists, a lot of storage) until your job ends. It is the storage associated with the open lists that we will attempt to recover when a failure occurs within MODUSAGE. There are certainly many other activities that we might want to perform in a more-robust application.
Within the ON-ERROR group, we check the indicators associated with the two open lists. If the indicator is *on, MODUSAGE then closes the corresponding open list prior to ending. After closing any lists that had been open, MODUSAGE DSPLYs a message telling the user that an error has been encountered and that they should check the job log for additional information. The escape message that caused the ON-ERROR group to become activated should be found in the job log.
The last change we made to MODUSAGE is in the SndErrMsg procedure. As a reminder, this is the procedure that gets control when an API is called with the ErrCde error code data structure (disabling the sending of escape messages) and an unexpected error was returned in the ErrCde data structure. In previous versions of MODUSAGE, SndErrMsg sent the error message as an escape to the caller of MODUSAGE. With this version of the program, SndErrMsg sends the error message as an escape to itself. By programming MODUSAGE to send the escape message to itself, we will trigger the ON-ERROR group discussed above and provide for the cleanup/operator notification functions.
That's it! We now have a reasonably functional development tool to identify which *SRVPGMs and *PGMs may be impacted by a change to a *MODULE. I would not consider this tool ready for the general public; it uses embedded text messages, doesn't provide a lot in the area of error logging and capture, etc. But it can certainly still provide a useful function. More importantly, we have also seen how to use List and Open List APIs, what some of the design considerations are in using these APIs, how to selectively handle some errors while handling other errors in a more generic fashion, and more. Hopefully, this series of articles will help you in your application development efforts; certainly having more knowledge of the tools available to you never hurts.
And remember, if you have API questions, send them to me at
LATEST COMMENTS
MC Press Online