ASG
IBM
Zystems
Cressida
Icon
Netflexity
 
  MQSeries.net
Search  Search       Tech Exchange      Education      Certifications      Library      Info Center      SupportPacs      LinkedIn  Search  Search                                                                   FAQ  FAQ   Usergroups  Usergroups
 
Register  ::  Log in Log in to check your private messages
 
RSS Feed - WebSphere MQ Support RSS Feed - Message Broker Support

MQSeries.net Forum Index » General IBM MQ Support » cursors and browsing

Post new topic  Reply to topic
 cursors and browsing « View previous topic :: View next topic » 
Author Message
Pat Fleming
PostPosted: Thu Apr 07, 2005 4:07 am    Post subject: cursors and browsing Reply with quote

Newbie

Joined: 16 Oct 2003
Posts: 8

We have 2 MQ Clients both at V5.0 running on NT4 connect to MQ Qmgr at V5.3 on Solaris 2.9.

Both clients Get from the same input queue and reply to the ReplyTo queue in the incoming message. Both browse the input queue for any message then, if a message is present, get it, process it, move the MsgId into the CorrelId field and Put the reply to the ReplyTo queue. The server is waiting on a reply message with the outgoing MsgId to appear in the ReplyTo queue.

This works fine when both client and server are V5.0 on NT4 and Solaris 2.6. We can correct it by locking the browsed message in the MQ client but feel we should not have to do this in the client to support an MQ server upgrade to 5.3.

What we are seeing is that if we set the GetMessageOptions on the destructive Get to MQGMO_MSG_UNDER_CURSOR we are not getting the message we have just browsed or are not getting an MQRC_NO_MSG_UNDER_CURSOR error to say the message has been removed rather than that there is none.

Is this a known issue or are we not doing something or doing something wrong in the client or, possibly in the configuration of the server?

We have simulated this behaviour using one of the standard C programs in MQM samp directory. Here is the program that shows what we are seeing:


/********************************************************************/
/* */
/* Program name: AMQSGET0 */
/* */
/* Description: Sample C program that gets messages from */
/* a message queue (example using MQGET) */
/* */
/* Statement: Licensed Materials - Property of IBM */
/* */
/* 84H2000, 5765-B73 */
/* 84H2001, 5639-B42 */
/* 84H2002, 5765-B74 */
/* 84H2003, 5765-B75 */
/* 84H2004, 5639-B43 */
/* 5799-RJL */
/* (C) Copyright IBM Corp. 1994, 1997 */
/* */
/********************************************************************/
/* */
/* Function: */
/* */
/* */
/* AMQSGET0 is a sample C program to get messages from a */
/* message queue, and is an example of MQGET. */
/* */
/* -- sample reads from message queue named in the parameter */
/* */
/* -- displays the contents of the message queue, */
/* assuming each message data to represent a line of */
/* text to be written */
/* */
/* messages are removed from the queue */
/* */
/* -- writes a message for each MQI reason other than */
/* MQRC_NONE; stops if there is a MQI completion code */
/* of MQCC_FAILED */
/* */
/* */
/* Program logic: */
/* Take name of input queue from the parameter */
/* MQOPEN queue for INPUT */
/* while no MQI failures, */
/* . MQGET next message, remove from queue */
/* . print the result */
/* . (no message available counts as failure, and loop ends) */
/* MQCLOSE the subject queue */
/* */
/* */
/********************************************************************/
/* */
/* AMQSGET0 has 2 parameters - */
/* - the name of the message queue (required) */
/* - the queue manager name (optional) */
/* */
/********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* includes for MQI */
#include <cmqc.h>
#include <Windows.h>

int main(int argc, char **argv)
{

/* Declare MQI structures needed */
MQOD getod = {MQOD_DEFAULT}; /* Object Descriptor */
MQOD putod = {MQOD_DEFAULT}; /* Object Descriptor */
MQMD browsemd = {MQMD_DEFAULT}; /* Message Descriptor */
MQMD getmd = {MQMD_DEFAULT}; /* Message Descriptor */
MQGMO gmo = {MQGMO_DEFAULT}; /* get message options */
MQPMO pmo = {MQPMO_DEFAULT}; /* put message options */
/** note, sample uses defaults where it can **/
MQMD ReplyDescriptor = { MQMD_DEFAULT };
MQHCONN Hcon; /* connection handle */
MQHOBJ getHobj; /* object handle */
MQHOBJ putHobj; /* object handle */
MQLONG O_options; /* MQOPEN options */
MQLONG C_options; /* MQCLOSE options */
MQLONG CompCode; /* completion code */
MQLONG OpenCode; /* MQOPEN completion code */
MQLONG Reason; /* reason code */
MQLONG CReason; /* reason code for MQCONN */
MQBYTE buffer[101]; /* message buffer */
MQLONG buflen; /* buffer length */
MQLONG messlen; /* message length received */
char QMName[50]; /* queue manager name */
int i = 0;
int j;
int putQueueOpen = 0;

printf("Sample AMQSGET0 start\n");
if (argc < 2)
{

printf("Required parameter missing - queue name\n");
exit(99);

}



/******************************************************************/
/* */
/* Create object descriptor for subject queue */
/* */
/******************************************************************/
strcpy(getod.ObjectName, argv[1]);
QMName[0] = 0; /* default */
if (argc > 2)
strcpy(QMName, argv[2]);

/******************************************************************/
/* */
/* Connect to queue manager */
/* */
/******************************************************************/
MQCONN(QMName, /* queue manager */
&Hcon, /* connection handle */
&CompCode, /* completion code */
&CReason); /* reason code */

/* report reason and stop if it failed */
if (CompCode == MQCC_FAILED)
{
printf("MQCONN %s ended with reason code %ld\n", QMName, CReason);
exit( (int)CReason );
}

/******************************************************************/
/* */
/* Open the named message queue for input; exclusive or shared */
/* use of the queue is controlled by the queue definition here */
/* */
/******************************************************************/
//O_options = MQOO_INPUT_AS_Q_DEF /* open queue for input */
// + MQOO_FAIL_IF_QUIESCING + MQOO_BROWSE; /* but not if MQM stopping */


O_options = MQOO_INPUT_SHARED | MQOO_OUTPUT | MQOO_FAIL_IF_QUIESCING | MQOO_BROWSE;

MQOPEN(Hcon, /* connection handle */
&getod, /* object descriptor for queue */
O_options, /* open options */
&getHobj, /* object handle */
&OpenCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any; stop if failed */
if (Reason != MQRC_NONE)
{
printf("MQOPEN ended with reason code %ld\n", Reason);
}

if (OpenCode == MQCC_FAILED)
{
printf("unable to open queue for input\n");
}

/******************************************************************/
/* */
/* Get messages from the message queue */
/* Loop until there is a failure */
/* */
/******************************************************************/
CompCode = OpenCode; /* use MQOPEN result for initial test */

while (CompCode != 999999)
{
i++;
buflen = sizeof(buffer) - 1; /* buffer size available for GET */
//gmo.Options = MQGMO_WAIT /* wait for new messages */
// + MQGMO_CONVERT;/* convert if necessary */

gmo.Options = MQGMO_WAIT + // wait for new messages
MQGMO_FAIL_IF_QUIESCING + MQGMO_BROWSE_NEXT;
gmo.WaitInterval = 1500; /* 1.5 second limit for waiting */

/****************************************************************/
/* */
/* In order to read the messages in sequence, MsgId and */
/* CorrelID must have the default value. MQGET sets them */
/* to the values in for message it returns, so re-initialise */
/* them before every call */
/* */
/****************************************************************/
memcpy(browsemd.MsgId, MQMI_NONE, sizeof(browsemd.MsgId));
memcpy(browsemd.CorrelId, MQCI_NONE, sizeof(browsemd.CorrelId));

/****************************************************************/
/* */
/* MQGET sets Encoding and CodedCharSetId to the values in */
/* the message returned, so these fields should be reset to */
/* the default values before every call, as MQGMO_CONVERT is */
/* specified. */
/* */
/****************************************************************/
//md.Encoding = MQENC_NATIVE;
//md.CodedCharSetId = MQCCSI_Q_MGR;

MQGET(Hcon, /* connection handle */
getHobj, /* object handle */
&browsemd, /* message descriptor */
&gmo, /* get message options */
buflen, /* buffer length */
buffer, /* message buffer */
&messlen, /* message length */
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
if (Reason == MQRC_NO_MSG_AVAILABLE)
{ /* special report for normal end */
printf("Browse - no more messages\n");
}
else /* general report for other reasons */
{
printf("MQGET ended with reason code %ld\n", Reason);

/* treat truncated message as a failure for this sample */
if (Reason == MQRC_TRUNCATED_MSG_FAILED)
{
CompCode = MQCC_FAILED;
}
}
}
if (CompCode != MQCC_FAILED)
{

printf("%i Browse message <%s> ", i, buffer);

printf("\n MsgId : X'");

for (j = 0 ; j < MQ_MSG_ID_LENGTH ; j++)
printf("%02X",browsemd.MsgId[j] );

printf("'");
printf("\n CorrelId : X'");

for (j = 0 ; j < MQ_CORREL_ID_LENGTH ; j++)
printf("%02X",browsemd.CorrelId[j] );

printf("'\n");


Sleep(200);


memcpy(getmd.MsgId, MQMI_NONE, sizeof(getmd.MsgId));
memcpy(getmd.CorrelId, MQCI_NONE, sizeof(getmd.CorrelId));

// Get message uinder cursor
gmo.Options = MQGMO_WAIT + MQGMO_FAIL_IF_QUIESCING + MQGMO_MSG_UNDER_CURSOR;

MQGET(Hcon, /* connection handle */
getHobj, /* object handle */
&getmd, /* message descriptor */
&gmo, /* get message options */
buflen, /* buffer length */
buffer, /* message buffer */
&messlen, /* message length */
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
if (Reason == MQRC_NO_MSG_AVAILABLE)
{ /* special report for normal end */
printf(" Get - no more messages\n");
}
else /* general report for other reasons */
{
printf("MQGET ended with reason code %ld\n", Reason);

/* treat truncated message as a failure for this sample */
if (Reason == MQRC_TRUNCATED_MSG_FAILED)
{
CompCode = MQCC_FAILED;
}
}
}
else
{
buffer[messlen] = '\0'; /* add terminator */
printf("%i Got message <%s> ", i, buffer);

printf("\n MsgId : X'");

for (j = 0 ; j < MQ_MSG_ID_LENGTH ; j++)
printf("%02X",getmd.MsgId[j] );

printf("'");
printf("\n CorrelId : X'");

for (j = 0 ; j < MQ_CORREL_ID_LENGTH ; j++)
printf("%02X",getmd.CorrelId[j] );

printf("'\n");


for (j = 0 ; j < MQ_MSG_ID_LENGTH ; j++)
{
if ( getmd.MsgId[j] != browsemd.MsgId[j] )
{
printf("------------- HERE IS THE ERROR ----------------\n");
break;
}
}
}

}

/****************************************************************/
/* Display each message received */
/****************************************************************/


if (CompCode != MQCC_FAILED)
{

if ( putQueueOpen == 0 )
{

strcpy(putod.ObjectName, getmd.ReplyToQ);

O_options = MQOO_OUTPUT /* open queue for output */
+ MQOO_FAIL_IF_QUIESCING; /* but not if MQM stopping */
MQOPEN(Hcon, /* connection handle */
&putod, /* object descriptor for queue */
O_options, /* open options */
&putHobj, /* object handle */
&OpenCode, /* completion code */
&Reason); /* reason code */

putQueueOpen = -1;

/* report reason, if any; stop if failed */
if (Reason != MQRC_NONE)
{
printf("MQOPEN ended with reason code %ld\n", Reason);
}

if (OpenCode == MQCC_FAILED)
{
printf("unable to open queue for input\n");
}

}

// got something to send via reply queue
ReplyDescriptor.MsgType = MQMT_REPLY;
ReplyDescriptor.Expiry = 3000;

memcpy( ReplyDescriptor.MsgId, getmd.MsgId, MQ_MSG_ID_LENGTH );
memcpy( ReplyDescriptor.CorrelId, getmd.CorrelId, MQ_CORREL_ID_LENGTH );

// Set as reply message
getmd.MsgType = MQMT_REPLY;

MQPUT(Hcon, /* connection handle */
putHobj, /* object handle */
&getmd, /* message descriptor */
&pmo, /* default options (datagram) */
buflen, /* buffer length */
buffer, /* message buffer */
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
printf("MQPUT ended with reason code %ld\n", Reason);
}
else
{
printf("%i Put message", i);
printf("\n MsgId : X'");

for (j = 0 ; j < MQ_MSG_ID_LENGTH ; j++)
printf("%02X",getmd.MsgId[j] );

printf("'");
printf("\n CorrelId : X'");

for (j = 0 ; j < MQ_CORREL_ID_LENGTH ; j++)
printf("%02X",getmd.CorrelId[j] );

printf("'\n");
}

}
}

/******************************************************************/
/* */
/* Close the source queue (if it was opened) */
/* */
/******************************************************************/
if (OpenCode != MQCC_FAILED)
{
C_options = 0; /* no close options */
MQCLOSE(Hcon, /* connection handle */
&getHobj, /* object handle */
C_options,
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
printf("MQCLOSE ended with reason code %ld\n", Reason);
}


C_options = 0; /* no close options */
MQCLOSE(Hcon, /* connection handle */
&putHobj, /* object handle */
C_options,
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
printf("MQCLOSE ended with reason code %ld\n", Reason);
}
}

/******************************************************************/
/* */
/* Disconnect from MQM if not already connected */
/* */
/******************************************************************/
if (CReason != MQRC_ALREADY_CONNECTED )
{
MQDISC(&Hcon, /* connection handle */
&CompCode, /* completion code */
&Reason); /* reason code */

/* report reason, if any */
if (Reason != MQRC_NONE)
{
printf("MQDISC ended with reason code %ld\n", Reason);
}
}

/******************************************************************/
/* */
/* END OF AMQSGET0 */
/* */
/******************************************************************/
printf("Sample AMQSGET0 end\n");
return(0);
}
Back to top
View user's profile Send private message
jefflowrey
PostPosted: Thu Apr 07, 2005 4:26 am    Post subject: Re: cursors and browsing Reply with quote

Grand Poobah

Joined: 16 Oct 2002
Posts: 19981

Pat Fleming wrote:
Both browse the input queue for any message then, if a message is present, get it, process it, move the MsgId into the CorrelId field and Put the reply to the ReplyTo queue.


Don't do that. It's way too much work.

Just have each client do an open-shared and destructive get.

MQ will make sure that they don't get the same message.
_________________
I am *not* the model of the modern major general.
Back to top
View user's profile Send private message
Pat Fleming
PostPosted: Thu Apr 07, 2005 4:39 am    Post subject: Reply with quote

Newbie

Joined: 16 Oct 2003
Posts: 8

Hi jefflowery,

Thanks for the reply. I should've said at the outset that the client code is legacy and is a major deal to change and redeploy, and, my feeling is that we shouldn't really have to change a client for a server upgrade, although occasionally, I accept, there may be no alternative.
Back to top
View user's profile Send private message
bower5932
PostPosted: Thu Apr 07, 2005 6:01 am    Post subject: Re: cursors and browsing Reply with quote

Jedi Knight

Joined: 27 Aug 2001
Posts: 3023
Location: Dallas, TX, USA

Pat Fleming wrote:
We have 2 MQ Clients both at V5.0 running on NT4


I'd strongly suggest that you move the clients forward to a later (supported) version of WMQ. There is no telling what may have been 'fixed' since v5.0.
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger
Nigelg
PostPosted: Thu Apr 07, 2005 8:05 am    Post subject: Reply with quote

Grand Master

Joined: 02 Aug 2004
Posts: 1046

I suspect that the 5.3 server is quicker, and so the msg is passed to the 'wrong' client in between the browse and the get.
What you were doing was wrong anyway. There is no guarantee that the msg you have just browsed will still be there when you do the get, unless you also lock the msg on the browse. You must have been lucky that the client worked when connected to the 5.0 server. It looks like the performance enhancements at 5.3 have exposed the bug in your client code.
Back to top
View user's profile Send private message
Pat Fleming
PostPosted: Thu Apr 07, 2005 9:11 am    Post subject: Reply with quote

Newbie

Joined: 16 Oct 2003
Posts: 8

Hi Nigelg,

Thanks for the reply. My colleague has just tried it with a V5.3 client and the same behaviour seems to occur. He was expecting the client to either get the message it has just browsed or to get an MQRC_NO_MSG_UNDER_CURSOR error to say the message has been removed rather than getting a completely different message.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic  Reply to topic Page 1 of 1

MQSeries.net Forum Index » General IBM MQ Support » cursors and browsing
Jump to:  



You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Protected by Anti-Spam ACP
 
 


Theme by Dustin Baccetti
Powered by phpBB © 2001, 2002 phpBB Group

Copyright © MQSeries.net. All rights reserved.