• ActiveMQ queue 分页


    分页:即获取部分数据,queue按页从message cursor读取消息,然后分发给consumer。

    页大小:

    public abstract class BaseDestination implements Destination {
        /**
         * The maximum number of messages to page in to the destination from
         * persistent storage
         */
        public static final int MAX_PAGE_SIZE = 200;
    }

    存放分页消息的数据结构:

    public class Queue extends BaseDestination implements Task, UsageListener {
        // message cursor,可视为消息的数据源
        protected PendingMessageCursor messages;
        // 所有的分页消息
        private final PendingList pagedInMessages = new OrderedPendingList();
        // 剩余的没有dispatch的分页消息
        protected PendingList pagedInPendingDispatch = new OrderedPendingList();
    }

    把消息添加到分页中:

    protected void pageInMessages(boolean force) throws Exception {
        doDispatch(doPageInForDispatch(force, true));
    }
      1 private PendingList doPageInForDispatch(boolean force, boolean processExpired) throws Exception {
      2     List<QueueMessageReference> result = null;
      3     PendingList resultList = null;
      4 
      5     // 根据maxPageSize和message cursor中的大小,决定需要读取的消息数量
      6     int toPageIn = Math.min(getMaxPageSize(), messages.size());
      7     int pagedInPendingSize = 0;
      8     pagedInPendingDispatchLock.readLock().lock();
      9     try {
     10         pagedInPendingSize = pagedInPendingDispatch.size();
     11     } finally {
     12         pagedInPendingDispatchLock.readLock().unlock();
     13     }
     14 
     15     LOG.debug("{} toPageIn: {}, Inflight: {}, pagedInMessages.size {}, pagedInPendingDispatch.size {}, enqueueCount: {}, dequeueCount: {}, memUsage:{}",
     16             new Object[]{
     17                     destination.getPhysicalName(),
     18                     toPageIn,
     19                     destinationStatistics.getInflight().getCount(),
     20                     pagedInMessages.size(),
     21                     pagedInPendingSize,
     22                     destinationStatistics.getEnqueues().getCount(),
     23                     destinationStatistics.getDequeues().getCount(),
     24                     getMemoryUsage().getUsage()
     25             });
     26     if (isLazyDispatch() && !force) {
     27         // Only page in the minimum number of messages which can be
     28         // dispatched immediately.
     29         toPageIn = Math.min(getConsumerMessageCountBeforeFull(), toPageIn);
     30     }
     31     if (toPageIn > 0 && (force || (!consumers.isEmpty() && pagedInPendingSize < getMaxPageSize()))) {
     32         int count = 0;
     33         result = new ArrayList<QueueMessageReference>(toPageIn);
     34         messagesLock.writeLock().lock();
     35         try {
     36             try {
     37                 messages.setMaxBatchSize(toPageIn);
     38                 messages.reset();
     39                 while (messages.hasNext() && count < toPageIn) {
     40                     MessageReference node = messages.next();
     41                     messages.remove();
     42 
     43                     QueueMessageReference ref = createMessageReference(node.getMessage());
     44                     if (processExpired && ref.isExpired()) {
     45                         if (broker.isExpired(ref)) {
     46                             messageExpired(createConnectionContext(), ref);
     47                         } else {
     48                             ref.decrementReferenceCount();
     49                         }
     50                     } else {
     51                         // 添加QueueMessageReference到result中
     52                         result.add(ref);
     53                         count++;
     54                     }
     55                 }
     56             } finally {
     57                 messages.release();
     58             }
     59         } finally {
     60             messagesLock.writeLock().unlock();
     61         }
     62         // Only add new messages, not already pagedIn to avoid multiple
     63         // dispatch attempts
     64         pagedInMessagesLock.writeLock().lock();
     65         try {
     66             if(isPrioritizedMessages()) {
     67                 resultList = new PrioritizedPendingList();
     68             } else {
     69                 resultList = new OrderedPendingList();
     70             }
     71             for (QueueMessageReference ref : result) {
     72                 if (!pagedInMessages.contains(ref)) {
     73                     //分别添加QueueMessageReference到 pagedInMessages 和 resultList
     74                     //resultList作为返回值,直接传递给doDispatch(PendingList list),
     75                     //在doDispatch中,分发给消费者后,就会从 resultList 中删除,
     76                     pagedInMessages.addMessageLast(ref);
     77                     resultList.addMessageLast(ref);
     78                 } else {
     79                     ref.decrementReferenceCount();
     80                     // store should have trapped duplicate in it's index, also cursor audit
     81                     // we need to remove the duplicate from the store in the knowledge that the original message may be inflight
     82                     // note: jdbc store will not trap unacked messages as a duplicate b/c it gives each message a unique sequence id
     83                     LOG.warn("{}, duplicate message {} paged in, is cursor audit disabled? Removing from store and redirecting to dlq", this, ref.getMessage());
     84                     if (store != null) {
     85                         ConnectionContext connectionContext = createConnectionContext();
     86                         store.removeMessage(connectionContext, new MessageAck(ref.getMessage(), MessageAck.POSION_ACK_TYPE, 1));
     87                         broker.getRoot().sendToDeadLetterQueue(connectionContext, ref.getMessage(), null, new Throwable("duplicate paged in from store for " + destination));
     88                     }
     89                 }
     90             }
     91         } finally {
     92             pagedInMessagesLock.writeLock().unlock();
     93         }
     94     } else {
     95         // Avoid return null list, if condition is not validated
     96         resultList = new OrderedPendingList();
     97     }
     98 
     99     return resultList;
    100 }
    101 
    102 //分发消息
    103 private void doDispatch(PendingList list) throws Exception {
    104     boolean doWakeUp = false;
    105 
    106     pagedInPendingDispatchLock.writeLock().lock();
    107     try {
    108         //存在需要重新发送的消息
    109         if (!redeliveredWaitingDispatch.isEmpty()) {
    110             // Try first to dispatch redelivered messages to keep an
    111             // proper order
    112             redeliveredWaitingDispatch = doActualDispatch(redeliveredWaitingDispatch);
    113         }
    114         //存在没有分发的分页消息
    115         if (!pagedInPendingDispatch.isEmpty()) {
    116             // Next dispatch anything that had not been
    117             // dispatched before.
    118             pagedInPendingDispatch = doActualDispatch(pagedInPendingDispatch);
    119         }
    120         // and now see if we can dispatch the new stuff.. and append to
    121         // the pending
    122         // list anything that does not actually get dispatched.
    123         if (list != null && !list.isEmpty()) {
    124             if (pagedInPendingDispatch.isEmpty()) {
    125                 //doActualDispatch进行实际的分发消息:
    126                 //分发给消费者的消息,会从list中删除,list中保存剩下的消息,doActualDispatch返回list
    127                 pagedInPendingDispatch.addAll(doActualDispatch(list));
    128             } else {
    129                 for (MessageReference qmr : list) {
    130                     if (!pagedInPendingDispatch.contains(qmr)) {
    131                         pagedInPendingDispatch.addMessageLast(qmr);
    132                     }
    133                 }
    134                 doWakeUp = true;
    135             }
    136         }
    137     } finally {
    138         pagedInPendingDispatchLock.writeLock().unlock();
    139     }
    140 
    141     if (doWakeUp) {
    142         // avoid lock order contention
    143         asyncWakeup();
    144     }
    145 }
    146 
    147 // 实际分发消息
    148 private PendingList doActualDispatch(PendingList list) throws Exception {
    149     List<Subscription> consumers;
    150     consumersLock.writeLock().lock();
    151 
    152     try {
    153         if (this.consumers.isEmpty()) {
    154             // slave dispatch happens in processDispatchNotification
    155             return list;
    156         }
    157         consumers = new ArrayList<Subscription>(this.consumers);
    158     } finally {
    159         consumersLock.writeLock().unlock();
    160     }
    161 
    162     Set<Subscription> fullConsumers = new HashSet<Subscription>(this.consumers.size());
    163 
    164     for (Iterator<MessageReference> iterator = list.iterator(); iterator.hasNext();) {
    165 
    166         MessageReference node = iterator.next();
    167         Subscription target = null;
    168         for (Subscription s : consumers) {
    169             if (s instanceof QueueBrowserSubscription) {
    170                 continue;
    171             }
    172             if (!fullConsumers.contains(s)) {
    173                 if (!s.isFull()) {
    174                     if (dispatchSelector.canSelect(s, node) && assignMessageGroup(s, (QueueMessageReference)node) && !((QueueMessageReference) node).isAcked() ) {
    175                         // Dispatch it.
    176                         s.add(node);
    177                         LOG.trace("assigned {} to consumer {}", node.getMessageId(), s.getConsumerInfo().getConsumerId());
    178                         //从list中删除
    179                         iterator.remove();
    180                         target = s;
    181                         break;
    182                     }
    183                 } else {
    184                     // no further dispatch of list to a full consumer to
    185                     // avoid out of order message receipt
    186                     fullConsumers.add(s);
    187                     LOG.trace("Subscription full {}", s);
    188                 }
    189             }
    190         }
    191 
    192         if (target == null && node.isDropped()) {
    193             iterator.remove();
    194         }
    195 
    196         // return if there are no consumers or all consumers are full
    197         if (target == null && consumers.size() == fullConsumers.size()) {
    198             return list;
    199         }
    200 
    201         // If it got dispatched, rotate the consumer list to get round robin
    202         // distribution.
    203         if (target != null && !strictOrderDispatch && consumers.size() > 1
    204                 && !dispatchSelector.isExclusiveConsumer(target)) {
    205             consumersLock.writeLock().lock();
    206             try {
    207                 if (removeFromConsumerList(target)) {
    208                     addToConsumerList(target);
    209                     consumers = new ArrayList<Subscription>(this.consumers);
    210                 }
    211             } finally {
    212                 consumersLock.writeLock().unlock();
    213             }
    214         }
    215     }
    216 
    217     return list;
    218 }


     

  • 相关阅读:
    CCS的一些问题
    SignalTapII新特性Storage Qualification
    信号发生器输出幅值与输出阻抗的关系
    关于print函数的一些细节问题探讨
    hp3020 打印机驱动完全卸载方法
    【转】Ruby Selenium 测试
    [nodejs]CoffeeScript里实现Mixin
    [Ruby]ARGF的使用
    【Groovy】使用Maven集成Groovy代码
    [nodejs]optimist库
  • 原文地址:https://www.cnblogs.com/allenwas3/p/8665199.html
Copyright © 2020-2023  润新知