/** * @param clientFailed If the client has failed, we can't decrease the delivery-counts, and the close may issue a rollback * @param considerLastMessageAsDelivered * @throws Exception */ private synchronized void rollback(final boolean clientFailed, final boolean considerLastMessageAsDelivered) throws Exception { if (tx == null) { // Might be null if XA tx = newTransaction(); } doRollback(clientFailed, considerLastMessageAsDelivered, tx); if (xa) { tx = null; } else { tx = newTransaction(); } }
@Override public synchronized void commit() throws Exception { if (logger.isTraceEnabled()) { logger.trace("Calling commit"); } try { if (tx != null) { tx.commit(); } } finally { if (xa) { tx = null; } else { tx = newTransaction(); } } }
private void doRollback(final boolean clientFailed, final boolean lastMessageAsDelived, final Transaction theTx) throws Exception { boolean wasStarted = started; List<MessageReference> toCancel = new ArrayList<>(); for (ServerConsumer consumer : consumers.values()) { if (wasStarted) { consumer.setStarted(false); } toCancel.addAll(consumer.cancelRefs(clientFailed, lastMessageAsDelived, theTx)); } //we need to check this before we cancel the refs and add them to the tx, any delivering refs will have been delivered //after the last tx was rolled back so we should handle them separately. if not they //will end up added to the tx but never ever handled even tho they were removed from the consumers delivering refs. //we add them to a new tx and roll them back as the calling client will assume that this has happened. if (theTx.getState() == State.ROLLEDBACK) { Transaction newTX = newTransaction(); cancelAndRollback(clientFailed, newTX, wasStarted, toCancel); } else { cancelAndRollback(clientFailed, theTx, wasStarted, toCancel); } }
@Override public synchronized void xaFailed(final Xid xid) throws Exception { Transaction theTX = resourceManager.getTransaction(xid); if (theTX == null) { theTX = newTransaction(xid); resourceManager.putTransaction(xid, theTX); } if (theTX.isEffective()) { logger.debug("Client failed with Xid " + xid + " but the server already had it " + theTX.getState()); tx = null; } else { theTX.markAsRollbackOnly(new ActiveMQException("Can't commit as a Failover happened during the operation")); tx = theTX; } if (logger.isTraceEnabled()) { logger.trace("xastart into tx= " + tx); } }
@Override public void acknowledge(final long consumerID, final long messageID) throws Exception { ServerConsumer consumer = findConsumer(consumerID); if (tx != null && tx.getState() == State.ROLLEDBACK) { // JBPAPP-8845 - if we let stuff to be acked on a rolled back TX, we will just // have these messages to be stuck on the limbo until the server is restarted // The tx has already timed out, so we need to ack and rollback immediately Transaction newTX = newTransaction(); try { consumer.acknowledge(newTX, messageID); } catch (Exception e) { // just ignored // will log it just in case logger.debug("Ignored exception while acking messageID " + messageID + " on a rolledback TX", e); } newTX.rollback(); } else { consumer.acknowledge(autoCommitAcks ? null : tx, messageID); } }
@Override public synchronized void xaStart(final Xid xid) throws Exception { if (tx != null) { ActiveMQServerLogger.LOGGER.xidReplacedOnXStart(tx.getXid().toString(), xid.toString()); try { if (tx.getState() != Transaction.State.PREPARED) { // we don't want to rollback anything prepared here if (tx.getXid() != null) { resourceManager.removeTransaction(tx.getXid()); } tx.rollback(); } } catch (Exception e) { logger.debug("An exception happened while we tried to debug the previous tx, we can ignore this exception", e); } } tx = newTransaction(xid); if (logger.isTraceEnabled()) { logger.trace("xastart into tx= " + tx); } boolean added = resourceManager.putTransaction(xid, tx); if (!added) { final String msg = "Cannot start, there is already a xid " + tx.getXid(); throw new ActiveMQXAException(XAException.XAER_DUPID, msg); } }
@Override public void individualAcknowledge(final long consumerID, final long messageID) throws Exception { ServerConsumer consumer = findConsumer(consumerID); if (tx != null && tx.getState() == State.ROLLEDBACK) { // JBPAPP-8845 - if we let stuff to be acked on a rolled back TX, we will just // have these messages to be stuck on the limbo until the server is restarted // The tx has already timed out, so we need to ack and rollback immediately Transaction newTX = newTransaction(); consumer.individualAcknowledge(tx, messageID); newTX.rollback(); } else { consumer.individualAcknowledge(autoCommitAcks ? null : tx, messageID); } }
state.getPubRec().add(messageId); Transaction tx = session.getServerSession().newTransaction(); try { if (internal) {
state.getPubRec().add(messageId); Transaction tx = session.getServerSession().newTransaction(); try { if (internal) {
void addRetainedMessagesToQueue(Queue queue, String address) throws Exception { // The address filter that matches all retained message queues. String retainAddress = MQTTUtil.convertMQTTAddressFilterToCoreRetain(address, session.getWildcardConfiguration()); BindingQueryResult bindingQueryResult = session.getServerSession().executeBindingQuery(new SimpleString(retainAddress)); // Iterate over all matching retain queues and add the queue Transaction tx = session.getServerSession().newTransaction(); try { synchronized (queue) { for (SimpleString retainedQueueName : bindingQueryResult.getQueueNames()) { Queue retainedQueue = session.getServer().locateQueue(retainedQueueName); try (LinkedListIterator<MessageReference> i = retainedQueue.iterator()) { if (i.hasNext()) { Message message = i.next().getMessage().copy(session.getServer().getStorageManager().generateID()); sendToQueue(message, queue, tx); } } } } } catch (Throwable t) { tx.rollback(); throw t; } tx.commit(); }
void addRetainedMessagesToQueue(Queue queue, String address) throws Exception { // The address filter that matches all retained message queues. String retainAddress = MQTTUtil.convertMQTTAddressFilterToCoreRetain(address, session.getWildcardConfiguration()); BindingQueryResult bindingQueryResult = session.getServerSession().executeBindingQuery(new SimpleString(retainAddress)); // Iterate over all matching retain queues and add the queue Transaction tx = session.getServerSession().newTransaction(); try { synchronized (queue) { for (SimpleString retainedQueueName : bindingQueryResult.getQueueNames()) { Queue retainedQueue = session.getServer().locateQueue(retainedQueueName); try (LinkedListIterator<MessageReference> i = retainedQueue.iterator()) { if (i.hasNext()) { Message message = i.next().getMessage().copy(session.getServer().getStorageManager().generateID()); sendToQueue(message, queue, tx); } } } } } catch (Throwable t) { tx.rollback(); throw t; } tx.commit(); }