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