Author |
Message
|
educos |
Posted: Wed Jun 11, 2003 10:42 am Post subject: Doing a GET and a PUT within one transaction |
|
|
 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 |
|
 |
mqonnet |
Posted: Wed Jun 11, 2003 11:47 am Post subject: |
|
|
 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 |
|
 |
educos |
Posted: Wed Jun 11, 2003 11:59 am Post subject: |
|
|
 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 |
|
 |
mqonnet |
Posted: Wed Jun 11, 2003 12:23 pm Post subject: |
|
|
 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 |
|
 |
educos |
Posted: Wed Jun 11, 2003 12:32 pm Post subject: |
|
|
 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 |
|
 |
educos |
Posted: Wed Jun 11, 2003 12:54 pm Post subject: |
|
|
 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 |
|
 |
educos |
Posted: Wed Jun 11, 2003 1:02 pm Post subject: |
|
|
 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 |
|
 |
kingdon |
Posted: Thu Jun 12, 2003 12:49 am Post subject: |
|
|
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 |
|
 |
mqonnet |
Posted: Thu Jun 12, 2003 3:13 am Post subject: |
|
|
 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 |
|
 |
educos |
Posted: Thu Jun 12, 2003 9:06 am Post subject: |
|
|
 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 |
|
 |
clindsey |
Posted: Thu Jun 12, 2003 11:25 am Post subject: |
|
|
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 |
|
 |
|