Talk about the priority of artemis message

Posted by mrinfin1ty on Wed, 29 Jan 2020 16:46:29 +0100

order

This paper mainly studies the priority of artemis message

priority

activemq-artemis-2.11.0/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/message/impl/CoreMessage.java

public class CoreMessage extends RefCountMessage implements ICoreMessage {

   //......
   protected byte priority;

   public byte getPriority() {
      return priority;
   }

   public CoreMessage setPriority(byte priority) {
      this.priority = priority;
      messageChanged();
      return this;
   }

   //......
}
  • CoreMessage defines the values range from 0 (less priority) to 9 (more priority) inclusive, and provides getPriority and setPriority methods

messageReferences.add

activemq-artemis-2.11.0/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/QueueImpl.java

public class QueueImpl extends CriticalComponentImpl implements Queue {

   //......

   private final PriorityLinkedList<MessageReference> messageReferences = new PriorityLinkedListImpl<>(QueueImpl.NUM_PRIORITIES, MessageReferenceImpl.getIDComparator());

   //......   

   private synchronized void internalAddTail(final MessageReference ref) {
      refAdded(ref);
      messageReferences.addTail(ref, getPriority(ref));
      pendingMetrics.incrementMetrics(ref);
      enforceRing(false);
   }

   private void internalAddHead(final MessageReference ref) {
      queueMemorySize.addAndGet(ref.getMessageMemoryEstimate());
      pendingMetrics.incrementMetrics(ref);
      refAdded(ref);

      int priority = getPriority(ref);

      messageReferences.addHead(ref, priority);

      ref.setInDelivery(false);
   }

   private void internalAddSorted(final MessageReference ref) {
      queueMemorySize.addAndGet(ref.getMessageMemoryEstimate());
      pendingMetrics.incrementMetrics(ref);
      refAdded(ref);

      int priority = getPriority(ref);

      messageReferences.addSorted(ref, priority);
   }

   private int getPriority(MessageReference ref) {
      try {
         return ref.getMessage().getPriority();
      } catch (Throwable e) {
         ActiveMQServerLogger.LOGGER.unableToGetMessagePriority(e);
         return 4; // the default one in case of failure
      }
   }

   //......
}
  • QueueImpl defines messageReferences, whose type is prioritylinkedlist < messagereference >; its internalAddTail, internalAddHead and internalAddSorted methods will call getPriority method to get priority, return 4 in case of exception, and then add to the queue through the addTail, addHead and addSorted methods of messageReferences

PriorityLinkedList

activemq-artemis-2.11.0/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/PriorityLinkedList.java

public interface PriorityLinkedList<T> {

   void addHead(T t, int priority);

   void addTail(T t, int priority);

   void addSorted(T t, int priority);

   T poll();

   void clear();

   /**
    * Returns the size of this list.<br>
    * It is safe to be called concurrently.
    */
   int size();

   LinkedListIterator<T> iterator();

   /**
    * Returns {@code true} if empty, {@code false} otherwise.<br>
    * It is safe to be called concurrently.
    */
   boolean isEmpty();
}
  • The PriorityLinkedList interface defines the addHead, addTail, and addSorted methods according to priority, and its size and isEmpty requirements are thread safe

PriorityLinkedListImpl

activemq-artemis-2.11.0/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/PriorityLinkedListImpl.java

public class PriorityLinkedListImpl<T> implements PriorityLinkedList<T> {

   private static final AtomicIntegerFieldUpdater<PriorityLinkedListImpl> SIZE_UPDATER = AtomicIntegerFieldUpdater.newUpdater(PriorityLinkedListImpl.class, "size");

   protected LinkedListImpl<T>[] levels;

   private volatile int size;

   private int lastReset;

   private int highestPriority = -1;

   private int lastPriority = -1;

   public PriorityLinkedListImpl(final int priorities) {
      this(priorities, null);
   }


   public PriorityLinkedListImpl(final int priorities, Comparator<T> comparator) {
      levels = (LinkedListImpl<T>[]) Array.newInstance(LinkedListImpl.class, priorities);

      for (int i = 0; i < priorities; i++) {
         levels[i] = new LinkedListImpl<>(comparator);
      }
   }

   private void checkHighest(final int priority) {
      if (lastPriority != priority || priority > highestPriority) {
         lastPriority = priority;
         if (lastReset == Integer.MAX_VALUE) {
            lastReset = 0;
         } else {
            lastReset++;
         }
      }

      if (priority > highestPriority) {
         highestPriority = priority;
      }
   }

   @Override
   public void addHead(final T t, final int priority) {
      checkHighest(priority);

      levels[priority].addHead(t);

      exclusiveIncrementSize(1);
   }

   @Override
   public void addTail(final T t, final int priority) {
      checkHighest(priority);

      levels[priority].addTail(t);

      exclusiveIncrementSize(1);
   }

   @Override
   public void addSorted(T t, int priority) {
      checkHighest(priority);

      levels[priority].addSorted(t);

      exclusiveIncrementSize(1);
   }

   @Override
   public T poll() {
      T t = null;

      // We are just using a simple prioritization algorithm:
      // Highest priority refs always get returned first.
      // This could cause starvation of lower priority refs.

      // TODO - A better prioritization algorithm

      for (int i = highestPriority; i >= 0; i--) {
         LinkedListImpl<T> ll = levels[i];

         if (ll.size() != 0) {
            t = ll.poll();

            if (t != null) {
               exclusiveIncrementSize(-1);

               if (ll.size() == 0) {
                  if (highestPriority == i) {
                     highestPriority--;
                  }
               }
            }

            break;
         }
      }

      return t;
   }

   @Override
   public void clear() {
      for (LinkedListImpl<T> list : levels) {
         list.clear();
      }

      exclusiveSetSize(0);
   }

   private void exclusiveIncrementSize(int amount) {
      SIZE_UPDATER.lazySet(this, this.size + amount);
   }

   private void exclusiveSetSize(int value) {
      SIZE_UPDATER.lazySet(this, value);
   }

   @Override
   public int size() {
      return size;
   }

   @Override
   public boolean isEmpty() {
      return size == 0;
   }

   @Override
   public LinkedListIterator<T> iterator() {
      return new PriorityLinkedListIterator();
   }

   //......
}
  • PriorityLinkedListImpl implements the PriorityLinkedList interface, and its constructor needs priorities parameters. It uses Array.newInstance(LinkedListImpl.class, priorities) to create and initialize the levels array, and its array element type is LinkedListImpl; its addHead, addTail, and addSorted execute the first (x) maintenance. InkedListImpl's addHead, addTail, addSorted methods, finally call the exclusiveIncrementSize method to increase size; its poll method will start poll from LinkedListImpl of highestPriority.

Summary

CoreMessage defines the priority attribute (Values range from 0 (less priority) to 9 (more priority) inclusive), and provides getPriority and setPriority methods; QueueImpl defines messageReferences, whose type is PriorityLinkedList < messagereference >; its internalAddTail, internalAddHead and internalAddSorted methods all call getPriority methods to obtain priority, If an exception occurs, return 4, and then add it to the queue through the addTail, addHead, and addSorted methods of messageReferences. PriorityLinkedListImpl implements the PriorityLinkedList interface. Its constructor needs the priorities parameter, which uses Array.newInstance(LinkedListImpl.class, priorities) to create and initialize the levels array. Its array element type is LinkedListImpl; priorityli addHead, addTail and addSorted of nkedlistimpl are all entrusted to LinkedListImpl class

doc

Topics: Programming Java Apache less Attribute