예제 #1
0
  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();
  }
예제 #2
0
  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);
    }
  }
예제 #3
0
  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();
    }
  }
예제 #4
0
  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();
    }
  }
예제 #5
0
  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;
  }
예제 #6
0
  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;
  }
예제 #7
0
  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();
  }
예제 #8
0
  @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;
  }
예제 #9
0
  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;
  }
예제 #10
0
  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();
    }
  }
예제 #11
0
  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);
    }
  }
예제 #12
0
  /**
   * @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);
      }
    }
  }
예제 #13
0
  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();
    }
  }
예제 #14
0
    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();
      }
    }
예제 #15
0
  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;
    }
  }
예제 #16
0
  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);
    }
  }
예제 #17
0
  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;
    }
  }