The most common reason for a 3009 is the first reason cited in the documentation, namely an Adabas timeout.
Consider the following code:
READ some file
IF some condition
::
UPDATE
END-IF
:: /* more processing
END-READ
Since the UPDATE corresponds to the READ, the READ command to Adabas will be L4, L5, or L6, which are reads with “hold” (update intent).
The very first record read will start a “stop watch”. If an End Transaction, or a Backout Transaction is not issued within the time limit specified by the ET timeout parameter, a 3009 will be issued.
Suppose only a few records out of 20 million on the file will pass the IF test and hence be updated. Further, suppose that there is some processing required for all records, whether updated or not. It is likely that you would get a 3009. The solution is quite simple, you could have a GET within the IF clause. The code would be something like:
IF some condition
GETR. GET … /* current record using *ISN
UPDATE (GETR.)
END TRANSACTION
etc
The READ would now be an L1, L2, or L3 which do not have update intent (they will not be held). When a record passes the IF test, it will be obtained by the GET, which will be a read with hold (since there is an update that refers to it).
WARNING. If a large percentage of the records are to be updated, the original code, modified to count records, and issuing an ET say every 100 records, would almost certainly be preferable.