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 » IBM MQ API Support » MQPUT1/MQGET match by CORRELID issue

Post new topic  Reply to topic
 MQPUT1/MQGET match by CORRELID issue « View previous topic :: View next topic » 
Author Message
indo_canadian
PostPosted: Mon May 07, 2012 2:10 pm    Post subject: MQPUT1/MQGET match by CORRELID issue Reply with quote

Newbie

Joined: 07 May 2012
Posts: 4

Hi:

I've developed a C++ client app that puts a request to a remote queue and then reads a response on the reply-to-queue.

Here's the high-level picture:

My C++ DLL function <--> Our MQ Server (Windows 2003 Server, MQ version 7.1, with a queue manager, remote queues and reply-to-queues defined) <--> Customer's MQ Server

Issue description - My DLL function puts a message on a remote queue using MQPUT1, receives a msgID, sets the correlID = msgID (from MQPUT1), sets the matchoptions=MQMO_MATCH_CORREL_ID, calls MQGET and it results in completion code 2 MQCC_FAILED, reason code 2033 MQRC_NO_MSG_AVAILABLE.

Here's my code:

MQMD PMD = {MQMD_DEFAULT};
memcpy((char *)PMD.ReplyToQ, pszReplyToQ, MQ_Q_NAME_LENGTH);
memcpy((char *)PMD.ReplyToQMgr, pszQMgrName, MQ_Q_MGR_NAME_LENGTH);
PMD.Persistence = MQPER_PERSISTENT;
PMD.MsgType = MQMT_REQUEST;

This PMD struct variable is passed in a parameter to the SendMQMessage function, to map to the MQMD* MessDesc parameter below.

MQPUT1 code:

int SendMQMessage(MQHCONN ConnHdl, MQMD* MessDesc, MQBYTE *Message, MQLONG MesLen, const char *Queue, const char *QMgr)
{
MQLONG CompCode;
MQLONG Reason;
MQPMO Put_Message_Options = {MQPMO_DEFAULT};
MQOD QueueDescriptor = {MQOD_DEFAULT};

strcpy_s(QueueDescriptor.ObjectName, MQ_Q_NAME_LENGTH, Queue);

strcpy_s(QueueDescriptor.ObjectQMgrName, MQ_Q_MGR_NAME_LENGTH, QMgr);

Put_Message_Options.Options = MQPMO_NEW_MSG_ID;

MQPUT1(ConnHdl,
&QueueDescriptor,
MessDesc,
&Put_Message_Options,
MesLen,
Message,
&CompCode,
&Reason);

if (CompCode == MQCC_FAILED)
return 0;
else
return 1;
}

This results in CompCode=0 and Reason=0.

The same PMD struct variable is passed in a parameter to the GetReply function, to map to the MQMD* MessDesc parameter below.

MQGET code:

int GetReply(MQHCONN ConnectionHandle, MQHOBJ QueueHandle, MQMD* MessDesc, MQBYTE *Message, MQLONG *MesLen, long WaitInterval)
{
MQGMO GetMessageOptions = {MQGMO_DEFAULT};
MQLONG CompCode;
MQLONG Reason;
MQMD GMD = {MQMD_DEFAULT}; // Get Msg Desc

memcpy(GMD.MsgId, MQMI_NONE, sizeof(MQMI_NONE));
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->MsgId, sizeof(MQ_CORREL_ID_LENGTH));

if (WaitInterval == 0)
GetMessageOptions.Options = MQGMO_NO_WAIT|MQGMO_CONVERT;
else
{
GetMessageOptions.Options = MQGMO_WAIT|MQGMO_CONVERT;
GetMessageOptions.WaitInterval = WaitInterval; // since WaitInterval is in ms already, passed in as 5000ms
}

GetMessageOptions.MatchOptions = MQMO_MATCH_CORREL_ID;

MQGET (ConnectionHandle,
QueueHandle,
//MessDesc,
&GMD,
&GetMessageOptions,
strlen((const char*)Message),
Message,
MesLen,
&CompCode,
&Reason);

if (CompCode == MQCC_OK)
return 1;
else if (CompCode == MQCC_FAILED && Reason == MQRC_NO_MSG_AVAILABLE)
return -2; // WaitInterval has elapsed and no suitable message has arrived, i.e. timeout
else
return 0;
}

This results in CompCode=2 and Reason=2033.

I've tried various other options in my code such as:

1. In SendMQMessage,
MessDesc->Report = MQRO_COPY_MSG_ID_TO_CORREL_ID + MQRO_PASS_CORREL_ID;

In GetReply,
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->CorrelId, sizeof(MQ_CORREL_ID_LENGTH));
GetMessageOptions.MatchOptions = MQMO_MATCH_CORREL_ID;

This results in CompCode=2 and Reason=2033.

2. In GetReply,
memcpy(GMD.MsgId, MessDesc->MsgId, sizeof(MQ_MSG_ID_LENGTH));
GetMessageOptions.MatchOptions = MQMO_MATCH_MSG_ID;

This results in CompCode=2 and Reason=2033.

3. I've run the rfhutil with my current options. I put a message to the remote queue, switch over to the MQMD tab, copy/paste the msgid into the correlid field, switch back to the main tab, check the 'get by correlid' check box, and click Read Q button, I'm able to get the correct message.

What am I doing incorrectly in my C++ code?

Thanks.
Back to top
View user's profile Send private message
PeterPotkay
PostPosted: Mon May 07, 2012 2:56 pm    Post subject: Reply with quote

Poobah

Joined: 15 May 2001
Posts: 7717

Maybe the app you're sending the request to is never sending back a reply?
Maybe they are but not respecting your wishes to move the MessageID of the request into the Correl ID of the reply.

Your code does not specify the syncpoint yes or no option on the put and get, leaving the reader to assume you are picking up the default for that platform if the code does not specify it. You should code no syncpoint if that is what you want.

After the successful MQPUT1, you should save the value of the Message ID produced by the QM and use it on the MQGET call. I don't see where your code does this.

You should not copy the entire MQMD after the MQPUT1 and use it for the MQGET call.
_________________
Peter Potkay
Keep Calm and MQ On
Back to top
View user's profile Send private message
indo_canadian
PostPosted: Mon May 07, 2012 3:22 pm    Post subject: Reply with quote

Newbie

Joined: 07 May 2012
Posts: 4

Thanks for your response. My comments/responses are below.

PeterPotkay wrote:
Maybe the app you're sending the request to is never sending back a reply?
Maybe they are but not respecting your wishes to move the MessageID of the request into the Correl ID of the reply.


It does send a reply and it does move the MessageID of the request into the Correl ID of the response. I do see the queue depth count for the response queue increasing in the MQ Explorer. I've run the rfhutil with my current options. I put a message to the remote queue, switch over to the MQMD tab, copy/paste the msgid into the correlid field, switch back to the main tab, check the 'get by correlid' check box, and click Read Q button, I'm able to get the correct message.

PeterPotkay wrote:

Your code does not specify the syncpoint yes or no option on the put and get, leaving the reader to assume you are picking up the default for that platform if the code does not specify it. You should code no syncpoint if that is what you want.


OK I will try that.

PeterPotkay wrote:

After the successful MQPUT1, you should save the value of the Message ID produced by the QM and use it on the MQGET call. I don't see where your code does this.


In GetReply():

memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->MsgId, sizeof(MQ_CORREL_ID_LENGTH));

PeterPotkay wrote:

You should not copy the entire MQMD after the MQPUT1 and use it for the MQGET call.


I copy only the MQMD.MsgID after the MQPUT1 into the MQMD.CorrelID before the MQGET.
Back to top
View user's profile Send private message
bruce2359
PostPosted: Mon May 07, 2012 4:23 pm    Post subject: Reply with quote

Poobah

Joined: 05 Jan 2008
Posts: 9394
Location: US: west coast, almost. Otherwise, enroute.

indo_canadian wrote:
I copy only the MQMD.MsgID after the MQPUT1 into the MQMD.CorrelID before the MQGET.

So, you only initialize the correlid to the value of the request message?

Look at the reply message in the queue. What is the value of the msgid field before the get? Is it still the the msgid of the msg you put?
_________________
I like deadlines. I like to wave as they pass by.
ב''ה
Lex Orandi, Lex Credendi, Lex Vivendi. As we Worship, So we Believe, So we Live.
Back to top
View user's profile Send private message
mvic
PostPosted: Mon May 07, 2012 4:25 pm    Post subject: Re: MQPUT1/MQGET match by CORRELID issue Reply with quote

Jedi

Joined: 09 Mar 2004
Posts: 2080

Quote:
memcpy(GMD.MsgId, MQMI_NONE, sizeof(MQMI_NONE));

I think that this code pattern will copy one byte too many for the data area you are copying to. But it should be benign in this case, as your code continues to write something explicit into the field following MD.MsgId. To be correct, I think you should use MQ_MSG_ID_LENGTH instead of sizeof(MQMI_NONE).

If you are setting MQPER_PERSISTENT, you should also set MQPMO_SYNCPOINT/MQGMO_SYNCPOINT and use MQCMIT. There are a couple of reasons for this: performance and message integrity. Remember: persistent messages go fastest when inside syncpoints, non-persistent when outside. See the last sections of the MQ Performance Reports for official mentions of this.

I see your app also does not use syncpoint for its MQGET. This can easily cause you to lose messages when testing. (Is this what is happening in your testing?) If you are not clear why this is true, have a think of what the queue manager will do on behalf of an app that gets outside syncpoint, and the app dies just before a message arrives on the queue it was getting from.

Finally:
Quote:
QueueHandle

How certain are you that this is a handle to the correct queue?
Back to top
View user's profile Send private message
indo_canadian
PostPosted: Tue May 08, 2012 7:23 pm    Post subject: Reply with quote

Newbie

Joined: 07 May 2012
Posts: 4

PeterPotkay wrote:


"You should not copy the entire MQMD after the MQPUT1 and use it for the MQGET call."


I created a new function and I copy just the MQMD.MsgId into that function, which then copies it into the MQMD.correlid. The main error was in the method that I was using for this copy. I changed it to:

int GetResponse(MQHCONN ConnectionHandle, MQHOBJ QueueHandle, MQBYTE24 MsgID, MQBYTE *Message, MQLONG *MesLen, long WaitInterval)
{
MQMD GMD = {MQMD_DEFAULT};
sprintf((char*)GMD.CorrelId, "%s", (char*)MsgID);
}

The rest of the options are the same, i.e. MatchOptions = MQMO_MATCH_CORREL_ID;

mvic:

"If you are setting MQPER_PERSISTENT, you should also set MQPMO_SYNCPOINT/MQGMO_SYNCPOINT and use MQCMIT. There are a couple of reasons for this: performance and message integrity. Remember: persistent messages go fastest when inside syncpoints, non-persistent when outside."

I have tried with these PMO and GMO options, and they do improve the performance. However, I came across this IBM article:

http://www-01.ibm.com/support/docview.wss?uid=swg1IV00659

It advises to use MQPMO_SYNC_RESPONSE, and no syncpoint for MQGET. I've tried with this option and the results are similar to when I use MQPMO_SYNCPOINT/MQGMO_SYNCPOINT/MQCMIT. I will play around with these options some more to see/compare the results.

"I see your app also does not use syncpoint for its MQGET. This can easily cause you to lose messages when testing. (Is this what is happening in your testing?)"

The messages were coming into the response queue in a timely manner. Mainly due to my MQMD.correlid in the MQGET not having the proper value was causing it to fail with reason 2033 MQRC_NO_MSG_AVAILABLE after 5 seconds.

"How certain are you that this is a handle to the correct queue?"

I am certain that this is the handle to the correct (response) queue, since if I comment out the MatchOptions = MQMO_MATCH_CORREL_ID; line of code, I would get the first (non-matching) message in that response queue, with the queue depth being over 60 messages.

I would like to thank everyone for their timely responses and suggestions.

Cheers.
Back to top
View user's profile Send private message
fjb_saper
PostPosted: Tue May 08, 2012 8:09 pm    Post subject: Reply with quote

Grand High Poobah

Joined: 18 Nov 2003
Posts: 20696
Location: LI,NY

indo_canadien wrote:
Code:
sprintf((char*)GMD.CorrelId, "%s", (char*)MsgID);
My C is not so good as it once was, but AFAIK the correlationId/messageid is and has never been of type char... so using a char pointer might cause some problems down the road. You are in presence of a type MQ_BYTE_24 which is an array of 24 bytes containing values from 00 to FF for each byte. Not all those values are legal in a char...
_________________
MQ & Broker admin
Back to top
View user's profile Send private message Send e-mail
gbaddeley
PostPosted: Tue May 08, 2012 11:04 pm    Post subject: Reply with quote

Jedi

Joined: 25 Mar 2003
Posts: 2491
Location: Melbourne, Australia

Code:
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->CorrelId, sizeof(MQ_CORREL_ID_LENGTH));

Correlation Id and Message Id are binary fields, so C string functions are not appropriate. memcpy is the easiest option. The 3rd argument is the number of bytes to copy. sizeof() returns the number of bytes required to represent the integer value MQ_CORREL_ID_LENGTH. I don't think you intented that! Take out the sizeof():
Code:
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->CorrelId, MQ_CORREL_ID_LENGTH);

_________________
Glenn
Back to top
View user's profile Send private message
mvic
PostPosted: Wed May 09, 2012 1:57 am    Post subject: Reply with quote

Jedi

Joined: 09 Mar 2004
Posts: 2080

gbaddeley wrote:
Take out the sizeof()

This is what we were all missing! I spotted that the other sizeof was wrong, but missed this one
Back to top
View user's profile Send private message
bruce2359
PostPosted: Wed May 09, 2012 5:18 am    Post subject: Reply with quote

Poobah

Joined: 05 Jan 2008
Posts: 9394
Location: US: west coast, almost. Otherwise, enroute.

mvic wrote:
gbaddeley wrote:
Take out the sizeof()

This is what we were all missing! I spotted that the other sizeof was wrong, but missed this one

...Hmmm. I've been told that sizeof() doesn't matter.
_________________
I like deadlines. I like to wave as they pass by.
ב''ה
Lex Orandi, Lex Credendi, Lex Vivendi. As we Worship, So we Believe, So we Live.
Back to top
View user's profile Send private message
mvic
PostPosted: Wed May 09, 2012 6:03 am    Post subject: Reply with quote

Jedi

Joined: 09 Mar 2004
Posts: 2080

bruce2359 wrote:
...Hmmm. I've been told that sizeof() doesn't matter.

It does matter to C programmers.
Back to top
View user's profile Send private message
indo_canadian
PostPosted: Wed May 09, 2012 2:20 pm    Post subject: Reply with quote

Newbie

Joined: 07 May 2012
Posts: 4

gbaddeley wrote:
Code:
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->CorrelId, sizeof(MQ_CORREL_ID_LENGTH));

Correlation Id and Message Id are binary fields, so C string functions are not appropriate. memcpy is the easiest option. The 3rd argument is the number of bytes to copy. sizeof() returns the number of bytes required to represent the integer value MQ_CORREL_ID_LENGTH. I don't think you intented that! Take out the sizeof():
Code:
memcpy((unsigned char*)GMD.CorrelId, (unsigned char*)MessDesc->CorrelId, MQ_CORREL_ID_LENGTH);


Hi Glenn:

BINGO! That code change worked perfectly!

Thanks a lot!

Cheers.
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 » IBM MQ API Support » MQPUT1/MQGET match by CORRELID issue
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.