use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionHandler method doCommit.
/**
* Commit a transaction. This method is invoked from two places: 1) From TransactionHandler.handle() when handling a
* client COMMIT packet. This is the common case. 2) From the admin handler when an admin commit request has been issued
* on a PREPARED XA transaction.
*
* @param id The TransactionUID to commit
* @param xid The Xid of the transaction to commit. Required if transaction is an XA transaction. Must be null if it is
* not an XA transaction.
* @param xaFlags xaFlags passed on COMMIT operation. Used only if an XA transaction.
* @param ts Current TransactionState of this transaction.
* @param conlist List of transactions on this connection. Will be null if commit is trigger by an admin request.
* @param sendReply True to have method send a Status.OK reply while processing transaction. This should be "true" for
* client initiated commits, "false" for admin initiated commits.
* @param con Connection client commit packet came in on or, for admin, the connection the admin request came in on.
* @param msg Client commit packet. Should be "null" for admin initiated commits.
*
* @throws BrokerException on an error. The method will have logged a message to the broker log.
*/
public void doCommit(TransactionList translist, TransactionUID id, JMQXid xid, Integer xaFlags, TransactionState ts, List conlist, boolean sendReply, IMQConnection con, Packet msg, boolean startNextTransaction) throws BrokerException {
int status = Status.OK;
HashMap cmap = null;
HashMap sToCmap = null;
List plist = null;
PartitionedStore pstore = translist.getPartitionedStore();
// local, or cluster
int transactionType = BaseTransaction.UNDEFINED_TRANSACTION_TYPE;
if (fi.checkFault(FaultInjection.FAULT_TXN_COMMIT_1_EXCEPTION, null)) {
fi.unsetFault(FaultInjection.FAULT_TXN_COMMIT_1_EXCEPTION);
throw new BrokerException(FaultInjection.FAULT_TXN_COMMIT_1_EXCEPTION);
}
// let acks get handled at a lower level since the
// lower level methods assumes only 1 ack per message
plist = translist.retrieveSentMessages(id);
cmap = translist.retrieveConsumedMessages(id);
sToCmap = translist.retrieveStoredConsumerUIDs(id);
cacheSetState(id, ts, con);
// remove from our active connection list
if (conlist != null) {
conlist.remove(id);
}
try {
Globals.getStore().txnLogSharedLock.lock();
TransactionWork txnWork = null;
if (Globals.isNewTxnLogEnabled()) {
txnWork = getTransactionWork2(translist.getPartitionedStore(), plist, cmap, sToCmap);
}
// Update transaction state
try {
int s;
if (xid == null) {
// Plain JMS transaction.
s = TransactionState.COMMITTED;
} else {
// XA Transaction.
s = ts.nextState(PacketType.COMMIT_TRANSACTION, xaFlags);
}
// After this call, returned base transaction will either be:
// a) null (for single phase LOCAL transaction)
// b) a prepared XA LOCAL transaction
// c) a prepared (XA or not) CLUSTER transaction
// currently, all cluster transactions are 2 phase
BaseTransaction baseTransaction = doRemoteCommit(translist, id, xaFlags, ts, s, msg, txnWork, con);
if (Globals.isNewTxnLogEnabled()) {
if (ts.getState() == TransactionState.PREPARED) {
// commit called (from client) on 2-phase transaction
transactionType = BaseTransaction.LOCAL_TRANSACTION_TYPE;
if (translist.isClusterTransaction(id)) {
transactionType = BaseTransaction.CLUSTER_TRANSACTION_TYPE;
}
logTxnCompletion(translist.getPartitionedStore(), id, TransactionState.COMMITTED, transactionType);
} else if ((baseTransaction != null && baseTransaction.getState() == TransactionState.PREPARED)) {
transactionType = baseTransaction.getType();
logTxnCompletion(translist.getPartitionedStore(), id, TransactionState.COMMITTED, transactionType);
} else {
// one phase commit, log all work here
transactionType = BaseTransaction.LOCAL_TRANSACTION_TYPE;
LocalTransaction localTxn = new LocalTransaction(id, TransactionState.COMMITTED, xid, txnWork);
logTxn(translist.getPartitionedStore(), localTxn);
}
} else {
// System.out.println("isFastLogTransactions=false ");
}
if (fi.FAULT_INJECTION) {
fi.checkFaultAndThrowBrokerException(FaultInjection.FAULT_TXN_COMMIT_1_1, null);
}
if (ts.getState() == TransactionState.PREPARED || (baseTransaction != null && baseTransaction.getState() == TransactionState.PREPARED)) {
translist.updateState(id, s, true);
} else {
// 1-phase commit
if (ts.getType() != AutoRollbackType.NEVER && Globals.isMinimumPersistLevel2()) {
translist.updateStateCommitWithWork(id, s, true);
} else {
translist.updateState(id, s, true);
}
}
if (fi.FAULT_INJECTION) {
checkFIAfterDB(PacketType.COMMIT_TRANSACTION);
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_1_5, null, 2, false);
}
startTxnAndSendReply(translist, con, msg, status, startNextTransaction, conlist, xid, id, xaFlags, sendReply);
} catch (BrokerException ex) {
logger.logStack(((ex instanceof AckEntryNotFoundException) ? Logger.WARNING : Logger.ERROR), ex.toString() + ": TUID=" + id + " Xid=" + xid, ex);
throw ex;
}
try {
/*
* Can't really call the JMX notification code at the end of doCommit() because the call to
* translist.removeTransactionID(id) removes the MBean.
*/
Agent agent = Globals.getAgent();
if (agent != null) {
agent.notifyTransactionCommit(id);
}
} catch (Exception e) {
logger.log(Logger.WARNING, "JMX agent notify transaction committed failed:" + e.getMessage());
}
// 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 = DL.get(pstore, sysid);
if (ref == null) {
logger.log(Logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_MSG_REMOVED_BEFORE_SENDER_COMMIT, 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[] ds = DL.getDestination(pstore, ref.getDestinationUID());
Destination d = ds[0];
if (fi.FAULT_INJECTION) {
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_1_6, null, 2, false);
}
MessageDeliveryTimeInfo di = ref.getDeliveryTimeInfo();
if (di != null) {
d.routeCommittedMessageWithDeliveryTime(ref);
} else {
Set s = d.routeNewMessage(ref);
d.forwardMessage(s, ref);
}
} catch (Exception ex) {
logger.logStack((BrokerStateHandler.isShuttingDown() ? Logger.DEBUG : Logger.ERROR), ex.getMessage() + "[" + sysid + "]TUID=" + id, ex);
}
}
boolean processDone = true;
// handle consumer transaction
int cLogRecordCount = 0;
ArrayList cLogDstList = null;
ArrayList cLogMsgList = null;
ArrayList cLogIntList = null;
HashMap<TransactionBroker, Object> 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 = DL.get(null, sysid);
if (ref == null || ref.isDestroyed() || ref.isInvalid()) {
// already been deleted .. ignore
continue;
}
PartitionedStore refpstore = ref.getPartitionedStore();
Destination[] ds = DL.getDestination(refpstore, ref.getDestinationUID());
Destination dst = ds[0];
if (dst == null) {
if (ref.isDestroyed() || ref.isInvalid()) {
continue;
}
}
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) {
Consumer c = Consumer.getConsumer(intid);
if (c != null) {
c.messageCommitted(sysid);
}
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 = (PacketReference) s.ackMessage(intid, sysid, id, translist, remoteNotified, true);
try {
s.postAckMessage(intid, sysid, true);
if (r1 != null) {
if (fi.FAULT_INJECTION) {
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_1_7, null, 2, false);
}
if (dst != null) {
dst.removeMessage(ref.getSysMessageID(), RemoveReason.ACKNOWLEDGED);
}
} else {
s = Session.getSession(intid);
}
} finally {
if (r1 != null) {
r1.postAcknowledgedRemoval();
}
}
}
if (s == null) {
// with the stored UID
try {
if (ref.acknowledged(intid, sid, true, true, id, translist, remoteNotified, true)) {
try {
if (dst != null) {
dst.removeMessage(ref.getSysMessageID(), RemoveReason.ACKNOWLEDGED);
}
} finally {
ref.postAcknowledgedRemoval();
}
}
} 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();
}
// ignore non-durable subscriber
if (dst == null || (!dst.isQueue() && !sid.shouldStore())) {
continue;
}
cLogRecordCount++;
cLogDstList.add(dst.getUniqueName());
cLogMsgList.add(sysid);
cLogIntList.add(sid);
}
} catch (Exception ex) {
processDone = false;
String[] args = { "[" + sysid + ":" + intid + ", " + dst + "]ref=" + ref.getSysMessageID(), id.toString(), con.getConnectionUID().toString() };
String emsg = Globals.getBrokerResources().getKString(BrokerResources.W_PROCCESS_COMMITTED_ACK, args);
logger.logStack(Logger.WARNING, emsg + "\n" + com.sun.messaging.jmq.io.PacketUtil.dumpPacket(msg) + "--------------------------------------------", ex);
}
}
}
}
if (Globals.isNewTxnLogEnabled()) {
// notify that transaction work has been written to message store
loggedCommitWrittenToMessageStore(translist.getPartitionedStore(), id, transactionType);
}
if (fi.FAULT_INJECTION) {
checkFIAfterDB(PacketType.COMMIT_TRANSACTION);
fi.checkFaultAndExit(FaultInjection.FAULT_TXN_COMMIT_2_1, null, 2, false);
}
// 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.isShuttingDown())));
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);
// Transaction ID (8 bytes)
dos.writeLong(id.longValue());
// Msgs produce section
// Number of msgs (4 bytes)
dos.writeInt(pLogMsgList.size());
Iterator itr = pLogMsgList.iterator();
while (itr.hasNext()) {
// Message
dos.write((byte[]) itr.next());
}
// Msgs consume section
// Number of acks (4 bytes)
dos.writeInt(cLogRecordCount);
for (int i = 0; i < cLogRecordCount; i++) {
String dst = (String) cLogDstList.get(i);
// Destination
dos.writeUTF(dst);
SysMessageID sysid = (SysMessageID) cLogMsgList.get(i);
// SysMessageID
sysid.writeID(dos);
ConsumerUID intid = (ConsumerUID) cLogIntList.get(i);
// ConsumerUID
dos.writeLong(intid.longValue());
}
dos.close();
bos.close();
((TxnLoggingStore) pstore).logTxn(TransactionLogType.PRODUCE_AND_CONSUME_TRANSACTION, bos.toByteArray());
} else if (pLogRecordByteCount > 0) {
// Log all msgs for producing txn
ByteBuffer bbuf = ByteBuffer.allocate(pLogRecordByteCount + 12);
// Transaction ID (8 bytes)
bbuf.putLong(id.longValue());
// Number of msgs (4 bytes)
bbuf.putInt(pLogMsgList.size());
Iterator itr = pLogMsgList.iterator();
while (itr.hasNext()) {
// Message
bbuf.put((byte[]) itr.next());
}
((TxnLoggingStore) pstore).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);
// Transaction ID (8 bytes)
dos.writeLong(id.longValue());
// Number of acks (4 bytes)
dos.writeInt(cLogRecordCount);
for (int i = 0; i < cLogRecordCount; i++) {
String dst = (String) cLogDstList.get(i);
// Destination
dos.writeUTF(dst);
SysMessageID sysid = (SysMessageID) cLogMsgList.get(i);
// SysMessageID
sysid.writeID(dos);
ConsumerUID intid = (ConsumerUID) cLogIntList.get(i);
// ConsumerUID
dos.writeLong(intid.longValue());
}
dos.close();
bos.close();
((TxnLoggingStore) pstore).logTxn(TransactionLogType.CONSUME_TRANSACTION, bos.toByteArray());
}
} catch (IOException ex) {
logger.logStack(Logger.ERROR, BrokerResources.E_INTERNAL_BROKER_ERROR, "Got exception while writing to transaction log", ex);
throw new BrokerException("Got exception while writing to transaction log", ex);
}
} finally {
// release lock
Globals.getStore().txnLogSharedLock.unlock();
}
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionHandler method getTransactionWork2.
private TransactionWork getTransactionWork2(PartitionedStore pstore, List plist, HashMap cmap, HashMap sToCmap) {
TransactionWork txnWork = new TransactionWork();
// NB should we be checking for persistent messages?
for (int i = 0; plist != null && i < plist.size(); i++) {
SysMessageID sysid = (SysMessageID) plist.get(i);
PacketReference ref = DL.get(pstore, sysid);
if (ref == null) {
logger.log(Logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_MSG_REMOVED_BEFORE_SENDER_COMMIT, sysid));
continue;
}
try {
if (ref.isPersistent()) {
TransactionWorkMessage txnWorkMessage = new TransactionWorkMessage();
Destination dest = ref.getDestination();
txnWorkMessage.setDestUID(dest.getDestinationUID());
txnWorkMessage.setPacketReference(ref);
txnWork.addMessage(txnWorkMessage);
}
} catch (Exception ex) {
logger.logStack((BrokerStateHandler.isShuttingDown() ? Logger.DEBUG : Logger.ERROR), BrokerResources.E_INTERNAL_BROKER_ERROR, "unable to log transaction message " + sysid, ex);
}
}
// iterate over messages consumed in this transaction
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();
List interests = (List) entry.getValue();
if (sysid == null) {
continue;
}
PacketReference ref = DL.get(null, sysid);
if (ref == null || ref.isDestroyed() || ref.isInvalid()) {
// already been deleted .. ignore
continue;
}
// The cluster txn should only need op store the addresses of the brokers involved.
if (!ref.isLocal()) {
continue;
}
Destination[] ds = DL.getDestination(ref.getPartitionedStore(), ref.getDestinationUID());
Destination dst = ds[0];
// - hence the list.
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 {
// ignore non-durable subscriber
if (!dst.isQueue() && !sid.shouldStore()) {
continue;
}
if (ref.isPersistent()) {
TransactionWorkMessageAck ack = new TransactionWorkMessageAck();
ack.setConsumerID(sid);
ack.setDest(dst.getDestinationUID());
ack.setSysMessageID(sysid);
txnWork.addMessageAcknowledgement(ack);
}
} catch (Exception ex) {
logger.logStack(Logger.ERROR, BrokerResources.E_INTERNAL_BROKER_ERROR, " unable to log transaction message acknowledgement " + sysid + ":" + intid, ex);
}
}
}
}
return txnWork;
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionHandler method doRollback.
/**
* Rollback a transaction. This method is invoked from two places: 1) From TransactionHandler.handle() when handling a
* client ROLLBACK packet. This is the common case. 2) From the admin handler when an admin rollback request has been
* issued on a PREPARED XA transaction.
*
* @param id The TransactionUID to commit
* @param xid The Xid of the transaction to commit. Required if transaction is an XA transaction. Must be null if it is
* not an XA transaction.
* @param xaFlags xaFlags passed on COMMIT operation. Used only if an XA transaction.
* @param ts Current TransactionState of this transaction.
* @param conlist List of transactions on this connection. Will be null if commit is trigger by an admin request.
* @param con Connection client commit packet came in on or, for admin, the connection the admin request came in on.
*
* @throws BrokerException on an error. The method will have logged a message to the broker log.
*/
public void doRollback(TransactionList translist, TransactionUID id, JMQXid xid, Integer xaFlags, TransactionState ts, List conlist, IMQConnection con, RollbackReason rbreason) throws BrokerException {
int s;
int oldstate = ts.getState();
PartitionedStore pstore = translist.getPartitionedStore();
// Update transaction state
try {
if (xid == null) {
// Plain JMS transaction.
s = TransactionState.ROLLEDBACK;
} else {
// XA Transaction.
if (rbreason == RollbackReason.ADMIN || rbreason == RollbackReason.CONNECTION_CLEANUP) {
if (ts.getState() == TransactionState.STARTED) {
ts = translist.updateState(id, TransactionState.FAILED, TransactionState.STARTED, true);
String[] args = { rbreason.toString(), id.toString() + "[" + TransactionState.toString(oldstate) + "]XID=", xid.toString() };
if (rbreason != RollbackReason.ADMIN && (DEBUG || DEBUG_CLUSTER_TXN || logger.getLevel() <= Logger.DEBUG)) {
logger.log(logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_FORCE_ENDED_TXN, args));
}
}
}
s = ts.nextState(PacketType.ROLLBACK_TRANSACTION, xaFlags);
}
} catch (BrokerException ex) {
if (ex.getStatusCode() == Status.CONFLICT) {
logger.log(Logger.ERROR, ex.toString());
} else {
logger.log(Logger.ERROR, ex.toString() + ": TUID=" + id + " Xid=" + xid);
}
throw ex;
}
ts = translist.updateState(id, s, true);
if (Globals.isNewTxnLogEnabled() && oldstate == TransactionState.PREPARED) {
int transactionType = BaseTransaction.LOCAL_TRANSACTION_TYPE;
if (translist.isClusterTransaction(id)) {
transactionType = BaseTransaction.CLUSTER_TRANSACTION_TYPE;
}
logTxnCompletion(pstore, id, TransactionState.ROLLEDBACK, transactionType);
}
if (fi.FAULT_INJECTION) {
checkFIAfterDB(PacketType.ROLLBACK_TRANSACTION);
}
boolean processDone = true;
List list = new ArrayList(translist.retrieveSentMessages(id));
for (int i = 0; i < list.size(); i++) {
SysMessageID sysid = (SysMessageID) list.get(i);
if (DEBUG) {
logger.log(Logger.INFO, "Removing " + sysid + " because of rollback");
}
PacketReference ref = DL.get(null, sysid);
if (ref == null) {
continue;
}
DestinationUID duid = ref.getDestinationUID();
Destination[] ds = DL.getDestination(ref.getPartitionedStore(), duid);
Destination d = ds[0];
if (d != null) {
Destination.RemoveMessageReturnInfo ret = d.removeMessageWithReturnInfo(sysid, RemoveReason.ROLLBACK);
if (ret.storermerror) {
processDone = false;
}
}
}
// remove from our active connection list
if (conlist != null) {
conlist.remove(id);
}
// re-queue any orphan messages
// how we handle the orphan messages depends on a couple
// of things:
// - has the session closed ?
// if the session has closed the messages are "orphan"
// - otherwise, the messages are still "in play" and
// we dont do anything with them
//
Map m = translist.getOrphanAck(id);
if (m != null) {
Iterator itr = m.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry me = (Map.Entry) itr.next();
SysMessageID sysid = (SysMessageID) me.getKey();
PacketReference ref = DL.get(null, sysid, false);
if (ref == null) {
if (DEBUG) {
logger.log(Logger.INFO, "Process transaction rollback " + id + ": orphan message already removed " + sysid);
}
continue;
}
Destination dst = ref.getDestination();
Map sids = (Map) me.getValue();
if (sids == null) {
continue;
}
Iterator siditr = sids.entrySet().iterator();
while (siditr.hasNext()) {
Map.Entry se = (Map.Entry) siditr.next();
ConsumerUID sid = (ConsumerUID) se.getKey();
if (ref.isLocal()) {
if (dst != null) {
dst.forwardOrphanMessage(ref, sid);
} else {
if (DEBUG) {
logger.log(Logger.INFO, "Process transaction rollback " + id + ": orphan consumed message destination already removed " + sysid);
}
}
continue;
}
List cids = (List) se.getValue();
if (cids == null) {
continue;
}
Iterator ciditr = cids.iterator();
while (ciditr.hasNext()) {
ConsumerUID cid = (ConsumerUID) ciditr.next();
try {
ref.acquireDestroyRemoteReadLock();
try {
if (ref.isLastRemoteConsumerUID(sid, cid)) {
if (ref.acknowledged(cid, sid, !(cid.isNoAck() || cid.isDupsOK()), false, id, translist, null, false)) {
try {
if (dst != null) {
dst.removeRemoteMessage(sysid, RemoveReason.ACKNOWLEDGED, ref);
} else {
logger.log(Logger.INFO, "Process transaction rollback " + id + ": orphan consumed remote message destination already removed " + sysid);
}
} finally {
ref.postAcknowledgedRemoval();
}
}
}
} finally {
ref.clearDestroyRemoteReadLock();
}
} catch (Exception ex) {
logger.logStack((DEBUG_CLUSTER_TXN ? Logger.WARNING : Logger.DEBUG), "Unable to cleanup orphaned remote message " + "[" + cid + "," + sid + "," + sysid + "]" + " on rollback transaction " + id, ex);
}
BrokerAddress addr = translist.getAckBrokerAddress(id, sysid, cid);
try {
HashMap prop = new HashMap();
prop.put(ClusterBroadcast.RB_RELEASE_MSG_ORPHAN, id.toString());
Globals.getClusterBroadcast().acknowledgeMessage(addr, sysid, cid, ClusterBroadcast.MSG_IGNORED, prop, false);
} catch (BrokerException e) {
Globals.getLogger().log(Logger.WARNING, "Unable to notify " + addr + " for orphaned remote message " + "[" + cid + ", " + sid + ", " + ", " + sysid + "]" + " in rollback transaction " + id);
}
}
}
}
}
// OK .. now remove the acks
translist.removeTransactionAck(id, true);
/*
* Can't really call the JMX notification code at the end of doRollback() because the call to
* translist.removeTransactionID(id) removes the MBean.
*/
Agent agent = Globals.getAgent();
if (agent != null) {
agent.notifyTransactionRollback(id);
}
try {
ts.setState(s);
cacheSetState(id, ts, con);
doRemoteRollback(translist, id, s);
translist.removeTransaction(id, !processDone);
if (rbreason == RollbackReason.ADMIN || rbreason == RollbackReason.CONNECTION_CLEANUP) {
String[] args = { rbreason.toString(), id.toString() + "[" + TransactionState.toString(oldstate) + "]", (xid == null ? "null" : xid.toString()) };
if (rbreason == RollbackReason.CONNECTION_CLEANUP) {
if (DEBUG || DEBUG_CLUSTER_TXN || logger.getLevel() <= Logger.DEBUG) {
logger.log(logger.INFO, Globals.getBrokerResources().getKString(BrokerResources.W_FORCE_ROLLEDBACK_TXN, args));
}
} else {
logger.log(logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_FORCE_ROLLEDBACK_TXN, args));
}
}
} catch (BrokerException ex) {
logger.logStack(logger.ERROR, br.getKString(br.X_REMOVE_TRANSACTION, id, ex.getMessage()), ex);
ex.setStackLogged();
throw ex;
}
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionInformation method removeConsumedMessage.
public synchronized ConsumerUID removeConsumedMessage(SysMessageID sysid, ConsumerUID id, boolean rerouted) throws BrokerException {
List l = (List) consumed.get(sysid);
if (l == null) {
throw new BrokerException(Globals.getBrokerResources().getKString(BrokerResources.X_CONSUMED_MSG_NOT_FOUND_IN_TXN, "[" + sysid + "," + id + "]", tid.toString()));
}
l.remove(id);
if (l.size() == 0) {
consumed.remove(sysid);
}
if (!rerouted) {
l = (List) removedConsumedRBD.get(sysid);
if (l == null) {
l = new ArrayList();
removedConsumedRBD.put(sysid, l);
}
l.add(id);
} else {
l = (List) removedConsumedRRT.get(sysid);
if (l == null) {
l = new ArrayList();
removedConsumedRRT.put(sysid, l);
}
l.add(id);
}
return (ConsumerUID) cuidToStored.get(id);
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionList method loadTransactions.
public void loadTransactions() throws BrokerException, IOException {
// before we do anything else, make sure we dont have any
// unexpected exceptions
// FIRST ... look at transaction table (tid,state)
LoadException load_ex = pstore.getLoadTransactionException();
if (load_ex != null) {
// some messages could not be loaded
LoadException processing = load_ex;
while (processing != null) {
TransactionUID tid = (TransactionUID) processing.getKey();
TransactionInfo ti = (TransactionInfo) processing.getValue();
if (tid == null && ti == null) {
logger.log(Logger.WARNING, "LoadTransactionException: " + "Both key and value for a transactions entry" + " are corrupted with key exception " + processing.getKeyCause().getMessage() + " and value exception " + processing.getValueCause());
processing = processing.getNextException();
continue;
}
if (tid == null) {
// at this point, there is nothing we can do ...
// store with valid key
// improve when we address 5060661
logger.logStack(Logger.WARNING, BrokerResources.W_TRANS_ID_CORRUPT, ti.toString(), processing.getKeyCause());
processing = processing.getNextException();
continue;
}
if (ti == null) {
// if we dont know ... so make it prepared
logger.log(Logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_TRAN_INFO_CORRUPTED, tid.toString()));
TransactionState ts = new TransactionState(AutoRollbackType.NOT_PREPARED, 0, true);
ts.setState(TransactionState.PREPARED);
try {
pstore.storeTransaction(tid, ts, false);
} catch (Exception ex) {
logger.logStack(Logger.WARNING, "Error updating transaction " + tid, ex);
}
processing = processing.getNextException();
continue;
}
if (ti.getType() == TransactionInfo.TXN_NOFLAG) {
logger.logStack(Logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_TXN_TYPE_CORRUPTED, tid + "[" + ti.toString() + "]", TransactionInfo.toString(TransactionInfo.TXN_LOCAL)), processing.getValueCause());
TransactionState ts = new TransactionState(AutoRollbackType.NOT_PREPARED, 0, true);
ts.setState(TransactionState.PREPARED);
try {
pstore.storeTransaction(tid, ts, false);
} catch (Exception ex) {
logger.logStack(Logger.WARNING, "Error updating transaction " + tid, ex);
}
processing = processing.getNextException();
continue;
}
if (ti.getTransactionState() == null) {
logger.log(Logger.WARNING, BrokerResources.W_TRANS_STATE_CORRUPT, tid, processing.getValueCause());
TransactionState ts = new TransactionState(AutoRollbackType.NOT_PREPARED, 0, true);
ts.setState(TransactionState.PREPARED);
try {
pstore.storeTransaction(tid, ts, false);
} catch (Exception ex) {
logger.logStack(Logger.WARNING, "Error updating transaction " + tid, ex);
}
processing = processing.getNextException();
continue;
}
if (ti.getType() == TransactionInfo.TXN_CLUSTER && ti.getTransactionBrokers() == null) {
logger.log(Logger.WARNING, BrokerResources.W_CLUSTER_TXN_BROKER_INFO_CORRUPTED, tid, processing.getValueCause());
pstore.storeClusterTransaction(tid, ti.getTransactionState(), null, false);
processing = processing.getNextException();
continue;
}
if (ti.getType() == TransactionInfo.TXN_REMOTE && ti.getTransactionHomeBroker() == null) {
logger.log(Logger.WARNING, BrokerResources.W_REMOTE_TXN_HOME_BROKER_INFO_CORRUPTED, tid, processing.getValueCause());
pstore.storeRemoteTransaction(tid, ti.getTransactionState(), null, null, false);
processing = processing.getNextException();
continue;
}
logger.log(Logger.ERROR, "XXXI18N Internal Error: unknown load error for TUID=" + tid + "[" + ti.toString() + "]");
}
// end while
}
// now look at acks load exception
load_ex = pstore.getLoadTransactionAckException();
if (load_ex != null) {
// some messages could not be loaded
LoadException processing = load_ex;
while (processing != null) {
TransactionUID tid = (TransactionUID) processing.getKey();
TransactionAcknowledgement[] ta = (TransactionAcknowledgement[]) processing.getValue();
if (tid == null && ta == null) {
logger.log(Logger.WARNING, "LoadTransactionAckException: " + "both key and value for a Transaction Ack entry" + " are corrupted");
processing = processing.getNextException();
continue;
}
if (tid == null) {
// at this point, there is nothing we can do ...
// store with valid key
// improve when we address 5060661
logger.log(Logger.WARNING, BrokerResources.W_TRANS_ID_CORRUPT, Arrays.toString(ta));
processing = processing.getNextException();
continue;
}
// ta == null, nothing we can do, remove it
logger.log(Logger.WARNING, BrokerResources.W_TRANS_ACK_CORRUPT, tid.toString());
try {
pstore.removeTransactionAck(tid, false);
} catch (Exception ex) {
logger.logStack(Logger.WARNING, "Error updating transaction acks " + tid, ex);
}
}
// end while
}
logger.log(Logger.INFO, br.getKString(br.I_PROCESSING_TRANS) + logsuffix);
// OK -> first load the list of pending
// transactions
HashMap trans = pstore.getAllTransactionStates();
// Write some info about the transactions to the log file
// for informational purposes.
logTransactionInfo(trans, AUTO_ROLLBACK, logsuffix);
// list of transactions which need to be cleaned up
HashSet clearTrans = new HashSet(trans.size());
HashSet clearAckOnlyTrans = new HashSet(trans.size());
HashMap openTransactions = new HashMap();
HashMap inprocessAcks = new HashMap();
HashMap committingTransactions = new HashMap();
// loop through the list of transactions
// placing each on the various lists
int prepareCN = 0, commitWaitCN = 0;
Iterator itr = trans.entrySet().iterator();
while (itr.hasNext()) {
try {
Map.Entry entry = (Map.Entry) itr.next();
TransactionUID tid = (TransactionUID) entry.getKey();
TransactionInfo tif = (TransactionInfo) entry.getValue();
TransactionState ts = tif.getTransactionState();
TransactionAcknowledgement[] ta = pstore.getTransactionAcks(tid);
if (ta == null) {
ta = new TransactionAcknowledgement[0];
}
int state = ts.getState();
if (DEBUG) {
logger.log(Logger.INFO, "Load transaction: TUID=" + tid + "[" + TransactionState.toString(state) + (ts.getCreationTime() == 0 ? "" : " createTime=" + ts.getCreationTime()) + "]");
}
switch(state) {
// no longer valid, ignore
case TransactionState.CREATED:
clearTrans.add(tid);
break;
case TransactionState.PREPARED:
// if autorollback, fall through to rollback
if (!AUTO_ROLLBACK) {
// nothing happens w/ preparedTransactions
// they go back into the list
// We don't persist this because it is already
// in the store
addTransactionID(tid, ts, false);
if (tif.getType() == TransactionInfo.TXN_CLUSTER) {
logClusterTransaction(tid, ts, tif.getTransactionBrokers(), true, false);
prepareCN++;
}
openTransactions.put(tid, Boolean.TRUE);
if (ts.getOnephasePrepare()) {
addDetachedTransactionID(tid);
}
break;
}
// rollback -> we didnt complete
case TransactionState.STARTED:
case TransactionState.COMPLETE:
case TransactionState.ROLLEDBACK:
case TransactionState.FAILED:
case TransactionState.INCOMPLETE:
addTransactionID(tid, ts, false);
if (tif.getType() == TransactionInfo.TXN_CLUSTER) {
logClusterTransaction(tid, ts, tif.getTransactionBrokers(), true, false);
}
openTransactions.put(tid, Boolean.FALSE);
clearTrans.add(tid);
ts.setState(TransactionState.ROLLEDBACK);
if (state == TransactionState.PREPARED) {
clearAckOnlyTrans.add(tid);
try {
updateState(tid, TransactionState.ROLLEDBACK, true);
} catch (Exception e) {
logger.logStack(Logger.WARNING, "Unable to update auto-rollback PREPARED transaction " + tid + " state to ROLLEDBACK", e);
}
}
break;
case TransactionState.COMMITTED:
committingTransactions.put(tid, "");
if (tif.getType() == TransactionInfo.TXN_CLUSTER) {
boolean completed = true;
TransactionBroker[] brokers = tif.getTransactionBrokers();
logClusterTransaction(tid, ts, brokers, false, false);
for (int i = 0; brokers != null && i < brokers.length; i++) {
completed = brokers[i].isCompleted();
if (!completed) {
if (DEBUG_CLUSTER_TXN) {
logger.log(logger.INFO, "COMMITTED cluster transaction " + tid + ", incomplete broker:" + brokers[i]);
}
break;
}
}
if (!completed) {
commitWaitCN++;
}
} else {
addTransactionID(tid, ts, false);
}
clearTrans.add(tid);
break;
default:
logger.log(logger.ERROR, "Internal Error unexpected transaction state:" + TransactionState.toString(state) + " TUID=" + tid + ", set to PREPARE");
addTransactionID(tid, ts, false);
if (tif.getType() == TransactionInfo.TXN_CLUSTER) {
logClusterTransaction(tid, ts, tif.getTransactionBrokers(), true, false);
}
updateState(tid, TransactionState.PREPARED, true);
openTransactions.put(tid, Boolean.TRUE);
}
for (int i = 0; i < ta.length; i++) {
if (DEBUG) {
logger.log(Logger.INFO, "Load transaction ack " + ta[i] + " [TUID=" + tid + "]");
}
ConsumerUID cuid = ta[i].getConsumerUID();
ConsumerUID scuid = ta[i].getStoredConsumerUID();
SysMessageID sysid = ta[i].getSysMessageID();
Map imap = (Map) inprocessAcks.get(sysid);
if (scuid == null) {
logger.log(Logger.WARNING, "Internal Error: " + " Unable to locate stored ConsumerUID :" + Arrays.toString(ta));
scuid = cuid;
}
if (imap == null) {
imap = new HashMap();
inprocessAcks.put(sysid, imap);
}
imap.put(scuid, tid);
if (openTransactions.get(tid) != null) {
TransactionInformation ti = (TransactionInformation) translist.get(tid);
if (ti == null) {
logger.log(Logger.INFO, "Unable to retrieve " + " transaction information " + ti + " for " + tid + " we may be clearing the transaction");
continue;
}
if (openTransactions.get(tid) == Boolean.TRUE) {
ti.addConsumedMessage(sysid, cuid, scuid);
}
ti.addOrphanAck(sysid, scuid);
}
}
} catch (Exception ex) {
logger.logStack(Logger.WARNING, BrokerResources.E_INTERNAL_BROKER_ERROR, "Error parsing transaction ", ex);
}
}
{
Object[] args = { Integer.valueOf(prepareCN), Integer.valueOf(commitWaitCN) };
logger.log(logger.INFO, Globals.getBrokerResources().getKString(BrokerResources.I_NCLUSTER_TRANS, args));
}
HashMap remoteTrans = pstore.getAllRemoteTransactionStates();
// list of transactions which need to be cleaned up
HashSet clearRemoteTrans = new HashSet(remoteTrans.size());
int prepareRN = 0, commitRN = 0, completeRN = 0;
itr = remoteTrans.entrySet().iterator();
while (itr.hasNext()) {
try {
Map.Entry entry = (Map.Entry) itr.next();
TransactionUID tid = (TransactionUID) entry.getKey();
TransactionState ts = (TransactionState) entry.getValue();
TransactionAcknowledgement[] ta = pstore.getTransactionAcks(tid);
int state = ts.getState();
if (DEBUG) {
logger.log(Logger.INFO, "Load remote transaction: TUID=" + tid + "[" + TransactionState.toString(state) + (ts.getCreationTime() == 0 ? "" : " createTime=" + ts.getCreationTime()) + "]");
}
switch(state) {
case TransactionState.CREATED:
clearRemoteTrans.add(tid);
break;
case TransactionState.PREPARED:
prepareRN++;
logRemoteTransaction(tid, ts, ta, pstore.getRemoteTransactionHomeBroker(tid), true, true, false);
openTransactions.put(tid, Boolean.TRUE);
break;
case TransactionState.COMPLETE:
if (Globals.getHAEnabled() && ta != null && ta.length > 0) {
completeRN++;
ts.setState(TransactionState.PREPARED);
logRemoteTransaction(tid, ts, ta, pstore.getRemoteTransactionHomeBroker(tid), true, true, false);
openTransactions.put(tid, Boolean.TRUE);
break;
}
case TransactionState.STARTED:
case TransactionState.ROLLEDBACK:
case TransactionState.FAILED:
case TransactionState.INCOMPLETE:
openTransactions.put(tid, Boolean.FALSE);
clearRemoteTrans.add(tid);
break;
case TransactionState.COMMITTED:
commitRN++;
logRemoteTransaction(tid, ts, ta, pstore.getRemoteTransactionHomeBroker(tid), true, true, false);
committingTransactions.put(tid, "");
break;
default:
logger.log(logger.ERROR, "Internal Error unexpected transaction state:" + TransactionState.toString(state) + " TUID=" + tid + ", set to PREPARED");
logRemoteTransaction(tid, ts, ta, pstore.getRemoteTransactionHomeBroker(tid), true, true, false);
updateRemoteTransactionState(tid, TransactionState.PREPARED, true, true, true);
openTransactions.put(tid, Boolean.TRUE);
}
for (int i = 0; i < ta.length; i++) {
if (DEBUG) {
logger.log(Logger.INFO, "Load remote transaction ack " + ta[i] + " [TUID=" + tid + "]");
}
ConsumerUID cuid = ta[i].getConsumerUID();
ConsumerUID scuid = ta[i].getStoredConsumerUID();
SysMessageID sysid = ta[i].getSysMessageID();
Map imap = (Map) inprocessAcks.get(sysid);
if (scuid == null) {
logger.log(Logger.WARNING, "Internal Error: " + " Unable to locate stored ConsumerUID :" + Arrays.toString(ta));
scuid = cuid;
}
if (imap == null) {
imap = new HashMap();
inprocessAcks.put(sysid, imap);
}
imap.put(scuid, tid);
}
} catch (Exception ex) {
logger.logStack(Logger.WARNING, BrokerResources.E_INTERNAL_BROKER_ERROR, "Error parsing remote transaction ", ex);
}
}
if (Globals.getHAEnabled()) {
Object[] args = { String.valueOf(remoteTrans.size()), String.valueOf(prepareRN), String.valueOf(completeRN), String.valueOf(commitRN) };
logger.log(logger.INFO, Globals.getBrokerResources().getString(BrokerResources.I_NREMOTE_TRANS_HA, args));
} else {
Object[] args = { String.valueOf(remoteTrans.size()), String.valueOf(prepareRN), String.valueOf(commitRN) };
logger.log(logger.INFO, Globals.getBrokerResources().getString(BrokerResources.I_NREMOTE_TRANS, args));
}
// load the database now and fix it
if (openTransactions.size() > 0 || inprocessAcks.size() > 0) {
LinkedHashMap m = DL.processTransactions(inprocessAcks, openTransactions, committingTransactions);
if (m != null && !m.isEmpty()) {
Iterator meitr = m.entrySet().iterator();
while (meitr.hasNext()) {
Map.Entry me = (Map.Entry) meitr.next();
TransactionInformation ti = (TransactionInformation) translist.get(me.getValue());
ti.addPublishedMessage((SysMessageID) me.getKey());
}
}
}
// OK -> now clean up the cleared transactions
// this removes them from the disk
itr = clearTrans.iterator();
while (itr.hasNext()) {
TransactionUID tid = (TransactionUID) itr.next();
logger.log(Logger.DEBUG, "Clearing transaction " + tid);
if (!clearAckOnlyTrans.contains(tid)) {
removeTransactionAck(tid);
removeTransactionID(tid);
} else {
removeTransactionAck(tid, true);
}
}
itr = clearRemoteTrans.iterator();
while (itr.hasNext()) {
TransactionUID tid = (TransactionUID) itr.next();
try {
logger.log(Logger.DEBUG, "Clearing remote transaction " + tid);
removeRemoteTransactionAck(tid);
removeRemoteTransactionID(tid, true);
} catch (Exception e) {
logger.log(logger.WARNING, "Failed to remove remote transaction TUID=" + tid + ": " + e.getMessage());
}
}
}
Aggregations