Last week I received a telephone call from my manager, "Jane Smith (her name has been changed to protect the innocent) cannot signon as she is getting some kind of an error message," he explained. "Can you help her?" Jane's problem was that the job description her user profile used was damaged. I quickly copied the one from the development IBM i partition and Jane was able to signon. When I reported this to my manager he asked the obvious question: "How many other damaged objects do we have?"
That is something most of us never encounter due to the robustness of the IBM i operating system. What I needed was a process to identify any damaged objects before they are used and cause errors. The question is how can you identify a damaged object without using it?
Fortunately I knew there was an output field from the Display Object Description command, DSPOBJD, that would tell me. I looked at all the columns in the SQL Views I have written about before, but could not find an equivalent column.
The field ODOBDM, Object Damaged, can contain one of three values:
- 0 = Object is not damaged
- 1 = Object is fully damaged
- 2 = Object is partially damaged
IBM has a lot of information about recovering damaged objects. You will find a link to that information at the bottom of this post.
Before I can determine what can be done to recover any damaged objects I need to identify them. This is what the CL program below does:
01 PGM 02 DCL VAR(&RECORDS) TYPE(*DEC) LEN(10 0) 03 DCL VAR(&USER) TYPE(*CHAR) LEN(10) 04 DLTF FILE(QTEMP/WDSPOBJD) 06 MONMSG MSGID(CPF0000) 07 DSPOBJD OBJ(*ALL/*ALL) OBJTYPE(*ALL) + OUTPUT(*OUTFILE) OUTFILE(QTEMP/WDSPOBJD) 08 RUNSQL SQL('DROP TABLE MYLIB/DAMAGED') COMMIT(*NC) 09 MONMSG MSGID(SQL9010) 10 RUNSQL SQL('CREATE TABLE MYLIB/DAMAGED AS + (SELECT ODOBDM,ODLBNM,ODOBNM,ODOBTP,ODOBAT,+ ODOBTX + FROM QTEMP/WDSPOBJD + WHERE ODOBDM <> 0) + WITH DATA') + COMMIT(*NC) 11 DLTF FILE(QTEMP/WDSPOBJD) 12 RTVJOBA USER(&USER) 13 RTVMBRD FILE(MYLIB/DAMAGED) NBRCURRCD(&RECORDS) 14 IF COND(&RECORDS = 0) THEN(DO) 15 SNDMSG MSG('There are no damaged objects') + TOUSR(&USER) 16 RUNSQL SQL('DROP TABLE MYLIB/DAMAGED') COMMIT(*NC) 17 ENDDO 18 ELSE CMD(SNDMSG MSG('There are ' || %CHAR(&RECORDS) |< + ' damaged objects. For details + look in file MYLIB/DAMAGED') + TOUSR(&USER)) 19 ENDPGM |
Line 7: The DSPOBJD command is run to list all objects in all libraries, and output to an output file in QTEMP. This is going to take a very long time, which is why I strongly recommend submitting this program to batch in a job queue where it will not hold up other jobs. I could have had this program submit itself to batch, to see how see here. I do not have that logic in this program as this is on the job scheduler, to be submitted to batch once a week.
Line 8: I am going to copy the data for any damaged objects from the DSPOBJD outfile to another file/table, therefore, I am deleting any existing table/file. I could have used a DLTF to delete the file, but I decided to use DROP TABLE instead which does the same thing.
Line 10: I am creating a table to include a list of the damaged records, ODOBDM <> 0. I call creating a table like this creating one "on the fly", you can learn more about how to do this in the post Creating a SQL table "on the fly".
The new table will including the columns/fields:
- ODOBDM - Severity of the damage
- ODLBNM – Library
- ODOBNM – Object name
- ODOBTP - Object type (*PGM, *FILE, *JOBD, etc)
- ODOBAT - Object attribute (RPGLE, CLLE, DSPF, PF-DTA, etc)
- ODOBTX - Object text (description)
Line 11: Those of you who know me know that I do not like leaving large files around after I have used them, even if they are in QTEMP. Which is why I delete the output file from the DSPOBJD command as soon as I am finished with it.
Line 13: I am retrieving the number of records/rows from the new Table.
Lines 14 – 17: If there are no records/rows in the table then there were no damaged objects. I send a message to whomever called this program, user name retrieved on line 12, saying that, line 15, and delete/drop the table I created, line 16.
Line 18: If there are records in the table then I send a message with the number of damaged records. The %CHAR built in function was introduced in IBM i 7.2 and I believe 7.1 TR8. If you are on an earlier release or TR you will need to replace it with your own logic to remove the leading zeros.
When the program is run and there are damaged objects the following message is sent:
Display Messages System: XXXXXXXX Queue . . . . . : SIMON Program . . . . : *DSPMSG Library . . . : QUSRSYS Library . . . : Severity . . . : 00 Delivery . . . : *BREAK Type reply (if required), press Enter. From . . . : SIMON DD/DD/DD HH:HH:HH There are 2 damaged objects. For details look in file QTEMP/DAMAGED |
As the saying goes "forewarned is forearmed", I can now go and determine what I need to do to fix those two damaged objects.
You can learn more about this from the IBM website:
- IBM: Recovering from damaged objects and unreadable sectors
- IBM: DSPOBJD command
- RPGPGM.COM: Char built in function added to CL
This article was written for IBM i 7.2, and should work for earlier releases too except for the %CHAR.
Nice tip. Thanks.
ReplyDeleteChris Ringer
Yeah, i have this kind of program running every week.
ReplyDeleteSimon - Good job:)
ReplyDeleteI had to rewrite a little to my system, but it's working.
Pawel Palys
Thank you!!!
ReplyDeleteHi Simon
ReplyDeleteUnder my tests I have observed some problems:
1. When I run DSPOBJD on library which is empty (no objects), this command returns error and breaks program.
I suggest to add after:
MONMSG MSGID (CPF2123) EXEC(GOTO CMDLBL(END))
and add label "END" at the end of program.
2. In command: "RUNSQL SQL('CREATE TABLE....WHERE ODOBDM <> 0...." I suggest change to: ODOBDM <> ''0''.
I had some errors, because on result of this command was builded a table MYLIB/DAMAGED. It have one record where field ODOBDM don't have any values.
The easiest way is to perform an Option 21 save, which you should be doing weekly anyway, the log will report any damaged objects.
ReplyDeleteWhile the transaction tables are backed up daily, other objects are usually backed up weekly. Then there are "Constant Objects" which do not change, and so they are never backed up except the first time backup.
DeleteHowever I agree that with option 21 there would be no need to run this program daily, but only when needed in urgency, as was the case of Simon.
It is also possible for Access Paths to be damaged, particular when a system suddenly shuts down whilst files are open. DSPFD TYPE(*MBR) will show where this is case via field MBINDX being set to N. The issue can be resolved by issuing an OPNDBF on said file/member which will then rebuild said access path. I'd also suggest referring to this article for means of finding damaged objects before the system has flagged them as damaged. https://www-01.ibm.com/support/docview.wss?uid=nas8N1019814
ReplyDelete