Record Locking Problem in a Monitor Block

Q. I am trying to find out which user is causing a record lock. I should be able to get some basic information on the record lock by examining the exception data subfield in the Program Status Data Structure (PSDS). But instead of the promised “Record in use by job …” data which actually names the job holding the lock, I get a more generic “Unable to allocate a record…” message.

What’s up with that?

A. When a record lock conflict occurs, the system sends message CPF5027 (“Record in use by job…”) and %Status is set to 1218.

Traditionally, we’ve been able to see the first level text for CPF5027 by simply looking at the exception data area (positions 91-170) of the program status data structure. Here’s a short program (PGM1) that illustrates the technique:

FMyfile    UF   E             Disk

D SDS
D Exceptiondata 91 170

D Wait S 1

/Free
Read(e) Myfile;
Select;
When %Status = 0;
Dsply 'Wait here...' ' ' Wait;
Other;
Dump(a);
Dsply %Status; // Status = 1218
Dsply %Substr(Exceptiondata:1:52) ' ' Wait; // CPF5027
Endsl;

*Inlr = *On;
Return;
/End-free

(You can test this program by running it simultaneously in two different jobs.)

If this program encounters a record lock (after waiting, usually for 60 seconds), it will receive a CPF5027 message and will display the following lines in the joblog:

DSPLY   1218                                             
DSPLY Record 1 in use by job 999999/MYUSER/MYJOB.

If, however, you use the recently introduced Monitor operation code to capture the record lock error, instead of the (e) operation code extender, you will get a different result. The following short program (PGM2) illustrates:

FMyfile    UF   E             Disk

D SDS
D Exceptiondata 91 170

D Wait S 1

/Free
Monitor;
Read Myfile;
Dsply 'Wait here...' ' ' Wait;
On-error;
Dump(a);
Dsply %Status; // Status = 1218
Dsply %Substr(Exceptiondata:1:52) ' ' Wait; // RNX1218
Endmon;

*Inlr = *On;
Return;
/End-free

Unlike the previous program, if PGM2 encounters a record lock, it will receive an RNX1218 message and will display the following lines:

DSPLY   1218                                        
DSPLY Unable to allocate a record in file MYFILE.

Why the different result from the same error? A deeper look at the job log will explain.

Here’s the job log from PGM1:

CPF5027 Record 1 in use by job 999999/MYUSER/MYJOB.

The message details indicate that this is a NOTIFY message from the IBM procedure QDBSIGEX directly to PGM1.

When PGM1 receives the message it sets the %STATUS to 1218, and places the message data directly into its program status data structure.

PGM2 introduces the Monitor block to the program. When an I/O error occurs that isn’t handled by the (e) extender — or an error indicator — RPG signals a new message, RNXnnnn, where nnnn is the status code. Here’s the job log from PGM2:

CPF5027 Record 1 in use by job 999999/MYUSER/MYJOB.   
RNX1218 Unable to allocate a record in file MYFILE.

The job log indicates that QDBSIGEX still sends the notify message (CPF5027), but then the “signalException” procedure in RPG runtime service program QRNXIE sends an RNX1218 escape message to PGM2. PGM2 still sets the %STATUS to 1218, but the program status data area now contains the data from the escape message, not the original notify message.

For the PGM2 scenario, the original CPF5027 message is still in the program’s call message queue, but you’d need to use the QMHRCVPM (Receive Program Message) API to retrieve it. But that’s a topic for another day.