ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Compile RPGLE effect

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Hi Jon,
    Sadly, it still not worked. But still thanks a lot for your help.
    The program is new that I created for simulation.

    Hi Peder,
    Thank you for your advice.
    Magically its worked. I can't figure it out how just with put the CL program between the call can works. Can you explain why?
    Is this solution can be apply to RPG III too?

    Comment


    • #17
      Hi Alex
      It has to do with how a call behave.
      There is a difference between RPG and CL -- an important difference.

      I'm not sure if I explain this in the right way. But this is my layman view.

      When a RPG program call another program this program is loaded into the memory and the calling program "remembers"
      the address. This increases performance since the operating system doesn't have to search and load the program every time.

      When a CL program call another program it searches and loads the program every time.
      Of course this gives a little overhead but normally this is not a problem.
      Years ago it might have had an impact on performance but not today.

      When you replace a program the problem is that the reference the RPG program "remembers" is now invalid. The old program
      has gone. Unfortunately it doesn't reload the called program or references it in QRPGOBJ as it did in the OPM model.
      Now you simply get an error that the object referenced is ....... ( you know what I mean ).

      This problem does not exist with the CL program since it refrehes the reference every time called.

      I'm using the trick with the CL program when dealing with triggers for files with a few transactions.
      If you use a CL program as your trigger program for the file and this CL program calls a RPG program that handles the changes
      then you can allways implement changes to your RPG program without having to shut everything and everybody down.
      As you might know it normally requires that nobody it referring to the trigger program referenced by the file.

      I hope this helped you.

      Regards
      Peder

      Comment


      • #18
        You are right about the difference between CL and RPG Peder - but it is not an ILE vs OPM thing. RPG/400 does the same thing and was enhanced to cache the address even when using a variable name for the program back in (I think) V2R1.

        But the method I outlined of using a different name to force re-resolution of the program should work (and does at many many customers) and as soon as I have 5 I'll try and work out why it doesn't work for Alex.

        Comment


        • #19
          How it Works in RPG can be found in the RPG Reference manual. For V7R1 it is on page 443.

          Program references are grouped to avoid the overhead of resolving to the target
          program. All references to a specific program using a named constant or literal are
          grouped so that the program is resolved to only once, and all subsequent
          references to that program (by way of named constant or literal only) do not cause
          a resolve to recur.

          The program references are grouped if both the program and the library name are
          identical. All program references by variable name are grouped by the variable
          name. When a program reference is made with a variable, its current value is
          compared to the value used on the previous program reference operation that used
          that variable. If the value did not change, no resolve is done. If it did change, a
          resolve is done to the new program specified. Note that this rule applies only to
          references using a variable name. References using a named constant or literal are
          never re-resolved, and they do not affect whether or not a program reference by
          variable is re-resolved.


          So according to this JonBoy is right.


          Regards
          Peder

          Comment


          • #20
            Hi Peder,
            "When a CL program call another program it searches and loads the program every time." -> is this mean the program to be called will be reloaded every time even though the program using RETURN instead of *INLR=*ON ?

            Hi Jon,
            Please help and try why the code that I built before not worked. I want still want to keep the RETURN function (keep everything in memory until the object is replaced/recompiled).

            Comment


            • #21
              Alex,
              this is a great opportunity for you to make 3 test programs that simulates the situation you describe.
              Then you can tell us all what the result was.

              I must admit that I don't remember it but I would expect that the RETURN state would still be active.

              Regards
              Peder

              Comment


              • #22

                Peder,

                The RETURN function still working fine.
                I made 3 programs like this :

                *) RPGM700R (the looping program)
                =================================
                FRLOG0P IF A E DISK
                *
                d p_cmdexc pr extpgm('QCMDEXC')
                d cmddta 1000 options(*varsize)
                d cmdlen 15 5
                *
                d cmddtax s 1000
                d cmdlenx s 15 5
                d pgmname s 10 INZ('RPGM701C')
                *
                c dow *inlr='0'
                c call pgmname 77
                /free
                cmddtax='DLYJOB DLY(15)';
                cmdlenx=%len(cmddtax);
                Monitor;
                p_cmdexc(cmddtax:cmdlenx);
                On-Error;
                EndMon;
                /end-free
                c eval log='DELAY......................'
                c write RLOG
                c enddo
                c eval *inlr='1'


                *) RPGM701C
                ===========
                PGM
                CALL PGM(RPGM701R)
                ENDPGM



                *) RPGM701R
                ============
                frlog0p if a e disk
                *
                d counter## s 4s 0 inz(0)
                d counter@@ s 4a
                *
                c if counter##=9999
                c eval counter##=0
                c endif
                *
                c add 1 counter##
                c eval counter@@=%char(counter##)
                c eval log='Counter...(' + %trim(counter@@) + ')'
                c write rlog
                c return



                Then I did this step :
                1. SBMJOB CMD(CALL PGM(RPGM700R)) JOB(TEST01) JOBD(MI3)

                2. Monitor the log file, and the counter## variable in RPGM701R not reset.

                3. Update RPGM701R with this code statement and recompile it, without re-sbmjob
                c if counter##=1
                c eval log='Recompile'
                c write rlog
                c endif

                4. Monitor the log file, and the counter## variable reset for the 1st time call after recompile.


                File . . . . . . : RLOG0P Library . . . . : MI31
                Member . . . . . : RLOG0P Record . . . . . : 45
                Control . . . . . -1 Column . . . . . : 1
                Find . . . . . . .
                *...+....1....+....2....+....3....+....4....+....5 ....+....6....+....7....+..
                Counter...(23)
                DELAY......................
                Counter...(24)
                DELAY......................
                Counter...(25)
                DELAY......................
                Counter...(26)
                DELAY......................
                Counter...(27)
                DELAY......................
                Recompile
                Counter...(1)
                DELAY......................
                Counter...(2)
                DELAY......................
                Counter...(3)
                ****** END OF DATA ******



                So, the RETURN function still works properly, and I suppose the file still in OPEN state (no OPEN-CLOSE for each call), and I think the performance can be considered still very good.

                Comment


                • #23
                  Sorry for the mess posting above. I can't post the text properly because the textbox for posting always in status "Connection failed: Unknown database 'analytics'". Will try to edit if the textbox function back to normal.

                  Update : Already fix the posting above

                  Comment


                  • #24
                    Originally posted by Alex View Post

                    Hi Jon,
                    Please help and try why the code that I built before not worked. I want still want to keep the RETURN function (keep everything in memory until the object is replaced/recompiled).
                    Not sure and I haven't got the time to reformat your code to test it. I have however just produced a couple of test programs to prove my original statement and it works as I expected.

                    Note: It _only_ works when DUMMY is a real program and can be resolved. I _think_ it used to also work with a non-existent program but it certainly works when the program is real and can be resolved.

                    Here's the main driver program:
                    Code:
                           Ctl-Opt  DftActGrp(*Yes);
                    
                           Dcl-S  targetName Char(10);
                    
                           Dcl-S  wait  Char(1);
                    
                           Dcl-Pr  callPgm ExtPgm(targetName) End-Pr;
                    
                           targetName = 'TARGET';
                           callPgm();
                    
                           targetName = 'DUMMY';
                           CallP(e) callPgm();
                    
                           If %Error;
                             Dsply (' Call to ' + targetName + ' failed' );
                           endif;
                    
                           Dsply ('Recompile new version of TARGET and press Enter') ' ' wait;
                    
                           targetName = 'TARGET';
                           callPgm();
                    
                           Dsply ('Check to see if that worked then press Enter') ' ' wait;
                    
                           *InLR = *ON;
                    This is the target program:

                    Code:
                           ctl-opt dftactgrp(*Yes);
                           Dsply 'Target V1' ;
                           Return;
                    And this is the DUMMY program:

                    Code:
                           ctl-opt dftactgrp(*Yes);
                           Dsply 'Dummy program called';
                           *InLr = *On;

                    Comment


                    • #25
                      Hi Jon,

                      I re-check my program, looks like I miss the 'else' statement for reset the pgmname variable.
                      Its working now with your advice, and now my challenge is how to trigger so the main program can call "dummy-which exist" program after the new program implemented.
                      I have more than 1 job using (QRCV) the same dataqueue so I can't send the trigger via dataqueue message because there is possibility some job don't get the message.
                      Because of this situation, I think "put CL before call RPG/RPGLE" approach is more easier to implement.
                      Need your advice, what do you think between the 2 approach? If the "put CL" approach is not hurting performance (because the RETURN function still work fine), I will choose that.

                      Thanks a lot for your help

                      Comment


                      • #26
                        I'm having a hard time seeing how the CL program helps. For DQ driven jobs you still need a way to signal that the switch is needed.

                        As I said in one of my earlier posts - one approach that works well is to use a data area (or user space) associated with the program. It would contain a timestamp (or other unique Id) that reflects the latest version of the program. So the sequence of the normal call is this:

                        Retrieve Data Area or map to User Space if needed

                        Code:
                        If programCopyOfTimestamp <> currentMasterValue
                           programName = dummyProgram
                           call programName
                           programName = realProgram
                           programCopyOfTimestamp = currentMasterValue
                        EndIf
                        
                        call programName
                        That's it. The only other thing you need to do is to ensure that every time a new version of the program is deployed that the process also updates the currentMasterValue.

                        I personally prefer a User space as once the pointer is resolved then there is no overhead of reading the data area value each time - it is just "there".

                        Comment


                        • #27
                          Jon, is that mean I have to retrieve user space/data area value before EACH call? If the current value <> before value then I have to call dummyprogram to resolve the pointer.

                          By the way, when will QRPLOBJ temporary object will be deleted? I read some articles said it will be deleted on IPL.
                          But I have some cases when I recompile some programs and not restart the job, then the job went to MSGW status (said like pointer or reference not .... - i forgot the detail message).

                          Comment


                          • #28
                            The solution that JonBoy shows might work. But I find it is simpler to test if the call to the program fails and then check
                            *STATUS in the Program Status Data Structure.
                            I would expect that it has the value 00211 Error calling program or procedure.

                            It could be something with MONITOR surrounding the call and then testing ON-ERROR 00211 etc.

                            Comment


                            • #29
                              Originally posted by Peder Udesen View Post
                              The solution that JonBoy shows might work. But I find it is simpler to test if the call to the program fails and then check
                              *STATUS in the Program Status Data Structure.
                              I would expect that it has the value 00211 Error calling program or procedure.

                              It could be something with MONITOR surrounding the call and then testing ON-ERROR 00211 etc.
                              I don't see how this helps Peder. The problem the OP faces is that when a program is replaced the old one continues to be called. There is no error to trap.

                              Comment


                              • #30
                                Originally posted by Alex View Post
                                Jon, is that mean I have to retrieve user space/data area value before EACH call? If the current value <> before value then I have to call dummyprogram to resolve the pointer.
                                If you use a data area then you have to input it on each call. If you use a user space then all you have to do is resolve the pointer on the first call (Via INZSR perhaps) - as long as the program remains active the pointer will be valid and therefore the data is immediately available.
                                By the way, when will QRPLOBJ temporary object will be deleted? I read some articles said it will be deleted on IPL.
                                But I have some cases when I recompile some programs and not restart the job, then the job went to MSGW status (said like pointer or reference not .... - i forgot the detail message).
                                They are cleaned up at IPL. Programs in use will be locked but I think the lock only holds while they are active on the stack and that may be the situation you have encountered. Not sure why you are concrned though since the proposed approach should avoid any calls to old versions anyway.

                                Comment

                                Working...
                                X