Have you ever felt as clumsy as Peter Falk's "Detective Columbo" when looking for an intermittent data problem that keeps cropping up in one of your data files? If you think that the nefarious lawbreaker is likely to strike again, we have some good news for you. There is a way to make sure that there will be a trail for you to follow-journaling.
Journaling is a process that records changes made to a physical file in an object called a journal receiver. These changes are recorded as journal entries and are much like the journal entries you would find in a general ledger. The purpose is the same: create a path that may be followed if you ever have to go back.
Generally, journaling is used for automatic error recovery and is necessary if you will be using commitment control. (For more information, see "Don't Be Afraid of Commitment," MC, March 1992.) For the purposes of this article, though, we will be using it as our own private gumshoe to help us track down the source of our wayward data.
Before you get too far into this article, we should warn you that this technique may not be suitable if your system is extremely low on disk space. The journal of file changes can get quite large. It all depends on how much activity occurs in the file you are journaling and how long it is between the intermittent data errors you are looking for. The journal not only logs what has changed in the record, but in fact copies the entire changed record; it also logs the who, when, and where. You will obviously incur additional I/O on your system, which can have an effect on overall system performance. As with most things in life, you must determine whether the potential benefits outweigh the cost.
First, we will demonstrate the three steps necessary to set up and initiate the journaling process. Then we will show you how to get to the journal data and what to do with it once you get there.
Journaling 101
To perform journaling, you need to deal with two principle components: the journal receiver and the journal itself. On the AS/400, the journal receiver actually holds the journal entries (changes to the file, in our case). The journal is like a directory of which files are being journaled, what receiver is attached to the journal, and other information that describes the journal itself. Think of the journal as the header file and the journal receiver as the detail file.
In the past, it was up to the programmers and operators to maintain the journal receivers. Failure to do so resulted in disk space getting "gobbled up" rapidly. With V3R1 came an improvement to the Create Journal (CRT-JRN) command. You can now elect to have the journal receivers managed by the system.
If you specify a threshold size when you create the journal receiver and use the Manage receivers (MNGRCV) parameter value of *SYSTEM when you create the journal, the system cleans up your journal receivers for you. The operating system checks to see if your receiver has reached its threshold size at IPL time. If it has, the system detaches the active receiver from the journal and automatically creates and attaches a new receiver in its place. Then the freshly deactivated journal may be saved (if desired) and deleted from the system to free up valuable disk space.
Realizing that not everyone is on V3R1 yet, we have elected to use self-managed journal receivers for our example here by using the default *USER for the MNGRCV parameter of the CRTJRN command.
You must create a journal receiver before you create a journal. For our example, we will create a journal receiver called CUST-RCV in a library called TESTLIB:
CRTJRNRCV JRNRCV(TESTLIB/CUSTRCV)
We will then create a journal named CUSTJRN in library TESTLIB, indicating the name of the initial receiver that we will use to store our journal entries.
CRTJRN JRN(TESTLIB/CUSTJRN) + JRNRCV(TESTLIB/CUSTRCV)
After entering those two commands, we are ready to put our detective to work. The Start Journal Physical File (SRTJRNPF) command activates journaling. This command begins journaling for file CUSTOMER in library TESTLIB:
STRJRNPF FILE(TESTLIB/CUSTOMER) + JRN(CUSTJRN)
Now that journaling is active, our journal will record everything that happens to our CUSTOMER file. That includes every time the file is opened, closed, or saved; every time a record is written, deleted, or updated; basically, every time the file is touched!
Reading the Results
To see all of the recorded journal entries for our CUSTOMER file, we key the Display Journal (DSPJRN) command as follows:
DSPJRN JRN(TESTLIB/CUSTJRN)
A display similar to that in 1 appears on the screen. For our example here, though, we see a little too much information. We do not really care when the file was opened, closed, or saved. We are more interested in knowing who and what is updating our file and when. The DSPJRN command allows us to filter out the journal entries we do not wish to see.
A display similar to that in Figure 1 appears on the screen. For our example here, though, we see a little too much information. We do not really care when the file was opened, closed, or saved. We are more interested in knowing who and what is updating our file and when. The DSPJRN command allows us to filter out the journal entries we do not wish to see.
To see only journal entries in which a record was changed, key this command:
DSPJRN JRN(TESTLIB/CUSTJRN) + JRNCDE((R))
You'll see a screen similar to the one in 2. All entries under the Code heading are an R, indicating journal entries in which a record has been changed. Under the Type heading, various codes indicate the type of update that was done. PT indicates that a record was added or posted, UP indicates an update, DL indicates that a record was deleted, and so on. Placing the cursor on the type field and pressing HELP gives us a more complete list of the codes.
You'll see a screen similar to the one in Figure 2. All entries under the Code heading are an R, indicating journal entries in which a record has been changed. Under the Type heading, various codes indicate the type of update that was done. PT indicates that a record was added or posted, UP indicates an update, DL indicates that a record was deleted, and so on. Placing the cursor on the type field and pressing HELP gives us a more complete list of the codes.
To see a more detailed accounting of a journal entry that piques your interest, enter option 5 (Display entire entry) in the option (Opt) column of the journal entry and press Enter. The display that is presented is similar to the one in 3. An entry may look scrambled if packed data exists in the record.
To see a more detailed accounting of a journal entry that piques your interest, enter option 5 (Display entire entry) in the option (Opt) column of the journal entry and press Enter. The display that is presented is similar to the one in Figure 3. An entry may look scrambled if packed data exists in the record.
Pressing F10 (Display only entry details) presents a display similar to the one in 4, telling who, what, when, and where.
Pressing F10 (Display only entry details) presents a display similar to the one in Figure 4, telling who, what, when, and where.
The Outfile Method
It is possible that your journal may contain too many entries to make this method practical, or that the data you are looking for is contained in a packed field. If either situation exists, you may want to display the information to an outfile. You could then code an RPG program to process the outfile, and narrow down your search from there.
When displaying a journal to an outfile, DSPJRN will put the first 100 bytes of each record in a single field. To see more than the first 100 bytes of a file (we needed 126 bytes in our CUSTOMER file example), specify a field length in the Entry data length (ENT-DTALEN) parameter of the DSPJRN command. Otherwise, the data will be truncated.
To send CUSTOMER file journal entries to an outfile named JOURNOUT in library TESTLIB, key this command:
DSPJRN JRN(TESTLIB/CUSTJRN) + JRNCDE((R)) OUTPUT(*OUTFILE) + OUTFILE(TESTLIB/JOURNOUT) + ENTDTALEN(126)
The "after" picture of the complete record is stored in a single field named Journal Entry Specific Data (JOESD). We could use the substring function of Query to parse out the data we are looking for, but we have found that looking at individual fields in the after picture is easier if you use an RPG program.
For this technique, move the JOESD field to an external data structure of the same name and format as the file being journaled. For the example in 5, we simply used our Customer physical file as an external data structure within our program. We did not need to code a file specification for the customer file because our program only uses the external description of the customer file and does not need to perform any file I/O.
For this technique, move the JOESD field to an external data structure of the same name and format as the file being journaled. For the example in Figure 5, we simply used our Customer physical file as an external data structure within our program. We did not need to code a file specification for the customer file because our program only uses the external description of the customer file and does not need to perform any file I/O.
The RPG program in 5 could be used to read and interpret the data from the journal entries. You would probably want to perform some sort of selective process to qualify your search and then send the data to a database file or to the printer.
The RPG program in Figure 5 could be used to read and interpret the data from the journal entries. You would probably want to perform some sort of selective process to qualify your search and then send the data to a database file or to the printer.
Changing Receivers
Journal receivers can have voracious appetites. If left alone, one receiver can easily eat up your disk space without even belching. The only way to curb its appetite is to end journaling or to establish a new receiver so you can get rid of the old one. Before you can kill a journal receiver (by deleting it), you must detach it from the journal. For our example, we would issue the following command:
CHGJRN JRN(CUSTJRN) JRNRCV(*GEN)
This command detaches the current receiver (CUSTRCV), creates a new journal receiver, and attaches the new receiver to the journal. The name of the new receiver will be the name of the old receiver (up to six characters) plus a four-digit sequence number. In our example, the name of the new receiver is CUSTRC0001; the sequence number eliminates the last character of the original journal receiver name because the original has seven characters. If you prefer, you can make up your own name for the new receiver and enter it instead of *GEN.
We are now free to kill the beast and get back all of the storage it ate by issuing this command:
DLTJRNRCV JRNRCV(TESTLIB/CUSTRCV)
If you have not saved the original receiver, you will get the error message CPA7025-Receiver CUSTRCV in TESTLIB never fully saved. (I C). Just reply to the message with an I to ignore it, and the receiver will be deleted.
Clean Up Your Mess
Once we've isolated the problem, we need to end journaling and clean up our disk. Before we can delete the journal, we have to tell the system to stop journaling the file by issuing this command:
ENDJRNPF FILE(TESTLIB/CUSTOMER)
We then delete the journal by issuing this command:
DLTJRN JRN(TESTLIB/CUSTJRN)
If you have created other receivers, do not forget to delete them also.
Data problems are nothing to scoff at. Intermittent ones are the worst. They are difficult to chase down, and they give all of us in the business a bad name. We hope this article will help you and your new detective identify the culprits.
Good luck and good hunting.
Doug Pence is the founder and Ron Hawkins is the research and development manager of Computer Processing Unlimited, Inc. in San Diego, California.
Journaling: A Powerful Debugging Tool
Figure 1: Displaying All Journal Entries
Journaling: A Powerful Debugging Tool
Figure 2: Displaying Changed Record Journal Entries
Journaling: A Powerful Debugging Tool
Figure 3: Displaying Entire Journal Entry
Journaling: A Powerful Debugging Tool
Figure 4: Displaying Entry Details
Journaling: A Powerful Debugging Tool
Figure 5: RPG Code to Process a DSPJRN Outfile
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 FJOURNOUTIF E DISK IOUTFMT E DSCUSTOMER C *IN50 DOUEQ*ON C READ JOURNOUT 50 C *IN50 IFEQ *OFF C MOVELJOESD OUTFMT C ENDIF C ENDDO C MOVE *ON *INLR *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
LATEST COMMENTS
MC Press Online