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 Java / JMS » Doing a GET and a PUT within one transaction

Post new topic  Reply to topic
 Doing a GET and a PUT within one transaction « View previous topic :: View next topic » 
Author Message
educos
PostPosted: Wed Jun 11, 2003 10:42 am    Post subject: Doing a GET and a PUT within one transaction Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

Using the MQ Java API (5.3) I created 2 queue manager objects (each object actually points to the same queue manager).

- On the first qm object I access a queue (e.g. Q1) with the following options: MQC.MQOO_INPUT_SHARED | MQC.MQGMO_SYNCPOINT
- On the second qm object I access another queue (e.g. Q2) with the following options: MQC.MQOO_OUTPUT | MQC.MQPMO_SYNCPOINT
- I begin a transaction by calling begin() on the first qm object
- I get a message from Q1 using the following options MQC.MQGMO_WAIT | MQC.MQGMO_SYNCPOINT
- I put the message from Q1 into Q2 using the following option MQC.MQPMO_SYNCPOINT
- Lastly I commit the transaction by calling commit() on the first qm object

Note: My app requirements are such that I must keep both queues open after all this - meaning I am not closing the queues or disconnecting from the qms after the above logic is run.

I thought that the commit call on the first qm was going to commit the get on Q1 and the put on Q2. Instead, the message from Q1 is gone - which is expected - but the message never shows up in Q2

Any thoughts on how to make the 1 commit() work for both get & put operations in this scenario?
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
mqonnet
PostPosted: Wed Jun 11, 2003 11:47 am    Post subject: Reply with quote

Grand Master

Joined: 18 Feb 2002
Posts: 1114
Location: Boston, Ma, Usa.

Your understanding is right. It should have committed the message for both the operations with a single commit().

When you say the message never makes to Q2, where does the message land up finally??? Did you get a bad RC from the put. Because if put also completed fine, then i would assume that the message would have been committed successfully. Check to see that you have 2 different hobjs for put and get. Check to see if the curdepth of q1 actually went down.

As an aside you could make your program put and get persistent messages, so that under all circumstances in your test, the message is NEVER LOST. If you think that could be the case, which i think is highly unlikely.

Cheers
Kumar
Back to top
View user's profile Send private message Send e-mail Visit poster's website
educos
PostPosted: Wed Jun 11, 2003 11:59 am    Post subject: Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

The commit on the first qm effectively removes the message from Q1. The The message gets "lost" because the put to Q2 is never "effected" by the commit.

The queue depth on Q2 does show that the message is there - in a non committed state (that's because I used the SYNCPOINT put option). Because it is not commited, unless I disconnect from Q2 after the commit or explicitly call commit on the second qm, the message never "sticks".

Of course, having to call commit or disconnect on the 2nd qm negates all the benefits of the atomic transaction I was expecting to get from the one commit on the first qm...
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
mqonnet
PostPosted: Wed Jun 11, 2003 12:23 pm    Post subject: Reply with quote

Grand Master

Joined: 18 Feb 2002
Posts: 1114
Location: Boston, Ma, Usa.

Now the obvious question is, how do you deduce that the messages on Q2 are uncommitted. And if you see them can you as well browse/get them. If yoiu can do a get of the messages from Q2, that would mean they are committed. If this does not solve your problem, may be you can post your code here.

When you say you are using 2 qm objects, i would assume you are using only 1 qm and 2 queues. Right.

Cheers
Kumar
Back to top
View user's profile Send private message Send e-mail Visit poster's website
educos
PostPosted: Wed Jun 11, 2003 12:32 pm    Post subject: Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

I assumed the uncommitted message was on Q2 because the queue depth was 1, but no message was actually available to get or browse (through MQ explorer). When my test program stops, the queue depth for Q2 reverts to 0 after a second or so - which I believe is normal MQ cleanup behavior for uncommitted messages.

I did mean that I was using 2 qm objects but the MQQueueManager objects are connecting to the same queue manager. One instance of MQQueueManager is used to GET from queue Q1 and the other instance is used to PUT to Q2 - on the same queue manager. Note that I have to have 2 instances of the MQQueueManager object because of how the application is built.
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
educos
PostPosted: Wed Jun 11, 2003 12:54 pm    Post subject: Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

Debugging through the code I noticed that I am getting an MQRC_NO_EXTERNAL_PARTICIPANTS exception when begin() is called. It is my undestanding that this is normal behavior and simply means that the transaction isn't involving another transaction participant (like a DB2 or Oracle).
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
educos
PostPosted: Wed Jun 11, 2003 1:02 pm    Post subject: Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

As reference I am including minimal Java sample code that reliably reproduces the unexpected MQ transactional behavior:

//Get message from qm1///////////////////////////////////////
MQQueueManager qm1 = new MQQueueManager("FMCQM");

int qOpts = MQC.MQOO_INPUT_SHARED | MQC.MQGMO_SYNCPOINT;
MQQueue q1 = qm1.accessQueue("IN", qOpts, null, null, null);

try
{
//Begin transaction
qm1.begin();
}
catch(MQException e)
{
if(e.reasonCode != MQException.MQRC_NO_EXTERNAL_PARTICIPANTS)
throw e;
}

MQMessage msg = new MQMessage();
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQC.MQGMO_WAIT | MQC.MQGMO_SYNCPOINT;
gmo.waitInterval = 30000;
q1.get(msg, gmo);

//Store message data into byte []
byte [] buf = new byte[msg.getDataLength()];
msg.readFully(buf);

//Put message to qm2/////////////////////////////////////////
MQQueueManager qm2 = new MQQueueManager("FMCQM");

int qOpts2 = MQC.MQOO_OUTPUT | MQC.MQPMO_SYNCPOINT;
MQQueue q2 = qm2.accessQueue("OUT", qOpts2, null, null, null);

MQMessage msg2 = new MQMessage();
MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options = MQC.MQPMO_SYNCPOINT;
msg2.write(buf); //copy data of old msg into new msg

q2.put(msg2, pmo);

//Commit transaction - which should remove the old msg from q1 and write
//the new msg to q2 - but it doesn't
qm1.commit();
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
kingdon
PostPosted: Thu Jun 12, 2003 12:49 am    Post subject: Reply with quote

Acolyte

Joined: 14 Jan 2002
Posts: 63
Location: UK

I think you've headed off down a blind alley here. Let's see if we can simplify a little.

First, the use of the begin call is very unlikely to be what you are after. It's purpose is solely for controlling global transactions involving MQ and a database, where the queue manager acts as the transaction coordinator. Global transactions are also referred to as XA, distributed or two phase commit (2PC) transactions.

In order to group a number of GETs and PUTs into a unit of work on a single queue manager you only need to use a local transaction.

Local transactions are:
started implicitly when you do the first GET or PUT under syncpoint
scoped by the MQQueueManager instance
finished by a call to either MQQueueManager.commit() or MQQueueManager.backout()

So, to get the behaviour you are looking for, don't use begin, and do use a single MQQueueManager instance for accessing the two queues.

Cheers,
James.
Back to top
View user's profile Send private message
mqonnet
PostPosted: Thu Jun 12, 2003 3:13 am    Post subject: Reply with quote

Grand Master

Joined: 18 Feb 2002
Posts: 1114
Location: Boston, Ma, Usa.

As james pointed out, you might have to use a single QMGR object rather than 2. This surely seemed strange to me. But again, i have not read the java manuals thoroughly(as i use java only occassionaly). Hence i am not sure what goes inside the queue manager objects.

But the same exact scenario works using C app. Which kind of points the finger at the queue manager object. C does not have anything like that and uses the same hconn but diff hobjs.

Cheers
Kumar
Back to top
View user's profile Send private message Send e-mail Visit poster's website
educos
PostPosted: Thu Jun 12, 2003 9:06 am    Post subject: Reply with quote

Apprentice

Joined: 18 Jul 2001
Posts: 34
Location: Salt Lake City, UT

The begin() is actually necessary in my framework, because between the get & the put, I may actually do stuff (like database updates) that could require an external participant. Most of the time though, you're right - the begin is useless since the transaction isn't global.

I tried the idea of using the same MQQueueManager instance and - as you pointed out - it works, meaning the get & put occur in one unit of work.

I thought that I could use separate instances pointing to the same queue manager - but I was obviously mistaking. I'll open a PMR with IBM to verify that the MQ Java API is not behaving as designed and I will post the outcome here...
_________________
Eric Ducos

EmeriCon, LLC.
Phone: (801) 789-4348
e-Mail: Eric.Ducos@EmeriCon.com
Website: www.EmeriCon.com
Back to top
View user's profile Send private message Visit poster's website
clindsey
PostPosted: Thu Jun 12, 2003 11:25 am    Post subject: Reply with quote

Knight

Joined: 12 Jul 2002
Posts: 586
Location: Dallas, Tx

Eric,

I am sure you didn't recognize the name but, James Kingdon is very likely to be the one to answer the pmr if you open it. I don't think his anwer will change

Charlie
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 Java / JMS » Doing a GET and a PUT within one transaction
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.