// OK .. handle producer transaction
int pLogRecordByteCount = 0;
ArrayList pLogMsgList = null;
for (int i =0; plist != null && i < plist.size(); i ++ ) {
SysMessageID sysid = (SysMessageID)plist.get(i);
PacketReference ref = Destination.get(sysid);
if (ref == null) {
logger.log(Logger.ERROR,BrokerResources.E_INTERNAL_BROKER_ERROR, "transacted message removed too early "+sysid);
continue;
}
// handle forwarding the message
try {
if (Globals.txnLogEnabled()) {
if (pLogMsgList == null) {
pLogMsgList = new ArrayList();
}
// keep track for producer txn log
pLogRecordByteCount += ref.getSize();
pLogMsgList.add(ref.getPacket().getBytes());
}
Destination d = Destination.getDestination(ref.getDestinationUID());
if (fi.FAULT_INJECTION) {
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_1_6, null, 2, false);
}
Set s = d.routeNewMessage(ref);
d.forwardMessage(s,ref);
} catch (Exception ex) {
logger.logStack((BrokerStateHandler.shuttingDown? Logger.DEBUG : Logger.ERROR),BrokerResources.E_INTERNAL_BROKER_ERROR, "unable to route/send transaction message " + sysid , ex);
}
}
boolean processDone = true;
// handle consumer transaction
int cLogRecordCount = 0;
ArrayList cLogDstList = null;
ArrayList cLogMsgList = null;
ArrayList cLogIntList = null;
HashMap remoteNotified = new HashMap();
if (cmap != null && cmap.size() > 0) {
Iterator itr = cmap.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry)itr.next();
SysMessageID sysid = (SysMessageID)entry.getKey();
// CANT just pull from connection
if (sysid == null) continue;
PacketReference ref = Destination.get(sysid);
if (ref == null || ref.isDestroyed() || ref.isInvalid()) {
// already been deleted .. ignore
continue;
}
Destination dst =
Destination.getDestination(ref.getDestinationUID());
List interests = (List) entry.getValue();
for (int i = 0; i < interests.size(); i ++) {
ConsumerUID intid = (ConsumerUID) interests.get(i);
ConsumerUID sid = (ConsumerUID)sToCmap.get(intid);
if (sid == null) sid = intid;
try {
Session s = Session.getSession(intid);
if (s != null) {
PacketReference r1 = null;
if (fi.FAULT_INJECTION && fi.checkFault(
FaultInjection.FAULT_TXN_COMMIT_1_7_1, null)) {
Globals.getConnectionManager().getConnection(
s.getConnectionUID()).destroyConnection(
true, GoodbyeReason.OTHER,
"Fault injection of closing connection");
}
r1 =s.ackMessage(intid, sysid, id, remoteNotified, true);
if (r1 != null) {
if (fi.FAULT_INJECTION) {
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_1_7, null, 2, false);
}
dst.removeMessage(ref.getSysMessageID(),
RemoveReason.ACKNOWLEDGED);
} else {
s = Session.getSession(intid);
}
}
if (s == null) {
//OK the session has been closed, we need
// to retrieve the message and acknowledge it
// with the stored UID
try {
if (ref.acknowledged(intid, sid,
true, true, id, remoteNotified, true)) {
dst.removeMessage(ref.getSysMessageID(),
RemoveReason.ACKNOWLEDGED);
}
} catch (BrokerException ex) {
// XXX improve internal error
logger.log(Logger.WARNING,"Internal error", ex);
}
}
if (Globals.txnLogEnabled()) {
if (cLogDstList == null) {
cLogDstList = new ArrayList();
cLogMsgList = new ArrayList();
cLogIntList = new ArrayList();
}
// keep track for consumer txn log;
// ignore non-durable subscriber
if (!dst.isQueue() && !sid.shouldStore()) {
continue;
}
cLogRecordCount++;
cLogDstList.add(dst.getUniqueName());
cLogMsgList.add(sysid);
cLogIntList.add(sid);
}
} catch (Exception ex) {
processDone = false;
logger.logStack(Logger.ERROR,BrokerResources.E_INTERNAL_BROKER_ERROR,
"-------------------------------------------" +
"Processing Acknowledgement during committ [" +
sysid + ":" + intid + ":" + con.getConnectionUID()+
"]\nReference is " + (ref == null ? null : ref.getSysMessageID())
+ "\n" + com.sun.messaging.jmq.jmsserver.util.PacketUtil.dumpPacket(msg)
+ "--------------------------------------------",
ex);
}
}
}
}
if(Globals.isNewTxnLogEnabled())
{
// notify that transaction work has been written to message store
loggedCommitWrittenToMessageStore(id, transactionType);
}
// OK .. now remove the acks .. and free up the id for ues
// XXX Fixed 6383878, memory leaks because txn ack can never be removed
// from the store if the txn is removed before the ack; this is due
// to the fack that in 4.0 when removing the ack, the method check
// to see if the txn still exits in the cache. This temporary fix
// will probably break some HA functionality and need to be revisited.
translist.removeTransaction(id, (!processDone ||
(cmap.size()>0 && BrokerStateHandler.shuttingDown)));
if (conlist == null) { //from admin
logger.log(logger.WARNING,
BrokerResources.W_ADMIN_COMMITTED_TXN, id, ((xid==null)? "null":xid.toString()));
}
// log to txn log if enabled
try {
if (pLogRecordByteCount > 0 && cLogRecordCount > 0) {
// Log all msgs and acks for producing and consuming txn
ByteArrayOutputStream bos = new ByteArrayOutputStream(
(pLogRecordByteCount) +
(cLogRecordCount * (32 + SysMessageID.ID_SIZE + 8)) + 16);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(id.longValue()); // Transaction ID (8 bytes)
// Msgs produce section
dos.writeInt(pLogMsgList.size()); // Number of msgs (4 bytes)
Iterator itr = pLogMsgList.iterator();
while (itr.hasNext()) {
dos.write((byte[])itr.next()); // Message
}
// Msgs consume section
dos.writeInt(cLogRecordCount); // Number of acks (4 bytes)
for (int i = 0; i < cLogRecordCount; i++) {
String dst = (String)cLogDstList.get(i);
dos.writeUTF(dst); // Destination
SysMessageID sysid = (SysMessageID)cLogMsgList.get(i);
sysid.writeID(dos); // SysMessageID
ConsumerUID intid = (ConsumerUID)cLogIntList.get(i);
dos.writeLong(intid.longValue()); // ConsumerUID
}
dos.close();
bos.close();
Globals.getStore().logTxn(
TransactionLogType.PRODUCE_AND_CONSUME_TRANSACTION,
bos.toByteArray());
} else if (pLogRecordByteCount > 0) {
// Log all msgs for producing txn
ByteBuffer bbuf = ByteBuffer.allocate(pLogRecordByteCount + 12);
bbuf.putLong(id.longValue()); // Transaction ID (8 bytes)
bbuf.putInt(pLogMsgList.size()); // Number of msgs (4 bytes)
Iterator itr = pLogMsgList.iterator();
while (itr.hasNext()) {
bbuf.put((byte[])itr.next()); // Message
}
Globals.getStore().logTxn(
TransactionLogType.PRODUCE_TRANSACTION, bbuf.array());
} else if (cLogRecordCount > 0) {
// Log all acks for consuming txn
ByteArrayOutputStream bos = new ByteArrayOutputStream(
(cLogRecordCount * (32 + SysMessageID.ID_SIZE + 8)) + 12);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(id.longValue()); // Transaction ID (8 bytes)
dos.writeInt(cLogRecordCount); // Number of acks (4 bytes)
for (int i = 0; i < cLogRecordCount; i++) {
String dst = (String)cLogDstList.get(i);
dos.writeUTF(dst); // Destination
SysMessageID sysid = (SysMessageID)cLogMsgList.get(i);
sysid.writeID(dos); // SysMessageID
ConsumerUID intid = (ConsumerUID)cLogIntList.get(i);
dos.writeLong(intid.longValue()); // ConsumerUID
}
dos.close();
bos.close();