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 void expire(final long consumerID, final long messageID) throws Exception { MessageReference ref = consumers.get(consumerID).removeReferenceByID(messageID); if (ref != null) { ref.getQueue().expire(ref); } }
public long countMessages(final String filterStr) throws Exception { checkStarted(); clearIO(); try { Filter filter = FilterImpl.createFilter(filterStr); if (filter == null) { return getMessageCount(); } else { LinkedListIterator<MessageReference> iterator = queue.iterator(); try { int count = 0; while (iterator.hasNext()) { MessageReference ref = iterator.next(); if (filter.match(ref.getMessage())) { count++; } } return count; } finally { iterator.close(); } } } finally { blockOnIO(); } }
public Map<String, Object>[] listMessages(final String filterStr) throws Exception { checkStarted(); clearIO(); try { Filter filter = FilterImpl.createFilter(filterStr); List<Map<String, Object>> messages = new ArrayList<Map<String, Object>>(); queue.flushExecutor(); LinkedListIterator<MessageReference> iterator = queue.iterator(); try { while (iterator.hasNext()) { MessageReference ref = iterator.next(); if (filter == null || filter.match(ref.getMessage())) { Message message = ref.getMessage(); messages.add(message.toMap()); } } return messages.toArray(new Map[messages.size()]); } finally { iterator.close(); } } catch (HornetQException e) { throw new IllegalStateException(e.getMessage()); } finally { blockOnIO(); } }
public MessageReference removeReferenceByID(final long messageID) throws Exception { if (browseOnly) { return null; } // Expiries can come in out of sequence with respect to delivery order Iterator<MessageReference> iter = deliveringRefs.iterator(); MessageReference ref = null; while (iter.hasNext()) { MessageReference theRef = iter.next(); if (theRef.getMessage().getMessageID() == messageID) { iter.remove(); ref = theRef; break; } } return ref; }
public synchronized HandleStatus handle(final MessageReference reference) { if (statusToReturn == HandleStatus.BUSY) { return HandleStatus.BUSY; } if (filter != null) { if (filter.match(reference.getMessage())) { references.addLast(reference); reference.getQueue().referenceHandled(); notify(); return HandleStatus.HANDLED; } else { return HandleStatus.NO_MATCH; } } if (newStatus != null) { if (delayCountdown == 0) { statusToReturn = newStatus; newStatus = null; } else { delayCountdown--; } } if (statusToReturn == HandleStatus.HANDLED) { reference.getQueue().referenceHandled(); references.addLast(reference); notify(); } return statusToReturn; }
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(); }
@Override public boolean equals(Object other) { if (this == other) { return true; } if (other instanceof MessageReferenceImpl) { MessageReference reference = (MessageReferenceImpl) other; if (this.getMessage().equals(reference.getMessage())) return true; } return false; }
public LinkedList<MessageReference> cancelRefs( final boolean failed, final boolean lastConsumedAsDelivered, final Transaction tx) throws Exception { boolean performACK = lastConsumedAsDelivered; try { if (largeMessageDeliverer != null) { largeMessageDeliverer.finish(); } } catch (Throwable e) { HornetQServerLogger.LOGGER.errorResttingLargeMessage(e, largeMessageDeliverer); } finally { largeMessageDeliverer = null; } LinkedList<MessageReference> refs = new LinkedList<MessageReference>(); if (!deliveringRefs.isEmpty()) { for (MessageReference ref : deliveringRefs) { if (isTrace) { HornetQServerLogger.LOGGER.trace( "Cancelling reference for messageID = " + ref.getMessage().getMessageID() + ", ref = " + ref); } if (performACK) { acknowledge(false, tx, ref.getMessage().getMessageID()); performACK = false; } else { if (!failed) { // We don't decrement delivery count if the client failed, since there's a possibility // that refs // were actually delivered but we just didn't get any acks for them // before failure ref.decrementDeliveryCount(); } refs.add(ref); } } deliveringRefs.clear(); } return refs; }
public Map<String, Object>[] listScheduledMessages() throws Exception { checkStarted(); clearIO(); try { List<MessageReference> refs = queue.getScheduledMessages(); Map<String, Object>[] messages = new Map[refs.size()]; int i = 0; for (MessageReference ref : refs) { Message message = ref.getMessage(); messages[i++] = message.toMap(); } return messages; } finally { blockOnIO(); } }
public void individualAcknowledge( final boolean autoCommitAcks, final Transaction tx, final long messageID) throws Exception { if (browseOnly) { return; } MessageReference ref = removeReferenceByID(messageID); if (ref == null) { throw new IllegalStateException("Cannot find ref to ack " + messageID); } if (autoCommitAcks) { ref.getQueue().acknowledge(ref); } else { ref.getQueue().acknowledge(tx, ref); } }
/** * @param ref * @param message */ private void deliverStandardMessage(final MessageReference ref, final ServerMessage message) { int packetSize = callback.sendMessage(message, id, ref.getDeliveryCount()); if (availableCredits != null) { availableCredits.addAndGet(-packetSize); if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( this + "::FlowControl::delivery standard taking " + packetSize + " from credits, available now is " + availableCredits); } } }
public void proceedDeliver(MessageReference reference) throws Exception { try { ServerMessage message = reference.getMessage(); if (message.isLargeMessage()) { if (largeMessageDeliverer == null) { // This can't really happen as handle had already crated the deliverer // instead of throwing an exception in weird cases there is no problem on just go ahead // and create it // again here largeMessageDeliverer = new LargeMessageDeliverer((LargeServerMessage) message, reference); } // The deliverer was prepared during handle, as we can't have more than one pending large // message // as it would return busy if there is anything pending largeMessageDeliverer.deliver(); } else { deliverStandardMessage(reference, message); } } finally { lockDelivery.readLock().unlock(); } }
public boolean deliver() throws Exception { lockDelivery.readLock().lock(); try { if (largeMessage == null) { return true; } if (availableCredits != null && availableCredits.get() <= 0) { if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( this + "::FlowControl::delivery largeMessage interrupting as there are no more credits, available=" + availableCredits); } return false; } if (!sentInitialPacket) { context = largeMessage.getBodyEncoder(); sizePendingLargeMessage = context.getLargeBodySize(); context.open(); sentInitialPacket = true; int packetSize = callback.sendLargeMessage( largeMessage, id, context.getLargeBodySize(), ref.getDeliveryCount()); if (availableCredits != null) { availableCredits.addAndGet(-packetSize); if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( this + "::FlowControl::" + " deliver initialpackage with " + packetSize + " delivered, available now = " + availableCredits); } } // Execute the rest of the large message on a different thread so as not to tie up the // delivery thread // for too long resumeLargeMessage(); return false; } else { if (availableCredits != null && availableCredits.get() <= 0) { if (ServerConsumerImpl.isTrace) { HornetQServerLogger.LOGGER.trace( this + "::FlowControl::deliverLargeMessage Leaving loop of send LargeMessage because of credits, available=" + availableCredits); } return false; } int localChunkLen = 0; localChunkLen = (int) Math.min( sizePendingLargeMessage - positionPendingLargeMessage, minLargeMessageSize); HornetQBuffer bodyBuffer = HornetQBuffers.fixedBuffer(localChunkLen); context.encode(bodyBuffer, localChunkLen); byte[] body = bodyBuffer.toByteBuffer().array(); int packetSize = callback.sendLargeMessageContinuation( id, body, positionPendingLargeMessage + localChunkLen < sizePendingLargeMessage, false); int chunkLen = body.length; if (availableCredits != null) { availableCredits.addAndGet(-packetSize); if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( this + "::FlowControl::largeMessage deliver continuation, packetSize=" + packetSize + " available now=" + availableCredits); } } positionPendingLargeMessage += chunkLen; if (positionPendingLargeMessage < sizePendingLargeMessage) { resumeLargeMessage(); return false; } } if (ServerConsumerImpl.isTrace) { HornetQServerLogger.LOGGER.trace("Finished deliverLargeMessage"); } finish(); return true; } finally { lockDelivery.readLock().unlock(); } }
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 HandleStatus handle(final MessageReference ref) throws Exception { if (availableCredits != null && availableCredits.get() <= 0) { if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( this + " is busy for the lack of credits. Current credits = " + availableCredits + " Can't receive reference " + ref); } return HandleStatus.BUSY; } // TODO - https://jira.jboss.org/browse/HORNETQ-533 // if (!writeReady.get()) // { // return HandleStatus.BUSY; // } synchronized (lock) { // If the consumer is stopped then we don't accept the message, it // should go back into the // queue for delivery later. if (!started || transferring) { return HandleStatus.BUSY; } // If there is a pendingLargeMessage we can't take another message // This has to be checked inside the lock as the set to null is done inside the lock if (largeMessageDeliverer != null) { if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( this + " is busy delivering large message " + largeMessageDeliverer + ", can't deliver reference " + ref); } return HandleStatus.BUSY; } final ServerMessage message = ref.getMessage(); if (filter != null && !filter.match(message)) { if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( "Reference " + ref + " is a noMatch on consumer " + this); } return HandleStatus.NO_MATCH; } if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace("Handling reference " + ref); } if (!browseOnly) { if (!preAcknowledge) { deliveringRefs.add(ref); } ref.handled(); ref.incrementDeliveryCount(); // If updateDeliveries = false (set by strict-update), // the updateDeliveryCount would still be updated after c if (strictUpdateDeliveryCount && !ref.isPaged()) { if (ref.getMessage().isDurable() && ref.getQueue().isDurable() && !ref.getQueue().isInternalQueue() && !ref.isPaged()) { storageManager.updateDeliveryCount(ref); } } if (preAcknowledge) { if (message.isLargeMessage()) { // we must hold one reference, or the file will be deleted before it could be delivered ((LargeServerMessage) message).incrementDelayDeletionCount(); } // With pre-ack, we ack *before* sending to the client ref.getQueue().acknowledge(ref); } } if (message.isLargeMessage()) { largeMessageDeliverer = new LargeMessageDeliverer((LargeServerMessage) message, ref); } lockDelivery.readLock().lock(); return HandleStatus.HANDLED; } }