Search in sources :

Example 71 with ConsumerUID

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();
    }
}
Also used : Destination(com.sun.messaging.jmq.jmsserver.core.Destination) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) SortedSet(java.util.SortedSet) Set(java.util.Set) TreeSet(java.util.TreeSet) LocalTransaction(com.sun.messaging.jmq.jmsserver.data.LocalTransaction) HashMap(java.util.HashMap) CacheHashMap(com.sun.messaging.jmq.util.CacheHashMap) DataOutputStream(java.io.DataOutputStream) ArrayList(java.util.ArrayList) Consumer(com.sun.messaging.jmq.jmsserver.core.Consumer) PacketReference(com.sun.messaging.jmq.jmsserver.core.PacketReference) AckEntryNotFoundException(com.sun.messaging.jmq.jmsserver.util.AckEntryNotFoundException) Iterator(java.util.Iterator) DestinationList(com.sun.messaging.jmq.jmsserver.core.DestinationList) List(java.util.List) ArrayList(java.util.ArrayList) TransactionList(com.sun.messaging.jmq.jmsserver.data.TransactionList) MessageDeliveryTimeInfo(com.sun.messaging.jmq.jmsserver.core.MessageDeliveryTimeInfo) PartitionedStore(com.sun.messaging.jmq.jmsserver.persist.api.PartitionedStore) Agent(com.sun.messaging.jmq.jmsserver.management.agent.Agent) ConsumerUID(com.sun.messaging.jmq.jmsserver.core.ConsumerUID) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) BrokerDownException(com.sun.messaging.jmq.jmsserver.util.BrokerDownException) SelectorFormatException(com.sun.messaging.jmq.util.selector.SelectorFormatException) IOException(java.io.IOException) AckEntryNotFoundException(com.sun.messaging.jmq.jmsserver.util.AckEntryNotFoundException) MaxConsecutiveRollbackException(com.sun.messaging.jmq.jmsserver.util.MaxConsecutiveRollbackException) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) TransactionWork(com.sun.messaging.jmq.jmsserver.data.TransactionWork) TransactionBroker(com.sun.messaging.jmq.jmsserver.data.TransactionBroker) SysMessageID(com.sun.messaging.jmq.io.SysMessageID) BaseTransaction(com.sun.messaging.jmq.jmsserver.data.BaseTransaction) Map(java.util.Map) HashMap(java.util.HashMap) CacheHashMap(com.sun.messaging.jmq.util.CacheHashMap) TxnLoggingStore(com.sun.messaging.jmq.jmsserver.persist.api.TxnLoggingStore) Session(com.sun.messaging.jmq.jmsserver.core.Session)

Example 72 with ConsumerUID

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;
}
Also used : Destination(com.sun.messaging.jmq.jmsserver.core.Destination) TransactionWorkMessageAck(com.sun.messaging.jmq.jmsserver.data.TransactionWorkMessageAck) ConsumerUID(com.sun.messaging.jmq.jmsserver.core.ConsumerUID) BrokerDownException(com.sun.messaging.jmq.jmsserver.util.BrokerDownException) SelectorFormatException(com.sun.messaging.jmq.util.selector.SelectorFormatException) IOException(java.io.IOException) AckEntryNotFoundException(com.sun.messaging.jmq.jmsserver.util.AckEntryNotFoundException) MaxConsecutiveRollbackException(com.sun.messaging.jmq.jmsserver.util.MaxConsecutiveRollbackException) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) TransactionWorkMessage(com.sun.messaging.jmq.jmsserver.data.TransactionWorkMessage) TransactionWork(com.sun.messaging.jmq.jmsserver.data.TransactionWork) PacketReference(com.sun.messaging.jmq.jmsserver.core.PacketReference) Iterator(java.util.Iterator) SysMessageID(com.sun.messaging.jmq.io.SysMessageID) DestinationList(com.sun.messaging.jmq.jmsserver.core.DestinationList) List(java.util.List) ArrayList(java.util.ArrayList) TransactionList(com.sun.messaging.jmq.jmsserver.data.TransactionList) Map(java.util.Map) HashMap(java.util.HashMap) CacheHashMap(com.sun.messaging.jmq.util.CacheHashMap)

Example 73 with ConsumerUID

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;
    }
}
Also used : Destination(com.sun.messaging.jmq.jmsserver.core.Destination) Agent(com.sun.messaging.jmq.jmsserver.management.agent.Agent) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) ConsumerUID(com.sun.messaging.jmq.jmsserver.core.ConsumerUID) HashMap(java.util.HashMap) CacheHashMap(com.sun.messaging.jmq.util.CacheHashMap) ArrayList(java.util.ArrayList) BrokerDownException(com.sun.messaging.jmq.jmsserver.util.BrokerDownException) SelectorFormatException(com.sun.messaging.jmq.util.selector.SelectorFormatException) IOException(java.io.IOException) AckEntryNotFoundException(com.sun.messaging.jmq.jmsserver.util.AckEntryNotFoundException) MaxConsecutiveRollbackException(com.sun.messaging.jmq.jmsserver.util.MaxConsecutiveRollbackException) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) BrokerAddress(com.sun.messaging.jmq.jmsserver.core.BrokerAddress) DestinationUID(com.sun.messaging.jmq.jmsserver.core.DestinationUID) PacketReference(com.sun.messaging.jmq.jmsserver.core.PacketReference) Iterator(java.util.Iterator) SysMessageID(com.sun.messaging.jmq.io.SysMessageID) DestinationList(com.sun.messaging.jmq.jmsserver.core.DestinationList) List(java.util.List) ArrayList(java.util.ArrayList) TransactionList(com.sun.messaging.jmq.jmsserver.data.TransactionList) Map(java.util.Map) HashMap(java.util.HashMap) CacheHashMap(com.sun.messaging.jmq.util.CacheHashMap) PartitionedStore(com.sun.messaging.jmq.jmsserver.persist.api.PartitionedStore)

Example 74 with ConsumerUID

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);
}
Also used : BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) ConsumerUID(com.sun.messaging.jmq.jmsserver.core.ConsumerUID) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List)

Example 75 with ConsumerUID

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());
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ConsumerUID(com.sun.messaging.jmq.jmsserver.core.ConsumerUID) IOException(java.io.IOException) LoadException(com.sun.messaging.jmq.jmsserver.persist.api.LoadException) UnknownTransactionException(com.sun.messaging.jmq.jmsserver.util.UnknownTransactionException) BrokerException(com.sun.messaging.jmq.jmsserver.util.BrokerException) LoadException(com.sun.messaging.jmq.jmsserver.persist.api.LoadException) LinkedHashMap(java.util.LinkedHashMap) Iterator(java.util.Iterator) TransactionInfo(com.sun.messaging.jmq.jmsserver.persist.api.TransactionInfo) SysMessageID(com.sun.messaging.jmq.io.SysMessageID) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Aggregations

ConsumerUID (com.sun.messaging.jmq.jmsserver.core.ConsumerUID)83 SysMessageID (com.sun.messaging.jmq.io.SysMessageID)29 BrokerException (com.sun.messaging.jmq.jmsserver.util.BrokerException)28 Consumer (com.sun.messaging.jmq.jmsserver.core.Consumer)27 DestinationUID (com.sun.messaging.jmq.jmsserver.core.DestinationUID)22 PacketReference (com.sun.messaging.jmq.jmsserver.core.PacketReference)21 SelectorFormatException (com.sun.messaging.jmq.util.selector.SelectorFormatException)21 Iterator (java.util.Iterator)21 HashMap (java.util.HashMap)19 Destination (com.sun.messaging.jmq.jmsserver.core.Destination)17 TransactionUID (com.sun.messaging.jmq.jmsserver.data.TransactionUID)16 IOException (java.io.IOException)16 ArrayList (java.util.ArrayList)15 Map (java.util.Map)15 List (java.util.List)13 BrokerAddress (com.sun.messaging.jmq.jmsserver.core.BrokerAddress)10 DestinationList (com.sun.messaging.jmq.jmsserver.core.DestinationList)10 Session (com.sun.messaging.jmq.jmsserver.core.Session)10 TransactionList (com.sun.messaging.jmq.jmsserver.data.TransactionList)10 AckEntryNotFoundException (com.sun.messaging.jmq.jmsserver.util.AckEntryNotFoundException)9