Example

This chapter describes how to use the Tmax RQ system through examples.

1. Basic Program

RQ program operations are similar to async communications. The most basic type of program that uses the RQ system is a client that uses a single RQ. It calls a service using tpenq(), and receives the result using tpdeq().

The following is a basic RQ program process where a client calls a service and receives results using tpenq() and tpdeq().

figure 3 1
RQ Program Process

A client calls a service using tpenq() and receives a result value using tpdeq(). If TPNOFLAGS is given as a tpenq() flag, this process is almost same. If the tpenq() flag is not TPNOFLAGS, the service result value will be stored in a RQ data file in the server side instead of the client side. In other words, a client can check the completion of a service execution using tpsleep().

If a developer needs to know the time point of a service completion, TPNOFLAGS can be used or other APIs can be used to implement a method. If flags other than TPNOFLAGS are used, the urcode value that is returned by a server, will be ignored.

If a service name is specified and the TPRQS flag is used, a client reads result data from a Reply queue using tpqstat(). When a RQ is used by specifying a service name, requests in a RQ will be executed by service, so the order might be different from the storing order by tpenq().

For more information about errors, refer to tpdeq, and for more information about the functions, refer to Tmax Reference Guide.

1.1. Environment Configuration

The following is an example of Tmax environment configuration:

*DOMAIN
tmax    SHMKEY=88000,
        TPORTNO = 8888

*NODE
tmax1   TMAXDIR="/user1/tmax",
        APPDIR="/user1/tmax/appbin"

*SVRGROUP
svg1    NODENAME = tmax1,
        CPC = 4,
        SVGTYPE=RQMGR

*RQ
rqtest  SVGNAME = svg1

*SERVER
svr     SVGNAME = svg1

*SERVICE
SERVICE    SVRNAME = svr

For more information about the configuration fields of each section, refer to Environment Configuration in Tmax Administration Guide.

1.2. Client Program

The following is a client program example:

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>

int main(int argc, char *argv[])
{
    char *buf;
    long rlen;
    int rqcount, i;

    if (argc != 2){
        error procesing
    }

    if (tpstart((TPSTART_T *)NULL) == -1){
        error processing
    }

    buf = tpalloc("CARRAY", NULL, 0);
    if (buf == NULL){
        error processing
    }

    strcpy(buf, argv[1]);

    if (tpenq("rqtest", "SERVICE", buf, strlen(buf), TPRQS) == -1){
        error processing
    }

    ...

    rqcount = tpqstat("rqtest", TMAX_RPLY_QUEUE);
    for(i = 0;i < rqcount;i++){
        ...
        if(tpdeq("rqtest", "SERVICE", &buf, &rlen, TPRQS) == -1){
            error processing
        }
        ...
    }

    tpfree((char *)buf);
    tpend();
}

1.3. Server Program

The following is a server program example:

#include <stdio.h>
#include <usrinc/atmi.h>

SERVICE(TPSVCINFO *msg)
{
    int  i;
    ...
    tpreturn(TPSUCCESS,0,(char *)msg->data, 0,TPNOFLAGS);
}

2. UCS Using Program

RQ programs have a simple structures like tpenq() – tpdeq(). If one is developed using the various process management types in Tmax, the usage range can be widened. This section describes various programming techniques using UCS, Tmax’s proprietary method.

If the jobs requested by a client need to be executed in order and the process time of each server program is long, a client must wait in a blocking state during an entire service period. But if a RQ is used, the client can save the job to the RQ and can execute the next job directly and the server can read the service requests in order from the RQ to execute them.

The following is the program process that uses UCS:

figure 3 2
UCS Using Program Process

A client will store a desired service name and data in a structure and perform tpenq() multiple times. During this time, a service name will be given to NULL. Data will be accumulated in a Reply queue and a UCS server will read data from the queue and send it to a corresponding service to call a service.

2.1. Environment Configuration

The following is an example of a Tmax environment configuration:

*DOMAIN
tmax    SHMKEY=88000,
        TPORTNO = 8888

*NODE
tmax1   TMAXDIR="/user1/tmax",
        APPDIR="/user1/tmax/appbin"

*SVRGROUP
svg1    NODENAME = tmax1,
        CPC = 4,
        SVGTYPE=RQMGR

*RQ
rqenq   SVGNAME = svg1
rqdeq   SVGNAME = svg1

*SERVER
svr1    SVGNAME = svg1
svr2    SVGNAME = svg1,
        SVRTYPE = UCS

*SERVICE
SERVICE1     SVRNAME = svr1
SERVICE2     SVRNAME = svr1
SERVICE3     SVRNAME = svr1

For more information about the configuration fields of each section, refer to Environment Configuration in Tmax Administration Guide.

2.2. Client Program

The following is an example of a client program:

#include <stdio.h>
#include <sys/time.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>
#include “../sdl/demo.s”

int main(int argc, char *argv[])
{
    struct *buf1, *buf2, *buf3
    long rlen;
    int rqcount, i;
    struct timeval tval;

    if (argc != 4){
        error processing
    }

    if (tpstart((TPSTART_T *)NULL) == -1){
        error processing
    }

    buf1 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0);
    buf2 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0);
    buf3 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0);
    if (buf1 == NULL || buf2=NULL || buf3==NULL){
        error processing
    }

    strcpy(buf1->svc, “SERVICE1”);
    strcpy(buf1->data, argv[1]);
    strcpy(buf2->svc, “SERVICE2”);
    strcpy(buf2->data, argv[2]);
    strcpy(buf3->svc, “SERVICE3”);
    strcpy(buf3->data, argv[3]);

    /*Give the service name to NULL to send the data to the Reply queue*/
    if (tpenq("rqenq", NULL, buf1, 0, TPRQS) == -1){
        error processing
    }
    if (tpenq("rqenq", NULL, buf2, 0, TPRQS) == -1){
        error processing
    }
    if (tpenq("rqenq", NULL, buf3, 0, TPRQS) == -1){
        error processing
    }
    tpfree((char *)buf1);
    tpfree((char *)buf2);
    tpfree((char *)buf3);
    tpend();
}

2.3. Server Program

The following is an example of a server program:

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/ucs.h>
#include <usrinc/tmaxapi.h>
#include “../sdl/demo_sdl.h”

int usermain(int argc, char *argv[])
{
    struct rqsvc *buf;
    char *sndbuf;
    long rlen;
    int count, i, ret;

    buf = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0);
    if (buf == NULL){
        error processing
    }

    sndbuf = tpalloc("STRING", NULL, 0);
    if (sndbuf == NULL){
        error processing
    }

    while(1){
        tpschedule(10);

        /*Find out the number of data in the Reply queue*/
        count = tpqstat("rqenq", TMAX_RPLY_QUEUE);
        printf("count = %d\n", count);
        for (i = 0; i < count ; i++){
            /*Send the data that has NULL as the service name from the Reply queue*/
            if (tpdeq("rqenq", NULL, (char **)&buf, &rlen, TPRQS) == -1){
                error processing
            }
            buf=(struct rqsvc *)buf;
            strcpy(sndbuf, buf->data);

            /*Execute the services in order*/
            if (tpcall(buf->svc, sndbuf, 0, (char **)&buf, (long *)&rlen,
                TPNOFLAGS) == -1){
                error processing
            }
            ...
        }
    }
    return 1;
}

3. Fail Queue Recovery Program

Data in a Fail queue, which can be generated due to various causes, must be processed based on the situation. The simplest way is by deleting data using a management tool, but to process the data in a way a user may want, a corresponding program must be made.

The following is a UCS type program and the process of recovering a Fail queue.

figure 3 3
Fail Queue Recovery Program

The process reads data from a Fail queue every 10 seconds and finds a corresponding service using tpextsvcname(). The data of specific services are then discarded and the remaining data is again moved to a Request queue of a corresponding service. tpreissue() performs the process of reading data and sending it to a corresponding service all at once, so it cannot be used in cases that requires actions based on the situation.

3.1. Environment Configuration

The following is an example of a Tmax environment configuration:

*DOMAIN
tmax    SHMKEY=88000,
        TPORTNO = 8888

*NODE
tmax1   TMAXDIR="/user1/tmax",
        APPDIR="/user1/tmax/appbin"

*SVRGROUP
svg1    NODENAME = tmax1,
        CPC = 4,
        SVGTYPE=RQMGR

*RQ
rqtest    SVGNAME = svg1, BOOT = WARM

*SERVER
svr1    SVGNAME = svg1
svr2    SVGNAME = svg1
svr3    SVGNAME = svg1,
        SVRTYPE = UCS

*SERVICE
SERVICE1    SVRNAME = svr1
SERVICE2    SVRNAME = svr2
STOP        SVRNAME = svr2

For more information about the configuration fields of each section, refer to Environment Configuration in Tmax Administration Guide.

3.2. Server Program

The following is an example of a server program:

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>

int usermain(int argc, char *argv[])
{
    char *buf, svcname[16];
    long rlen;
    int failcount, i, ret;

    buf = tpalloc("STRING", NULL, 0);
    if (buf == NULL){
        error processing
    }

    while(1){
        tpschedule(10);
        /*Find out the number of data in the Fail queue*/
        failcount = tpqstat("rqtest", TMAX_FAIL_QUEUE);
        for (i = 0; i < failcount ; i++){
            /*Recieve data from the Fail queue*/
            if (tpdeq("rqtest", _rq_sub_queue_name[TMAX_FAIL_QUEUE], &buf, &rlen,
                TPRQS) == -1){
                error processing
            }
            /*Retrieve the service name*/
            if (tpextsvcname(buf, svcname) == -1){
                error processing
            }
            /*Skip if the read data is "STOP"*/
            if (strcomp(svcname, “STOP”)) {
              /*tpenq to the corresponding service name*/
              ret=tpenq("rqtest", svcname, buf, rlen, TPRQS);
              if (ret<0) {
                error processing
            }
         }
        }
    }

    return 1;
}