Feeds:
Posts
Comments

Archive for March, 2009

When faced with flat tire

How many of you like to have your tire completely flat at an isolated area with 15km back to the previous town and 15km to the next town?. Well it happened to me yesterday on my bike where there is no spare wheel for rescue. I inspected the flat tire but could not find any nail or nothing struct to the tire.
For a long time I kept a flat mate can in my traveling bag in addition to the necessary tool set. I have never tried it and in fact did not have much faith in it. Since there was no alternative I tried it. Bravo, it fixed the thing. It emits a white creamy rubber solution into the tire while inflating the tire with pressure. The cream is supposed to fix all the punctures.
The instruction on the bottle says to travel slowly and fix the puncture within next 15-20km. In the next town I stopped at a tire service place and they said no need to do a separate patch and asked me to continue without any doubt. I traveled about another 30km in high speed and still the tire goes strong. I bought the can for about 800Rupees and it rewarded me at last. Even in a car this is good thing to keep stand by because it prevents you from all the hassle of changing wheels until you go to next service station.
how to hold patch can

Advertisements

Read Full Post »

In a previous blog I discussed benchmark testing tools I used for some benchmark perposes. At that time I really used Apache Bench(ab) for the purpose. However when I am again doing some bench mark testing I stumbled upon a new tool(at least for me) httperf which seems to be more advanced and reliable than ab. Although there were ample guidance on how to use this for http GET requests I could not find any easy to read guide on how to use httperf with http POST requests. Following I try to explain how httperf could be used in testing my services.

httperf --server localhost --port 9090 --uri /axis2/services/weather
     --num-conn 4000 --num-call 16 --rate 64 --timeout 5 > report

Above command is a simple scenario where I request a HTTP get request on a servic running on context /axis2/services/weather on localhost.

It is important to understand the  options for the command.

1. –server – ip of the machine service is running

2. –port – port the service is running

3. –uri – The context path of the service on the server

4. –num-con – Number of test calls made to the service

5. –num-call – Number of calls per tcp connection.

6. –rate – Number of connections created per second to make requests to the service.

7. –time-out – This is the maximum time httperf wait for a successful response.

It is important to understand the correct balance between num-conn, num-call and rate options.

The maximum number of requests the httperf would generate = num-call * rate

Clearly your num-conn could be reasonably higher than this number. You could experiment between num-call and rate to produce a good load to the server. The actual number of requests to the server you will see in the generated report could be less than this number depending on the saturation of the server, client or network bandwidth. If such thing happen you need to reduce your num-call or rate options and find out at what point exactly saturation happen. If your num-conn is very large your server may exaust all servicing processes after some time.

Now let’s look at a more advance scenario. Here I am sending a http post request with some payload defined in the file name inputfile.

httperf --server localhost --port 80 --uri /axis2/services/weather --hog --method POST
    --add-header="Content-type:application/soap+xml;charset=UTF-8``\n``"
    --wsesslog=4000,0,inputfile --max-piped-calls 16 --rate 64 --timeout 5  > result

In adition to the payload you can also specify the http method and the server context uri in this input file. For more descriptions on writing this input file read [1]. Following is the content of the inputfile I used.

/axis2/services/weather method=POST contents="<soapenv:Envelope xmlns:soapenv=
\"http://www.w3.org/2003/05/soap-envelope\"><soapenv:Header xmlns:wsa=
\"http://www.w3.org/2005/08/addressing\"><wse:Identifier xmlns:wse=
\"http://schemas.xmlsoap.org/ws/2004/08/eventing\">
urn:uuid:57becf58-0fc3-1de1-24ad-0012f0b857ac</wse:Identifier>
<wsa:To>http://localhost:9090/axis2/services/weather</wsa:To>
<wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/eventing/GetStatus</wsa:Action>
<wsa:MessageID>urn:uuid:14d256a2-0f95-1de1-2b1a-0012f0b857ac</wsa:MessageID>
</soapenv:Header><soapenv:Body><wse:GetStatus xmlns:wse=
\"http://schemas.xmlsoap.org/ws/2004/08/eventing\"></wse:GetStatus>
</soapenv:Body></soapenv:Envelope>"

The important additional options of the above command is
1.–wsesslog – This value for this option is a three comma separated parameters. First one is the number of request sessions you need to make to the server. Second is used to emulate a real user delay between sessions. Third is the inputfile.

2. –max-piped-calls – Number of calls need in one tcp connection(in http 1.1). This is used instead of num-call here.

[1] http://www.xenoclast.org/doc/benchmark/HTTP-benchmarking-HOWTO/node6.html

Read Full Post »

Dinesh Premalal in his blog post on Axis2/C with cbthread explain that using cbthreads he ran about 100,000 concurrent requests using Axis2/C client. The reason for this achievement is because of the non-preemptive and continuation-based threads implemented with cbthreads. However in his next blog Axis2/C with pthreads he goes on explaining how he used similer Axis2/C client with pthreads and could only run about 300 concurrent requests. This is predictable because each thread in pthreads consume considerable amount of memory in it’s stack-based nature implementation. In adition Dinesh’s program for pthreads does not use a thread pool which cause the the program to create threads until system resources exhausted.

In cbthreads home page it is mentioned

“A downside of having a non-preemptive thread system is that you cannot assign threads to blocking system calls as you can with pthreads, and have threads run while the system call blocks. If you do, the entire process blocks.”

This reason highly discourage using cbthreads for Axis2/C. Besides pthreads is provenly portable among numerous platforms. In my opinion what Axis2/C needs is a good thread pool implementation using pthreads.

In search of a good thread pool using pthreads I came across this one which seems to be a good candidate. I wrote a similer client as Dinesh wrote for testing cbthreads using this pthreads thread pool.

Axis2/C client With pthread threadpool for 10,000 request
real 1m9.974s
user 0m34.890s
sys 0m9.297s

Axis2/C client with cbthreads for 10,000 requests
real 3m29.835s
user 0m13.621s
sys 0m8.857s

This shows that using pthreads with a good thread pool is the right way to use pthreads for Axis2/C with it’s all proven features.

To try this with Axis2/C echo.cpp client program do the following steps.

1. Download the pthread pool from here and build the source by executing make in the root source folder.

2. Install Axis2/C. I assume you installed it into /axis2c/deploy.(You need Axis2/C 1.6 or build it from svn source)

3. Copy the following echo.cpp source file and build.sh build script into the same source folder.

4. Execute build.sh and run the exectuable program.

One thing to notice about the echo.cpp code is creating service client for each thread. Main overhead of creating service client is associated with creating the Axis2/C main cofiguration context. This is reduced by creating each service client passing the same configuratin context as following.

conf_ctx = axis2_svc_client_get_conf_ctx(svc_client, env);
svc = axis2_svc_client_get_svc(svc_client, env);
svc_client = axis2_svc_client_create_with_conf_ctx_and_svc(env, client_home, conf_ctx, svc);

echo.cpp

#include <TThreadPool.hh>
#include <stdio.h>
#include <stdio.h>
#include <axiom.h>
#include <axis2_util.h>
#include <axiom_soap.h>
#include <axis2_client.h>
#include <axis2_conf_ctx.h>
#include <axis2_svc.h>

#define NTHREADS 10000
#define POOLSIZE 100

axiom_node_t *
build_om_payload_for_echo_svc(const axutil_env_t * env);

typedef struct _svcinfo {
    const axutil_env_t *env;
    axis2_svc_client_t *svc_client;
    axis2_char_t *address;
}svc_info_t;

static void svc_client_send_request (void *v);

class echo : public TThreadPool::TJob
{
public:
   echo ( int id )
       : TThreadPool::TJob( id )
   {
   }

public:
  void run ( void * arg )
  {
      svc_client_send_request(arg);
  }
};

int
main(int argc, char **argv)
{
    const axutil_env_t *env = NULL;
    const axis2_char_t *address = NULL;
    axis2_endpoint_ref_t *endpoint_ref = NULL;
    axis2_options_t *options = NULL;
    const axis2_char_t *client_home = NULL;
    axis2_svc_client_t *svc_client = NULL;
    int i = 0;
    TThreadPool * pool = NULL;
    axis2_conf_ctx_t *conf_ctx = NULL;
    axis2_svc_t *svc = NULL;

    /* Set up the environment */
    env = axutil_env_create_all("echo.log", AXIS2_LOG_LEVEL_TRACE);

    /* Set end point reference of echo service */
    address = "http://localhost:9091/axis2/services/echo";
    if (argc > 1)
    {
        if (axutil_strcmp(argv[1], "-h") == 0)
        {
            printf("Usage : %s [endpoint_url]\n",
                   argv[0]);
            printf("use -h for help\n");
            return 0;
        }
        else
        {
            address = argv[1];
        }
    }
    printf("Using endpoint : %s\n", address);

    /* Set up deploy folder. It is from the deploy folder, the configuration is picked up
     * using the axis2.xml file.
     * In this sample client_home points to the Axis2/C default deploy folder. The client_home can
     * be different from this folder on your system. For example, you may have a different folder
     * (say, my_client_folder) with its own axis2.xml file. my_client_folder/modules will have the
     * modules that the client uses
     */
    client_home = AXIS2_GETENV("AXIS2C_HOME");
    if (!client_home || !strcmp(client_home, ""))
        client_home = "../..";

    /* Create service client */
    svc_client = axis2_svc_client_create(env, client_home);
    if (!svc_client)
    {
        printf
            ("Error creating service client, Please check AXIS2C_HOME again\n");
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
                        env->error->error_number,
                        AXIS2_ERROR_GET_MESSAGE(env->error));
        return -1;
    }

    /* Set service client options */
    axis2_svc_client_set_options(svc_client, env, options);

    /* Engage addressing module */
    axis2_svc_client_engage_module(svc_client, env, AXIS2_MODULE_ADDRESSING);

    conf_ctx = axis2_svc_client_get_conf_ctx(svc_client, env);
    svc = axis2_svc_client_get_svc(svc_client, env);
    pool = new TThreadPool( POOLSIZE );

    for (i = 0; i < NTHREADS; i++)
    {
        echo *job = new echo(i);
        axis2_svc_client_t *t_client = NULL;
        svc_info_t *svcinfo = NULL;

        svcinfo = (svc_info_t *) malloc (sizeof (svc_info_t));
        if (!svcinfo)
        {
            fprintf (stderr, "no enough memory\n");
            exit (1);
        }
        svcinfo->env = env;
        t_client = axis2_svc_client_create_with_conf_ctx_and_svc(env, client_home, conf_ctx, svc);
        svcinfo->svc_client = t_client;
        svcinfo->address = (axis2_char_t *) address;
        pool->run( job, (void *) svcinfo, true );
    }

    pool->sync_all();
    axis2_svc_client_free(svc_client, env);
    printf("success\n");
    return 0;
}

/* build SOAP request message content using OM */
axiom_node_t *
build_om_payload_for_echo_svc(
    const axutil_env_t * env)
{
    axiom_node_t *echo_om_node = NULL;
    axiom_element_t *echo_om_ele = NULL;
    axiom_node_t *text_om_node = NULL;
    axiom_element_t *text_om_ele = NULL;
    axiom_namespace_t *ns1 = NULL;
    axis2_char_t *om_str = NULL;

    ns1 =
        axiom_namespace_create(env, "http://ws.apache.org/axis2/services/echo",
                               "ns1");
    echo_om_ele =
        axiom_element_create(env, NULL, "echoString", ns1, &echo_om_node);
    text_om_ele =
        axiom_element_create(env, echo_om_node, "text", NULL, &text_om_node);
    axiom_element_set_text(text_om_ele, env, "Hello World!", text_om_node);
    om_str = axiom_node_to_string(echo_om_node, env);

    if (om_str)
    {
        AXIS2_FREE(env->allocator, om_str);
        om_str = NULL;
    }
    return echo_om_node;
}

static void
svc_client_send_request (void *v)
{
    svc_info_t *svcinfo;
    const axutil_env_t *env;
    axis2_svc_client_t *svc_client;
    axiom_node_t *payload = NULL;
    axiom_node_t *ret_node;
    axis2_options_t *options = NULL;
    axis2_endpoint_ref_t *endpoint_ref = NULL;
    axis2_char_t *address = NULL;

    svcinfo = (svc_info_t *)v;
    env = svcinfo->env;
    svc_client = svcinfo->svc_client;
    address = svcinfo->address;

    options = (axis2_options_t *) axis2_svc_client_get_options(svc_client, env);
    if(!options)
    {
        options = axis2_options_create(env);
        axis2_svc_client_set_options(svc_client, env, options);
    }

    endpoint_ref = axis2_endpoint_ref_create(env, address);

    axis2_options_set_to(options, env, endpoint_ref);
    axis2_options_set_action(options, env,
                             "http://ws.apache.org/axis2/c/samples/echoString");

    /* Build the SOAP request message payload using OM API. */
    payload = build_om_payload_for_echo_svc(env);

    /* Send request */
    ret_node = axis2_svc_client_send_receive(svc_client, env, payload);

    if (ret_node)
    {
        axiom_node_free_tree(payload, env);
        axiom_node_free_tree(ret_node, env);
        ret_node = NULL;
        printf("Invoke SUCCESSFUL\n");
    }
    else
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
                        env->error->error_number,
                        AXIS2_ERROR_GET_MESSAGE(env->error));
        printf("echo client invoke FAILED\n");
    }

    if(svcinfo)
    {
        AXIS2_FREE(env->allocator, svcinfo);
        svcinfo = NULL;
    }
    axis2_svc_client_free(svc_client, env);
}

build.sh

gcc *.cpp -oecho -I./src libthrpool.a -lstdc++ -lpthread -L/axis2c/deploy/lib -lm -laxis2_engine -laxutil -laxis2_axiom -I. -I/axis2c/deploy/include/axis2-1.6.0/

Read Full Post »

I found no documentation on basic memory handling conventions in Axis2/C. Until this content appear under a developer guide for Axis2/C, here are some facts that could be useful in preparing such document. Here I don’t talk about advance facilities provided regarding memory management in Axis2/C. However I’ll provide links below for such documents. I just talk about few points that could be useful for service and client developers in handling memory which are not included in the above mentioned documents.

Memory handling in services

Axis2/C services should be written implementing the API defined in axis2_svc_skeleton.h. Basically if your service name is echo you will have two implementation files echo_skeleton.c and echo.c. echo_skeleton.c will contain the functions implementing the API including life-cycle management functions of the service. They are echo_create(), echo_init(), echo_free, echo_invoke and echo_on_fault(). Within the create function you will instantiate axis2_svc_skeleton_t stuct and assign your services operation structure to the svc_skeleton_t structures operation structure so that your functions will be called from withing the Axis2/C engine.
Within free function you will free the sekelton structure you allocated in create function. When the service unloaded this function is called by the engine to free the service resources. If you allocate any additional stuff withing the service create function it is your responsibility to free them then and there.
In invoke function you can check the operation requested and call the appropriate service function from echo.c where all the service logic functions are implemented. The response nodes if any are created withing these service functions will be freed by the Axis2/C engine. Also any property you set there into Axis2/C configuration context structures will be garbaged by the Axis2/C engine according to their life scope. Any additional stuff you created there must be handled by your self.

In the on_fault function you can create a fault node which could be inserted as detail element in creating soap faults by the engine when something goes wrong when invoking your service. It is the responsibility of the Axis2/C engine to free such nodes.

Memory handling in clients

Most of the memory allocated in the client side (including SOAP request and reply messages), should be cleaned in the client side itself. Memory allocated for properties are taken care of by the SOAP engine. SOAP engine reclaims the memory allocated for properties based on the scope (Request, Session or Application) you set for each property.

You can read more advance information regarding memory management in Axis2/C in the following articles. However some of these articles are old so if you find it is difficult to understand them with the current Axis2/c code base don’t hesitate to ask in the Axis2/C developer list.

Overcoming Memory Related Issues in Axis2/C

Memory Management with Apache Axis2/C

Read Full Post »