How to Retry an Object Lock

Article ID: 20094

Q: Recently we received error CPF4128 while running an RPG program that generates reports. It's a simple program that opens a logical file for input only, reads it, and outputs it to a printer file. This is the system error that it receives:

  Not able to allocate objects needed for file GLTRANL1 in library 
  MYLIB member or program device GLTRANL1.

When we receive this error, we usually answer it with a "C" for cancel, and then the report won't be generated. How can we solve this? Is there a way to make it retry? If I wanted to run this program in batch, is there a way to make it retry automatically?

A: Whenever you access any type of object on the iSeries, you place some sort of "lock" on the object. These locks affect what other people can do with the object while you're using it.

For example, when you open a file for reading, you put a "shared" lock on the file. This means that other jobs on the system are allowed to share the file with you, but are not allowed to do something that would interfere with that sharing, such as deleting the file.

What's happening in your case is that another job has gained exclusive use of the file. It might be deleting the file in order to re-build it, or something else that can only be done with nobody else is using the file.

To handle this problem in your program, what you need to do is pre- allocate the file. This involves manually placing a lock on the object with the ALCOBJ command. If that fails, try again until it's successful. Once it's successful, you can run your RPG report program without worries.

For example, the following CL program tries every second to see if it can get a successful shared lock on the file named GLTRANL1. If it can't, it puts a message on the screen so the user knows what he's waiting for. As soon as the file is available, it'll run the RPG program. It will deallocate the file when it's done:

PGM

TRYAGAIN:
       ALCOBJ OBJ((GLTRANL1 *FILE *SHRRD *FIRST)) WAIT(1)
       MONMSG MSGID(CPF1002) EXEC(DO)
             SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA('Waiting +
                          for access to GLTRANL1 file') +
                          TOPGMQ(*EXT) MSGTYPE(*STATUS)
          GOTO TRYAGAIN
       ENDDO

       CALL PGM(MYRPGPGM)

       DLCOBJ OBJ((GLTRANL1 *FILE *SHRRD *FIRST))

ENDPGM

The *FIRST value that I used on the ALCOBJ command tells it to check the first member in the file. That means that even if other jobs are gaining exclusive use through the physical file or a different logical file, this will still catch the problem and allow it to keep retrying.

There may be times when you want the program to notify you that it's been hung up for a long time, since this may indicate a problem. It's easy to keep track of how long it's been waiting and send you a message after two minutes have passed.

The following code demonstrates how to do this:

PGM

       DCL VAR(&SECS) TYPE(*DEC) LEN(5 0) VALUE(0)

TRYAGAIN:
       ALCOBJ OBJ((GLTRANL1 *FILE *SHRRD *FIRST)) WAIT(1)
       MONMSG MSGID(CPF1002) EXEC(DO)

           SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA('Waiting +
                          for access to GLTRANL1 file') +
                          TOPGMQ(*EXT) MSGTYPE(*STATUS)

           CHGVAR VAR(&SECS) VALUE(&SECS + 1)
           IF (&SECS *GE 120) DO
             SNDMSG MSG('GLTRANL1 not available after two +
                     minutes!') TOUSR(KLEMSCOT)
             CHGVAR VAR(&SECS) VALUE(0)
           ENDDO

           GOTO TRYAGAIN
       ENDDO

       CALL PGM(MYRPGPGM)

       DLCOBJ OBJ((GLTRANL1 *FILE *SHRRD *FIRST))

ENDPGM

Naturally, you could substitute the SNDDST command for the SNDMSG command if you wanted to send e-mail instead. The important part is to notify someone who will know how to fix the problem so that a batch job doesn't get hung up indefinitely.

ProVIP Sponsors

ProVIP Sponsors