Tools

59. ユーザー待ち行列をクリヤーする CLRUSRQ

ユーザー待ち行列 ( *USRQ ) はデータ待ち行列 ( *DTAQ ) と良く似たオブジェクトであるが
データ待ち行列 ( *DTAQ ) に比べてユーザー待ち行列 ( *USRQ ) の実体はメモリであるので
パフォーマンスが圧倒的に優れている。
従ってソフトウェア製品に利用するのであれば *DTAQ より *USRQ を利用すべきである。
ところが

  • ユーザー待ち行列の作成 : API: QUSCRTUQ
  • ユーザー待ち行列の削除 : API: QUSDLTUQ


と2つの API が用意されているのだがクリヤーする API は用意されていない。
それではクリヤーする機能は必要ないのかというと大いに必要である。
ユーザー待ち行列にメッセージ(データ)が投入された後、それを読取ると
二度とそのデータを読取ることはできない。
するといつまでもおおよそ空の状態が続くので再編成やクリヤーは
必要ないように思えるのだが、物理ファイル ( PF ) で削除レコードが
元のレコード域を削除後もいつまでも占有しているのと同じように、
ユーザー待ち行列もメッセージ(レコード)数はないのにやがては
満杯になって使用できなくなってしまうのである。
そこで適切な時期に中身をクリヤー(消去)するという作業が必要となってくる。

*DTAQ には QCLRDTAQ という名前の API が用意されていたが、
*USRQ には QCLRUSRQ という API は用意されていない。
そこで今回は、QCLRUSRQ というデータ待ち行列をクリヤーする API を
作成してみた。

【 コマンド : CLRUSRQ 】
0001.00              CMD        PROMPT(' ユーザー待ち行列のクリヤー ')      
0002.00              PARM       KWD(USRQ) TYPE(USRQ) MIN(1) +               
0003.00                           PROMPT(' データ待ち行列 ')                
0004.00  USRQ:       QUAL       TYPE(*NAME) LEN(10) MIN(1)                  
0005.00              QUAL       TYPE(*NAME) LEN(10) DFT(*LIBL) +            
0006.00                           SPCVAL((*LIBL) (*CURLIB)) +               
0007.00                           PROMPT(' ライブラリー ')                  
0008.00              PARM       KWD(CLEAR) TYPE(*CHAR) LEN(10) RSTD(*YES) + 
0009.00                           DFT(*ALL) VALUES(*ALL *KEEP) +            
0010.00                           PROMPT(' クリヤー ')                      
[ コンパイル ]
CRTCMD CMD(MYLIB/CLRUSRQ) PGM(MYLIB/CLRUSRCL) SRCFILE(MYSRCLIB/QCMDSRC)AUT(*ALL)
【 解説 】

コマンド: CLRUSRQ はパラメータ : CLEAR を持っているが、
これは既存のユーザー待ち行列の中身を維持して消去するのかまたは、
すべて消去してまうのかを指定するためである。

【 CLP : CLRUSRQCL 】
0001.00              PGM        PARM(&USRQLIB &CLEAR)                           
0002.00 /*-------------------------------------------------------------------*/ 
0003.00 /*   CLRUSRQCL :    ユーザー待ち行列のクリヤー                       */ 
0004.00 /*                                                                   */ 
0005.00 /*   2017/05/03  作成                                                */ 
0006.00 /*-------------------------------------------------------------------*/ 
0007.00              DCL        VAR(&USRQLIB) TYPE(*CHAR) LEN(20)               
0008.00              DCL        VAR(&USRQ) TYPE(*CHAR) LEN(10)                  
0009.00              DCL        VAR(&USRLIB) TYPE(*CHAR) LEN(10)                
0010.00              DCL        VAR(&CLEAR) TYPE(*CHAR) LEN(10)                 
0011.00              DCL        VAR(&MSG) TYPE(*CHAR) LEN(132)                  
0012.00              DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                  
0013.00              DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)                  
0014.00              DCL        VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)               
0015.00              DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(132)               
0016.00              DCL        VAR(&TYPE) TYPE(*CHAR) LEN(1)                   
0017.00              DCL        VAR(&TOPGMQ) TYPE(*CHAR) LEN(10)                
0018.00              DCL        VAR(&ERR) TYPE(*CHAR) LEN(1)                    
0019.00              DCL        VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) +             
0020.00                           VALUE('*ESCAPE   ')                           
0021.00              DCL        VAR(&APIERR) TYPE(*CHAR) LEN(116) +            
0022.00                           VALUE(X'000074') /* 2 進数  */               
0023.00              DCL        VAR(&NULL4) TYPE(*CHAR) LEN(4) +               
0024.00                           VALUE(X'00000000')                           
0025.00              MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))        
0026.00                                                                        
0027.00 /*( 環境の取得 )*/                                                     
0028.00              RTVJOBA    TYPE(&TYPE)                                    
0029.00              IF         COND(&TYPE *EQ '0') THEN(DO) /*  バッチ  */    
0030.00              CHGVAR     VAR(&TOPGMQ) VALUE('*SYSOPR   ')               
0031.00              ENDDO      /*  バッチ  */                                 
0032.00              ELSE       CMD(DO) /*  対話式  */                         
0033.00              CHGVAR     VAR(&TOPGMQ) VALUE('*TOPGMQ   ')               
0034.00              ENDDO      /*  対話式  */                                 
0035.00                                                                        
0036.00 /*( パラメータの取得 )*/                                               
0037.00              CHGVAR     VAR(&USRQ) VALUE(%SST(&USRQLIB 01 10))         
0038.00              CHGVAR     VAR(&USRLIB) VALUE(%SST(&USRQLIB 11 10))       
0039.00                                                                        
0040.00 /*( USRQ の確保 )*/                                                    
0041.00          /*  ALCOBJ     OBJ((&USRQLIB/&USRQ *USRQ *EXCL)) WAIT(3) */   
0042.00                                                                      
0043.00 /*( USRQ のクリヤー )*/                                              
0044.00              CALL       PGM(SPOOLWTR/QCLRUSRQ) PARM(&USRQ &USRLIB +  
0045.00                           &CLEAR &ERR &MSG)                          
0046.00           /* DLCOBJ     OBJ((&USRQLIB/&USRQ *USRQ *EXCL))  */        
0047.00              IF         COND(&ERR *EQ 'E') THEN(DO)                  
0048.00              GOTO       SNDMSG                                       
0049.00              ENDDO                                                   
0050.00                                                                      
0051.00 /*( 完了メッセージ )*/                                               
0052.00              CHGVAR     VAR(&MSG) VALUE(' ユーザー待ち行列 ' *CAT +  
0053.00                           &USRLIB *TCAT '/' *CAT &USRQ *TCAT +       
0054.00                           ' をクリヤーしました。 ')                  
0055.00              CHGVAR     VAR(&MSGTYPE) VALUE('*DIAG     ')            
0056.00              GOTO       SNDMSG                                       
0057.00              RETURN                                                  
0058.00                                                                      
0059.00  APIERR:                                                             
0060.00              CHGVAR     VAR(&MSGID) VALUE(%SST(&APIERR 9 7))         
0061.00              CHGVAR     VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100))     
0062.00              CHGVAR     VAR(&MSGF) VALUE('QCPFMSG   ')               
0063.00              CHGVAR     VAR(&MSGFLIB) VALUE('QSYS      ')            
0064.00              GOTO       SNDMSG                                       
0065.00                                                                      
0066.00  ERROR:      RCVMSG     MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) +          
0067.00                           MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +
0068.00                           MSGFLIB(&MSGFLIB)                          
0069.00  SNDMSG:     IF         COND(&MSGID *EQ ' ') THEN(DO)                
0070.00              SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) +  
0071.00                           TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE)          
0072.00              ENDDO                                                   
0073.00              ELSE       CMD(DO)                                      
0074.00              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +         
0075.00                           MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) +          
0076.00                           MSGTYPE(&MSGTYPE)                          
0077.00              ENDDO                                                   
0078.00              ENDPGM                                                  
[ コンパイル ]
CRTCLPGM PGM(MYLIB/CLRUSRQCL) SRCFILE(MYSRCLIB/QCLSRC) AUT(*ALL)

【 C/400 : QCLRUSRQ 】
0001.00 /********************************************************************/  
0002.00 /*                                                                  */  
0003.00 /*   QCLRUSRQ    :   ユーザー待ち行列のクリヤー                     */  
0004.00 /*                                                                  */  
0005.00 /*          Office Quattro Co,.Ltd 2018/05/03 20:34:08 created      */  
0006.00 /*                                                                  */  
0007.00 /*                                                                  */  
0008.00 /********************************************************************/  
0009.00 #pragma comment(COPYRIGHT, "Spool Writer Ver5.0  (C) CopyRight ™        
0010.00 Office Quattro.Corp. 2018- All right reserved. Users Restricted ™       
0011.00 Rights - Use, duplication or disclosure restricted by Office Quattro ™  
0012.00 Corp. Licenced Materials-Property of Office Quattro.")                  
0013.00 #include                                                       
0014.00 #include                                                      
0015.00 #include                                                      
0016.00 #include  /* triml */                                       
0017.00 #include                                                       
0018.00 #include                                                      
0019.00 #include                                                     
0020.00 #include                                                    
0021.00 #include                                                    
0022.00                                                                         
0023.00 #define TRUE         0                                                  
0024.00 #define FALSE       -1                                                  
0025.00 int    bLR = FALSE;                                                     
0026.00 typedef struct {                                                        
0027.00    int  BYTESPRO;                                                       
0028.00    int  BYTESAVL;                                                       
0029.00    char MSGID[7];                                                       
0030.00    char RESRVD;                                                         
0031.00    char EXCPDATA[100];                                                  
0032.00 } ERRSTRUCTURE;     /* Define the error return structure            */  
0033.00 ERRSTRUCTURE  errcode;/* Error Code Structure for RCVMSG      */        
0034.00 volatile _INTRPT_Hndlr_Parms_T ca;                                      
0035.00                                                                         
0036.00 /*************************************************************/         
0037.00 /*       内 部 使 用  関  数                          */         
0038.00 /*************************************************************/         
0039.00 void  GetParam(int argc, char *argv[]);                                 
0040.00 void  INZSR(void);                                                      
0041.00 void  LRRTN(char *argv[]);                                              
0042.00                                                                        
0043.00 /*************************************************************/        
0044.00 /*       IMPORT  関  数                            */        
0045.00 /*************************************************************/        
0046.00 /*************************************************************/        
0047.00 /*       IMPORT  変  数                            */        
0048.00 /*************************************************************/        
0049.00 /*************************************************************/        
0050.00 /*       外 部 呼 出 し  関  数                      */        
0051.00 /*************************************************************/        
0052.00 void MonitorMSG(_INTRPT_Hndlr_Parms_T ca, char* ref);                  
0053.00 #pragma linkage(MonitorMSG, OS)                                        
0054.00 #pragma map(MonitorMSG, "ASNET.COM/MONMSG")                            
0055.00 /*************************************************************/        
0056.00 /*        グ ロ ー バ ル 変 数                         */        
0057.00 /*************************************************************/        
0058.00   /*------( 受取りパラメータ値 )----------*/                           
0059.00   char USRQ[11], USRQLIB[11], CLEAR[11], ERR[2], MSG[122];             
0060.00   /*------( 受取りパラメータ値 )----------*/                           
0061.00   char ref[133], usrq[11], usrqlib[11];                                
0062.00 /********************************************************************/ 
0063.00 /*            m  a  i  n --- main module of this pgm                */  
0064.00 /*                                                                  */  
0065.00 /*           1. USRQ                                     */  
0066.00 /*                      2. USRQLIB                                  */  
0067.00 /*                      3. CLEAR                                    */  
0068.00 /*                      4. ERR                                      */  
0069.00 /*                      5. MSG                                      */  
0070.00 /*                                                                  */  
0071.00 /*------------------------------------------------------------------*/  
0072.00                                                                         
0073.00 int  main(int argc, char *argv[]){                                      
0074.00   _MQAT_Template_T que_attributes; /* receiver template for matcat */   
0075.00   _SYSPTR   queue;                                                      
0076.00   int Num_Msgs; /* 現在のレコード数 */                                  
0077.00   int Max_Msgs; /* 最大数 */                                            
0078.00   int Extension; /* 追加回数 */                                         
0079.00   int Max_Size;  /* 最大サイズ */                                       
0080.00   int Init_Msgs; /* 初期メッセージ数 */                                 
0081.00   short Key_Length; /* キー長 */                                        
0082.00   int  Q_Type;   /* ユーザー待ち行列のタイプ */                         
0083.00   char Type[2];  /* ユーザー待ち行列のタイプ */                         
0084.00   char USRQQLIB[21], text[51], cmd[256], rcvbuf[4092];              
0085.00    _DEQ_Msg_Prefix_T d_msg_prefix;                                  
0086.00    _ENQ_Msg_Prefix_T e_msg_prefix;                                  
0087.00    _SYSPTR old_queue, new_queue;                                    
0088.00                                                                     
0089.00    #pragma exception_handler(MONMSG, ca, 0, _C2_MH_ESCAPE, ™        
0090.00                                             _CTLA_HANDLE)           
0091.00    GetParam(argc, argv);  /*[ パラメータの取得 ]*/                  
0092.00    INZSR();               /*[ 初期設定 ]*/                          
0093.00                                                                     
0094.00    queue   = rslvsp(_Usrq, USRQ, USRQLIB, _AUTH_ALL);               
0095.00    que_attributes.Template_Size = sizeof(_MQAT_Template_T);         
0096.00    matqat(&que_attributes, queue);                                  
0097.00                                                                     
0098.00    Num_Msgs  = que_attributes.Num_Msgs;                             
0099.00    Max_Msgs  = que_attributes.Max_Msgs;                             
0100.00    Extension = que_attributes.Extension;                            
0101.00    Max_Size  = que_attributes.Max_Size;                             
0102.00    Init_Msgs = que_attributes.Init_Msgs;                            
0103.00    Q_Type    = que_attributes.Q_Type;                               
0104.00    switch(Q_Type){/*switch*/                                        
0105.00    case 0:    strcpy(Type, "K"); break;                                 
0106.00    case 1:    strcpy(Type, "L"); break;                                 
0107.00    case 2:    strcpy(Type, "F"); break;                                 
0108.00    }/*switch*/                                                          
0109.00    if(strncmp(Type, "K", 1) != 0) Key_Length = 0;                       
0110.00                                                                         
0111.00    sprintf(USRQQLIB, "%10s%10s", USRQ, USRQLIB);                        
0112.00    if(Num_Msgs > 0 && strncmp(CLEAR, "*KEEP     ", 10) == 0){/* 複製 */ 
0113.00      /*( 現行 USRQ を QTEMP に移す )*/                                  
0114.00      sprintf(cmd, "MOVOBJ OBJ(%s/%s) OBJTYPE(*USRQ) TOLIB(QTEMP)",      
0115.00            usrqlib, usrq);                                              
0116.00      system(cmd);                                                       
0117.00    }/* 複製 */                                                          
0118.00    else{/* 新規再作成 */                                                
0119.00      /*( 不要であれば削除する )*/                                       
0120.00      sprintf(cmd, "DLTUSRSPC USRSPC(%s/%s )", usrqlib, usrq);           
0121.00      system(cmd);                                                       
0122.00    }/* 新規再作成 */                                                    
0123.00    QUSCRTUQ(USRQQLIB, "PF        ", Type, Key_Length, Max_Size, Init_Ms 
0124.00              Extension, "*ALL      ", text, "*NO       ", &errcode);    
0125.00    if(Num_Msgs > 0 && strncmp(CLEAR, "*KEEP     ", 10) == 0){/* 複製 */ 
0126.00      /*( OLD QUEUE から NEW QUEUE へデータを転送する )*/         
0127.00      old_queue = rslvsp(_Usrq, USRQ, "QTEMP     ", _AUTH_ALL);   
0128.00      new_queue = rslvsp(_Usrq, USRQ, USRQLIB, _AUTH_ALL);        
0129.00      d_msg_prefix.Wait_Forever = -1;/*nowait*/                   
0130.00      memset(d_msg_prefix.Wait_Time, 0, sizeof(_MI_Time));        
0131.00      while(1){/*while*/                                          
0132.00        if(deqi(&d_msg_prefix, rcvbuf, old_queue) == 0) break;    
0133.00        e_msg_prefix.Msg_Len = strlen(rcvbuf);                    
0134.00        enq(new_queue, &e_msg_prefix, rcvbuf);/* SNDUSRQ*/        
0135.00      }/*while*/                                                  
0136.00      sprintf(cmd, "DLTUSRSPC USRSPC(QTEMP/%s)", usrq);           
0137.00      system(cmd);                                                
0138.00    }/* 複製 */                                                   
0139.00                                                                  
0140.00    LRRTN(argv);                                                  
0141.00    exit(0);                                                      
0142.00                                                                  
0143.00 MONMSG:                                                          
0144.00    #pragma disable_handler                                       
0145.00    if(strncmp((char*)&ca.Msg_Id, "MCH3401", 7) == 0){/*NOT FOUND*
0146.00      sprintf(MSG, " ユーザー待ち行列 %s/%s が見つかりません。 ", 
147.00         usrqlib, usrq);                        
148.00      ERR[0] = 'E';                             
149.00      LRRTN(argv);                              
150.00      exit(-1);                                 
151.00    }/*NOT FOUND*/                              
152.00    MonitorMSG(ca, ref);                        
153.00                                                
154.00    exit(0);                                    
155.00 }                                              
156.00 /*************************************/        
157.00 void  GetParam(int argc, char *argv[])         
158.00 /*************************************/        
159.00 {                                              
160.00    memcpy(USRQ, argv[1], 10);                  
161.00    USRQ[10] = 0x00;                            
162.00    memcpy(USRQLIB, argv[2], 10);               
163.00    USRQLIB[10] = 0x00;                         
164.00    memcpy(CLEAR, argv[3], 10);                 
165.00    CLEAR[10] = 0x00;                           
166.00 }                                              
167.00 /****************/                             
0168.00 void  INZSR(void)                        
0169.00 /****************/                       
0170.00 {                                        
0171.00    errcode.BYTESPRO = 160;               
0172.00    errcode.BYTESAVL = 0;                 
0173.00    strcpy(usrq, USRQ);                   
0174.00    usrq[triml(usrq, ' ')] = 0x00;        
0175.00    strcpy(usrqlib, USRQ);                
0176.00    usrqlib[triml(usrqlib, ' ')] = 0x00;  
0177.00 }                                        
0178.00 /************************/               
0179.00 void  LRRTN(char *argv[])                
0180.00 /************************/               
0181.00 {                                        
0182.00    if(bLR == TRUE) return;               
0183.00    bLR = TRUE;                           
0184.00    memcpy(argv[4], ERR, 1);              
0185.00    strcpy(argv[5], MSG);                 
0186.00 }                                        
[ コンパイル ]
CRTBNDC PGM(MYLIB/QCLRUSR) SRCFILE(MYSRCLIB/QCSRC) AUT(*ALL)

【 解説 】

QCLRUSR は C言語として書かれているがそのままコンパイルすれば
言語は知らなくてもかまわない。
C言語を知らない人のために処理の概要を説明すると

(1)現在の *USRQ の属性 ( que_attributes ) を matqat ( MI ) によって
取得しておく matqat は知らない人も多いかも知れないが
*USRQ の属性を取得する MI ( = Machine Interface )である。

0001.00              CMD        PROMPT(' ユーザー待ち行列のクリヤー ')      
0002.00              PARM       KWD(USRQ) TYPE(USRQ) MIN(1) +               
0003.00                           PROMPT(' データ待ち行列 ')                
0004.00  USRQ:       QUAL       TYPE(*NAME) LEN(10) MIN(1)                  
0005.00              QUAL       TYPE(*NAME) LEN(10) DFT(*LIBL) +            
0006.00                           SPCVAL((*LIBL) (*CURLIB)) +               
0007.00                           PROMPT(' ライブラリー ')                  
0008.00              PARM       KWD(CLEAR) TYPE(*CHAR) LEN(10) RSTD(*YES) + 
0009.00                           DFT(*ALL) VALUES(*ALL *KEEP) +            
0010.00                           PROMPT(' クリヤー ')                      

(2)既存のレコード数が存在しているか、または *KEEP が指定されている場合は
MOVOBJ で現在の *USRQ をライブラリー QTEMP に移す。

0112.00    if(Num_Msgs > 0 && strncmp(CLEAR, "*KEEP     ", 10) == 0){/* 複製 */ 
0113.00      /*( 現行 USRQ を QTEMP に移す )*/                                  
0114.00      sprintf(cmd, "MOVOBJ OBJ(%s/%s) OBJTYPE(*USRQ) TOLIB(QTEMP)",      
0115.00            usrqlib, usrq);                                              
0116.00      system(cmd);                                                       
0117.00    }/* 複製 */

(3)それ以外であれば既存の *USRQ を削除する

0118.00    else{/* 新規再作成 */                                                
0119.00      /*( 不要であれば削除する )*/                                       
0120.00      sprintf(cmd, "DLTUSRSPC USRSPC(%s/%s )", usrqlib, usrq);           
0121.00      system(cmd);                                                       
0122.00    }/* 新規再作成 */

(4)新しい *USRQ を元の場所(ライブラリー)に API: QUSCRTUQ を使って作成する。

0123.00    QUSCRTUQ(USRQQLIB, "PF        ", Type, Key_Length, Max_Size, Init_Ms 
0124.00              Extension, "*ALL      ", text, "*NO       ", &errcode);

(5)元の *USRQ のレコード数が存在しているか、または *KEEP が指定されている場合は
QTEMP の旧 *USRQ を読み取ってデータを新しい *USRQ に入れる。

0125.00    if(Num_Msgs > 0 && strncmp(CLEAR, "*KEEP     ", 10) == 0){/* 複製 */ 
0126.00      /*( OLD QUEUE から NEW QUEUE へデータを転送する )*/         
0127.00      old_queue = rslvsp(_Usrq, USRQ, "QTEMP     ", _AUTH_ALL);   
0128.00      new_queue = rslvsp(_Usrq, USRQ, USRQLIB, _AUTH_ALL);        
0129.00      d_msg_prefix.Wait_Forever = -1;/*nowait*/                   
0130.00      memset(d_msg_prefix.Wait_Time, 0, sizeof(_MI_Time));        
0131.00      while(1){/*while*/                                          
0132.00        if(deqi(&d_msg_prefix, rcvbuf, old_queue) == 0) break;    
0133.00        e_msg_prefix.Msg_Len = strlen(rcvbuf);                    
0134.00        enq(new_queue, &e_msg_prefix, rcvbuf);/* SNDUSRQ*/        
0135.00      }/*while*/   

(6)旧い QTEMP の *USRQ を削除して終了する

0136.00      sprintf(cmd, "DLTUSRSPC USRSPC(QTEMP/%s)", usrq);           
0137.00      system(cmd); 

(1)〜(6)のシナリオは難しいものではないので、どうしても C 言語は嫌だと
いう人はこのソースを見ながら RPG たまたは CLP で書くこともできるが
内容は結局、ここに書いた多くの MI 関数などを使うことになるので
C 言語のほうが圧倒的に短くて済む。
処理の内容によって言語の向き、不向きがあるので
このまま C 言語でのコンパイルが最もお勧めである。