private void doRollback( final boolean clientFailed, final boolean lastMessageAsDelived, final Transaction theTx) throws Exception { boolean wasStarted = started; List<MessageReference> toCancel = new ArrayList<MessageReference>(); for (ServerConsumer consumer : consumers.values()) { if (wasStarted) { consumer.setStarted(false); } toCancel.addAll(consumer.cancelRefs(clientFailed, lastMessageAsDelived, theTx)); } for (MessageReference ref : toCancel) { ref.getQueue().cancel(theTx, ref); } if (wasStarted) { theTx.addOperation( new TransactionOperationAbstract() { public void afterRollback(Transaction tx) { for (ServerConsumer consumer : consumers.values()) { consumer.setStarted(true); } } }); } theTx.rollback(); }
public synchronized void xaFailed(final Xid xid) throws Exception { if (tx != null) { final String msg = "Cannot start, session is already doing work in a transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { tx = newTransaction(xid); tx.markAsRollbackOnly( new HornetQException("Can't commit as a Failover happened during the operation")); if (isTrace) { HornetQServerLogger.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 HornetQXAException(XAException.XAER_DUPID, msg); } } }
public synchronized void xaResume(final Xid xid) throws Exception { if (tx != null) { final String msg = "Cannot resume, session is currently doing work in a transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { Transaction theTx = resourceManager.getTransaction(xid); if (theTx == null) { final String msg = "Cannot find xid in resource manager: " + xid; throw new HornetQXAException(XAException.XAER_NOTA, msg); } else { if (theTx.getState() != Transaction.State.SUSPENDED) { throw new HornetQXAException( XAException.XAER_PROTO, "Cannot resume transaction, it is not suspended " + xid); } else { tx = theTx; tx.resume(); } } } }
private void doRollback( final boolean clientFailed, final boolean lastMessageAsDelived, final Transaction theTx) throws Exception { boolean wasStarted = started; List<MessageReference> toCancel = new ArrayList<MessageReference>(); for (ServerConsumer consumer : consumers.values()) { if (wasStarted) { consumer.setStarted(false); } toCancel.addAll(consumer.cancelRefs(clientFailed, lastMessageAsDelived, theTx)); } for (MessageReference ref : toCancel) { ref.getQueue().cancel(theTx, ref); } // if we failed don't restart as an attempt to deliver messages may be made before we actually // close the consumer if (wasStarted && !clientFailed) { theTx.addOperation( new TransactionOperationAbstract() { @Override public void afterRollback(Transaction tx) { for (ServerConsumer consumer : consumers.values()) { consumer.setStarted(true); } } }); } theTx.rollback(); }
public synchronized void xaRollback(final Xid xid) throws Exception { if (tx != null && tx.getXid().equals(xid)) { final String msg = "Cannot roll back, session is currently doing work in a transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { Transaction theTx = resourceManager.removeTransaction(xid); if (isTrace) { HornetQLogger.LOGGER.trace("xarollback into " + theTx); } if (theTx == null) { // checked heuristic committed transactions if (resourceManager.getHeuristicCommittedTransactions().contains(xid)) { throw new HornetQXAException( XAException.XA_HEURCOM, "transaction has ben heuristically committed: " + xid); } // checked heuristic rolled back transactions else if (resourceManager.getHeuristicRolledbackTransactions().contains(xid)) { throw new HornetQXAException( XAException.XA_HEURRB, "transaction has ben heuristically rolled back: " + xid); } else { if (isTrace) { HornetQLogger.LOGGER.trace( "xarollback into " + theTx + ", xid=" + xid + " forcing a rollback regular"); } try { // jbpapp-8845 // This could have happened because the TX timed out, // at this point we would be better on rolling back this session as a way to prevent // consumers from holding their messages this.rollback(false); } catch (Exception e) { HornetQLogger.LOGGER.warn(e.getMessage(), e); } throw new HornetQXAException( XAException.XAER_NOTA, "Cannot find xid in resource manager: " + xid); } } else { if (theTx.getState() == Transaction.State.SUSPENDED) { if (isTrace) { HornetQLogger.LOGGER.trace( "xarollback into " + theTx + " sending tx back as it was suspended"); } // Put it back resourceManager.putTransaction(xid, tx); throw new HornetQXAException( XAException.XAER_PROTO, "Cannot rollback transaction, it is suspended " + xid); } else { doRollback(false, false, theTx); } } } }
private synchronized void doClose(final boolean failed) throws Exception { if (tx != null && tx.getXid() == null) { // We only rollback local txs on close, not XA tx branches try { rollback(failed, false); } catch (Exception e) { HornetQLogger.LOGGER.warn(e.getMessage(), e); } } Set<ServerConsumer> consumersClone = new HashSet<ServerConsumer>(consumers.values()); for (ServerConsumer consumer : consumersClone) { consumer.close(failed); } consumers.clear(); server.removeSession(name); if (currentLargeMessage != null) { try { currentLargeMessage.deleteFile(); } catch (Throwable error) { HornetQLogger.LOGGER.errorDeletingLargeMessageFile(error); } } remotingConnection.removeFailureListener(this); callback.closed(); }
private void doSend(final ServerMessage msg, final boolean direct) throws Exception { // check the user has write access to this address. try { securityStore.check(msg.getAddress(), CheckType.SEND, this); } catch (HornetQException e) { if (!autoCommitSends) { tx.markAsRollbackOnly(e); } throw e; } if (tx == null || autoCommitSends) { } else { routingContext.setTransaction(tx); } postOffice.route(msg, routingContext, direct); Pair<UUID, AtomicLong> value = targetAddressInfos.get(msg.getAddress()); if (value == null) { targetAddressInfos.put( msg.getAddress(), new Pair<UUID, AtomicLong>(msg.getUserID(), new AtomicLong(1))); } else { value.setA(msg.getUserID()); value.getB().incrementAndGet(); } routingContext.clear(); }
public synchronized void xaJoin(final Xid xid) throws Exception { Transaction theTx = resourceManager.getTransaction(xid); if (theTx == null) { final String msg = "Cannot find xid in resource manager: " + xid; throw new HornetQXAException(XAException.XAER_NOTA, msg); } else { if (theTx.getState() == Transaction.State.SUSPENDED) { throw new HornetQXAException( XAException.XAER_PROTO, "Cannot join tx, it is suspended " + xid); } else { tx = theTx; } } }
public synchronized void xaCommit(final Xid xid, final boolean onePhase) throws Exception { if (tx != null && tx.getXid().equals(xid)) { final String msg = "Cannot commit, session is currently doing work in transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { Transaction theTx = resourceManager.removeTransaction(xid); if (isTrace) { HornetQLogger.LOGGER.trace("XAcommit into " + theTx + ", xid=" + xid); } if (theTx == null) { // checked heuristic committed transactions if (resourceManager.getHeuristicCommittedTransactions().contains(xid)) { throw new HornetQXAException( XAException.XA_HEURCOM, "transaction has been heuristically committed: " + xid); } // checked heuristic rolled back transactions else if (resourceManager.getHeuristicRolledbackTransactions().contains(xid)) { throw new HornetQXAException( XAException.XA_HEURRB, "transaction has been heuristically rolled back: " + xid); } else { if (isTrace) { HornetQLogger.LOGGER.trace( "XAcommit into " + theTx + ", xid=" + xid + " cannot find it"); } throw new HornetQXAException( XAException.XAER_NOTA, "Cannot find xid in resource manager: " + xid); } } else { if (theTx.getState() == Transaction.State.SUSPENDED) { // Put it back resourceManager.putTransaction(xid, theTx); throw new HornetQXAException( XAException.XAER_PROTO, "Cannot commit transaction, it is suspended " + xid); } else { theTx.commit(onePhase); } } } }
public void individualAcknowledge(final long consumerID, final long messageID) throws Exception { ServerConsumer consumer = consumers.get(consumerID); if (this.xa && tx == null) { throw new HornetQXAException(XAException.XAER_PROTO, "Invalid transaction state"); } 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(autoCommitAcks, tx, messageID); newTX.rollback(); } else { consumer.individualAcknowledge(autoCommitAcks, tx, messageID); } }
public void acknowledge(final long consumerID, final long messageID) throws Exception { ServerConsumer consumer = consumers.get(consumerID); if (consumer == null) { throw HornetQMessageBundle.BUNDLE.consumerDoesntExist(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.acknowledge(autoCommitAcks, newTX, messageID); newTX.rollback(); } else { consumer.acknowledge(autoCommitAcks, tx, messageID); } }
/** * Delete everything associated with any queue on this address. This is to be called when the * address is about to be released from paging. Hence the PagingStore will be holding a write * lock, meaning no messages are going to be paged at this time. So, we shouldn't lock anything * after this method, to avoid dead locks between the writeLock and any synchronization with the * CursorProvider. */ public void onPageModeCleared() { ArrayList<PageSubscription> subscriptions = cloneSubscriptions(); Transaction tx = new TransactionImpl(storageManager); for (PageSubscription sub : subscriptions) { try { sub.onPageModeCleared(tx); } catch (Exception e) { HornetQServerLogger.LOGGER.warn( "Error while cleaning paging on queue " + sub.getQueue().getName(), e); } } try { tx.commit(); } catch (Exception e) { HornetQServerLogger.LOGGER.warn("Error while cleaning page, during the commit", e); } }
public synchronized void commit() throws Exception { if (isTrace) { HornetQLogger.LOGGER.trace("Calling commit"); } try { tx.commit(); } finally { tx = newTransaction(); } }
public synchronized void xaPrepare(final Xid xid) throws Exception { if (tx != null && tx.getXid().equals(xid)) { final String msg = "Cannot commit, session is currently doing work in a transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { Transaction theTx = resourceManager.getTransaction(xid); if (isTrace) { HornetQLogger.LOGGER.trace("xaprepare into " + ", xid=" + xid + ", tx= " + tx); } if (theTx == null) { final String msg = "Cannot find xid in resource manager: " + xid; throw new HornetQXAException(XAException.XAER_NOTA, msg); } else { if (theTx.getState() == Transaction.State.SUSPENDED) { throw new HornetQXAException( XAException.XAER_PROTO, "Cannot prepare transaction, it is suspended " + xid); } else if (theTx.getState() == Transaction.State.PREPARED) { HornetQLogger.LOGGER.info("ignoring prepare on xid as already called :" + xid); } else { theTx.prepare(); } } } }
public synchronized void xaStart(final Xid xid) throws Exception { if (tx != null) { HornetQServerLogger.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) { HornetQServerLogger.LOGGER.debug( "An exception happened while we tried to debug the previous tx, we can ignore this exception", e); } } tx = newTransaction(xid); if (isTrace) { HornetQServerLogger.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 HornetQXAException(XAException.XAER_DUPID, msg); } }
public synchronized void xaSuspend() throws Exception { if (isTrace) { HornetQLogger.LOGGER.trace("xasuspend on " + this.tx); } if (tx == null) { final String msg = "Cannot suspend, session is not doing work in a transaction "; throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { if (tx.getState() == Transaction.State.SUSPENDED) { final String msg = "Cannot suspend, transaction is already suspended " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { tx.suspend(); tx = null; } } }
public synchronized void xaStart(final Xid xid) throws Exception { if (tx != null) { final String msg = "Cannot start, session is already doing work in a transaction " + tx.getXid(); throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { tx = newTransaction(xid); if (isTrace) { HornetQLogger.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 HornetQXAException(XAException.XAER_DUPID, msg); } } }
@Override public List<MessageReference> getInTXMessagesForConsumer(long consumerId) { if (this.tx != null) { QueueImpl.RefsOperation oper = (QueueImpl.RefsOperation) tx.getProperty(TransactionPropertyIndexes.REFS_OPERATION); if (oper == null) { return Collections.emptyList(); } else { return oper.getListOnConsumer(consumerId); } } else { return Collections.emptyList(); } }
private void doClose(final boolean failed) throws Exception { synchronized (this) { if (closed) return; if (tx != null && tx.getXid() == null) { // We only rollback local txs on close, not XA tx branches try { rollback(failed, false); } catch (Exception e) { HornetQServerLogger.LOGGER.warn(e.getMessage(), e); } } server.removeSession(name); remotingConnection.removeFailureListener(this); callback.closed(); closed = true; } // putting closing of consumers outside the sync block // https://issues.jboss.org/browse/HORNETQ-1141 Set<ServerConsumer> consumersClone = new HashSet<ServerConsumer>(consumers.values()); for (ServerConsumer consumer : consumersClone) { consumer.close(failed); } consumers.clear(); if (currentLargeMessage != null) { try { currentLargeMessage.deleteFile(); } catch (Throwable error) { HornetQServerLogger.LOGGER.errorDeletingLargeMessageFile(error); } } }
private void handleManagementMessage(final ServerMessage message, final boolean direct) throws Exception { try { securityStore.check(message.getAddress(), CheckType.MANAGE, this); } catch (HornetQException e) { if (!autoCommitSends) { tx.markAsRollbackOnly(e); } throw e; } ServerMessage reply = managementService.handleMessage(message); SimpleString replyTo = message.getSimpleStringProperty(ClientMessageImpl.REPLYTO_HEADER_NAME); if (replyTo != null) { reply.setAddress(replyTo); doSend(reply, direct); } }
public synchronized void xaEnd(final Xid xid) throws Exception { if (tx != null && tx.getXid().equals(xid)) { if (tx.getState() == Transaction.State.SUSPENDED) { final String msg = "Cannot end, transaction is suspended"; throw new HornetQXAException(XAException.XAER_PROTO, msg); } else if (tx.getState() == Transaction.State.ROLLEDBACK) { final String msg = "Cannot end, transaction is rolled back"; tx = null; throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { tx = null; } } else { // It's also legal for the TM to call end for a Xid in the suspended // state // See JTA 1.1 spec 3.4.4 - state diagram // Although in practice TMs rarely do this. Transaction theTx = resourceManager.getTransaction(xid); if (theTx == null) { final String msg = "Cannot find suspended transaction to end " + xid; throw new HornetQXAException(XAException.XAER_NOTA, msg); } else { if (theTx.getState() != Transaction.State.SUSPENDED) { final String msg = "Transaction is not suspended " + xid; throw new HornetQXAException(XAException.XAER_PROTO, msg); } else { theTx.resume(); } } } }
public void acknowledge(final boolean autoCommitAcks, Transaction tx, final long messageID) throws Exception { if (browseOnly) { return; } // Acknowledge acknowledges all refs delivered by the consumer up to and including the one // explicitly // acknowledged // We use a transaction here as if the message is not found, we should rollback anything done // This could eventually happen on retries during transactions, and we need to make sure we // don't ACK things we are not supposed to acknowledge boolean startedTransaction = false; if (tx == null || autoCommitAcks) { startedTransaction = true; tx = new TransactionImpl(storageManager); } try { MessageReference ref; do { ref = deliveringRefs.poll(); if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( "ACKing ref " + ref + " on tx= " + tx + ", consumer=" + this); } if (ref == null) { throw HornetQMessageBundle.BUNDLE.consumerNoReference( id, messageID, messageQueue.getName()); } ref.getQueue().acknowledge(tx, ref); } while (ref.getMessage().getMessageID() != messageID); if (startedTransaction) { tx.commit(); } } catch (HornetQException e) { if (startedTransaction) { tx.rollback(); } else { tx.markAsRollbackOnly(e); } throw e; } catch (Throwable e) { HornetQServerLogger.LOGGER.errorAckingMessage((Exception) e); HornetQException hqex = new HornetQIllegalStateException(e.getMessage()); if (startedTransaction) { tx.rollback(); } else { tx.markAsRollbackOnly(hqex); } throw hqex; } }
public void close(final boolean failed) throws Exception { callback.removeReadyListener(this); setStarted(false); LargeMessageDeliverer del = largeMessageDeliverer; if (del != null) { del.finish(); } if (browseOnly) { browserDeliverer.close(); } else { messageQueue.removeConsumer(this); } session.removeConsumer(id); LinkedList<MessageReference> refs = cancelRefs(failed, false, null); Iterator<MessageReference> iter = refs.iterator(); Transaction tx = new TransactionImpl(storageManager); while (iter.hasNext()) { MessageReference ref = iter.next(); ref.getQueue().cancel(tx, ref); } tx.rollback(); if (!browseOnly) { TypedProperties props = new TypedProperties(); props.putSimpleStringProperty(ManagementHelper.HDR_ADDRESS, binding.getAddress()); props.putSimpleStringProperty(ManagementHelper.HDR_CLUSTER_NAME, binding.getClusterName()); props.putSimpleStringProperty(ManagementHelper.HDR_ROUTING_NAME, binding.getRoutingName()); props.putSimpleStringProperty( ManagementHelper.HDR_FILTERSTRING, filter == null ? null : filter.getFilterString()); props.putIntProperty(ManagementHelper.HDR_DISTANCE, binding.getDistance()); props.putIntProperty(ManagementHelper.HDR_CONSUMER_COUNT, messageQueue.getConsumerCount()); // HORNETQ-946 props.putSimpleStringProperty( ManagementHelper.HDR_USER, SimpleString.toSimpleString(session.getUsername())); props.putSimpleStringProperty( ManagementHelper.HDR_REMOTE_ADDRESS, SimpleString.toSimpleString( ((ServerSessionImpl) session).getRemotingConnection().getRemoteAddress())); props.putSimpleStringProperty( ManagementHelper.HDR_SESSION_NAME, SimpleString.toSimpleString(session.getName())); Notification notification = new Notification(null, NotificationType.CONSUMER_CLOSED, props); managementService.sendNotification(notification); } }
public void xaSetTimeout(final int timeout) { timeoutSeconds = timeout; if (tx != null) { tx.setTimeout(timeout); } }