IBM i Housekeeping 101 – Deleting old Journal Receivers
Following on from the blog I wrote about “What is an IBM i Journal?“
We know that IBM i journals record what happens to files, and we know that this record is kept in these things called journal receivers.
What is a Journal Receiver?
An IBMi journal receiver is a component used in the journaling process on IBM’s IBMi (AS400/iSeries) systems. Here’s a brief overview:
- Purpose: The journal receiver is where the journal entries are actually recorded. It captures all changes made to the objects being journaled, such as updates, deletions, and additions.
- Function: When a journal is created, it must be associated with a journal receiver. The receiver stores the detailed records of all changes, which can be used for recovery, auditing, or replication purposes.
- Management: Journal receivers can be configured to fit specific needs, including setting their size and managing their lifecycle. They are “bound” to the journal, meaning they work together to ensure data integrity and consistency.
Now – since a journal can record thousands, millions or even squillions of updates to any given file, what happens to the RECEIVER when they get full of data?
IBM-i will create a new receiver and detach the old one.
So – any given journal can have 1, 2, 3, 4, 5, and so on receivers on the system. It will always be connected to, pointed at, the most recent receiver.
Once a receiver is disconnected it’s frozen and no new updates will be stored there.
All new updates will be stored in the next newer receiver in the chain.
How do we DELETE (PURGE) old JOURNAL RECEIVERS as part of our housekeeping?
Let’s take a simple CMD and CL program to do exactly that.
disclaimer – I’m not going to add nice error handling and messaging. That bit is up to you. This is just a quick utility built on these premises (1) you have backed up your receivers (2) you are not testing this on production (3) use at your own risk 😉
Me.
CODE EXAMPLE – PURGE JOURNAL RECEIVER
CMD
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *-*/
/* Delete Journal Receivers *-*/
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *-*/
/* Command Id ....... PRGJRNRCV *-*/
/* Calling Program .. Command=PRGJRNCPP *-*/
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *-*/
/* Apr 2022 - Nick Litten - Created *-*/
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *-*/
CMD PROMPT('Purge Journal Receivers')
PARM KWD(JRNRCV) TYPE(JRNFILPRM) PROMPT('Journal +
Receiver')
JRNFILPRM: QUAL TYPE(*GENERIC) LEN(10) SPCVAL((*ALL *ALL)) +
MIN(1) EXPR(*YES) PASSATR(*YES)
QUAL TYPE(*CHAR) LEN(10) DFT(*LIBL) +
SPCVAL((*ALLUSR) (*ALL) (*USRLIBL) +
(*LIBL) (*CURLIB)) EXPR(*YES) +
PASSATR(*YES) PROMPT('Library')
To Compile — CRTCMD CMD(yourlib/PRGJRNRCV) PGM(PRGJRNCPP)
CLLE
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* Purge Journal Receivers */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* Program Id ....... PRGJRNCPP */
/* Calling Program .. Command=PRGJRNRCV */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* Apr 2022 - Nick Litten - Created */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
PGM PARM(&PARMJRNRCV)
DCL VAR(&PARMJRNRCV) TYPE(*CHAR) LEN(22)
DCL VAR(&RCVHEXGEN) TYPE(*CHAR) LEN(1)
DCL VAR(&RCV) TYPE(*CHAR) LEN(10)
DCL VAR(&LIBHEXGEN) TYPE(*CHAR) LEN(11)
DCL VAR(&LIBRARY) TYPE(*CHAR) LEN(10)
DCL VAR(&COUNT) TYPE(*DEC) LEN(7 0)
DCL VAR(&COUNTALF) TYPE(*CHAR) LEN(7)
DCL VAR(&ENDSTS) TYPE(*CHAR) LEN(1) VALUE('0')
DCLF FILE(QADSPOBJ)
SNDPGMMSG MSG(('Loading list of all +
Journal Receivers in lib(' *TCAT &LIBRARY *TCAT ')')
CHGVAR VAR(&RCVHEXGEN) VALUE(%SST(&PARMJRNRCV 1 1))
CHGVAR VAR(&RCV) VALUE(%SST(&PARMJRNRCV 02 10))
CHGVAR VAR(&LIBHEXGEN) VALUE(%SST(&PARMJRNRCV 12 1))
CHGVAR VAR(&LIBRARY) VALUE(%SST(&PARMJRNRCV 13 10))
DSPOBJD OBJ(&LIBRARY/&RCV) OBJTYPE(*JRNRCV) OUTPUT(*OUTFILE) +
OUTFILE(QTEMP/PRGJRNRCV)
OVRDBF FILE(QADSPOBJ) TOFILE(QTEMP/PRGJRNRCV)
LOOP:
DOWHILE COND(&ENDSTS = '0')
RCVF
MONMSG MSGID(CPF0864) EXEC(LEAVE)
IF COND(&ODSDAT *NE ' ') THEN(DO)
SNDPGMMSG MSG('Purging' *BCAT +
&ODLBNM *TCAT '/' *TCAT &ODOBNM *TCAT '...')
/* -- This is where you could add some logic to check if the receiver has been saved, or select by date, or name, or whatever... go on do it... make this code prettier */
DLTJRNRCV JRNRCV(&ODLBNM/&ODOBNM) DLTOPT(*IGNINQMSG)
CHGVAR VAR(&COUNT) VALUE(&COUNT + 1)
ENDDO
RTVJOBA ENDSTS(&ENDSTS)
ENDDO
LEAVE:
CHGVAR VAR(&COUNTALF) VALUE(&COUNT)
SNDPGMMSG MSG('Purge Journal Receivers +
completed with' *bcat &countalf *tcat ' processed.')
DLTOVR FILE(QADSPOBJ)
MONMSG MSGID(CPF0000)
DLTF FILE(QTEMP/PRGJRNRCV)
MONMSG MSGID(CPF0000)
RETURN
ENDPGM: ENDPGM
To Compile —
CRTBNDCL PGM(YOURLIB/PRGJRNCPP) SRCFILE(QCLLESRC) SRCMBR(PRGJRNCPP)
And that’s that. Hope it helps…
are you aware there is a command in QSYS already called DLTJRNRCV?
while I carefully commented out the the line
/* DLTJRNRCV JRNRCV(&ODLBNM/&ODOBNM) DLTOPT(*IGNINQMSG)*/
in the cl pgm, the original command deleted them anyway.
some typos in CL
line 2 /- should be /*
SNDPGMMSG MSG((‘Loading list of all +
Journal Receivers in lib(‘ *TCAT &LIBRARY *TCAT ‘)’)
remove first (
Hi “Da”
This is a CL Program that wraps around the IBM-i system DLTJRNRCV command. This CL has a purpose of building a list of Journal Receivers, and then as it reads through that list it runs a DLTJRNRCV on each one.
Sorry about the typos – copy/paste sometimes poops when pasting ‘*’ into the website. I fixed them.
You’ve inspired me to add this code to my free CL PROGRAMMING lessons – I will update here when I’ve recorded an example lesson uploading this code and running it. Hopefully that will answer all your questions 😉