分页:即获取部分数据,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));
}
 private PendingList doPageInForDispatch(boolean force, boolean processExpired) throws Exception {
List<QueueMessageReference> result = null;
PendingList resultList = null; // 根据maxPageSize和message cursor中的大小,决定需要读取的消息数量
int toPageIn = Math.min(getMaxPageSize(), messages.size());
int pagedInPendingSize = 0;
pagedInPendingDispatchLock.readLock().lock();
try {
pagedInPendingSize = pagedInPendingDispatch.size();
} finally {
pagedInPendingDispatchLock.readLock().unlock();
} LOG.debug("{} toPageIn: {}, Inflight: {}, pagedInMessages.size {}, pagedInPendingDispatch.size {}, enqueueCount: {}, dequeueCount: {}, memUsage:{}",
new Object[]{
destination.getPhysicalName(),
toPageIn,
destinationStatistics.getInflight().getCount(),
pagedInMessages.size(),
pagedInPendingSize,
destinationStatistics.getEnqueues().getCount(),
destinationStatistics.getDequeues().getCount(),
getMemoryUsage().getUsage()
});
if (isLazyDispatch() && !force) {
// Only page in the minimum number of messages which can be
// dispatched immediately.
toPageIn = Math.min(getConsumerMessageCountBeforeFull(), toPageIn);
}
if (toPageIn > 0 && (force || (!consumers.isEmpty() && pagedInPendingSize < getMaxPageSize()))) {
int count = 0;
result = new ArrayList<QueueMessageReference>(toPageIn);
messagesLock.writeLock().lock();
try {
try {
messages.setMaxBatchSize(toPageIn);
messages.reset();
while (messages.hasNext() && count < toPageIn) {
MessageReference node = messages.next();
messages.remove(); QueueMessageReference ref = createMessageReference(node.getMessage());
if (processExpired && ref.isExpired()) {
if (broker.isExpired(ref)) {
messageExpired(createConnectionContext(), ref);
} else {
ref.decrementReferenceCount();
}
} else {
// 添加QueueMessageReference到result中
result.add(ref);
count++;
}
}
} finally {
messages.release();
}
} finally {
messagesLock.writeLock().unlock();
}
// Only add new messages, not already pagedIn to avoid multiple
// dispatch attempts
pagedInMessagesLock.writeLock().lock();
try {
if(isPrioritizedMessages()) {
resultList = new PrioritizedPendingList();
} else {
resultList = new OrderedPendingList();
}
for (QueueMessageReference ref : result) {
if (!pagedInMessages.contains(ref)) {
//分别添加QueueMessageReference到 pagedInMessages 和 resultList
//resultList作为返回值,直接传递给doDispatch(PendingList list),
//在doDispatch中,分发给消费者后,就会从 resultList 中删除,
pagedInMessages.addMessageLast(ref);
resultList.addMessageLast(ref);
} else {
ref.decrementReferenceCount();
// store should have trapped duplicate in it's index, also cursor audit
// we need to remove the duplicate from the store in the knowledge that the original message may be inflight
// note: jdbc store will not trap unacked messages as a duplicate b/c it gives each message a unique sequence id
LOG.warn("{}, duplicate message {} paged in, is cursor audit disabled? Removing from store and redirecting to dlq", this, ref.getMessage());
if (store != null) {
ConnectionContext connectionContext = createConnectionContext();
store.removeMessage(connectionContext, new MessageAck(ref.getMessage(), MessageAck.POSION_ACK_TYPE, 1));
broker.getRoot().sendToDeadLetterQueue(connectionContext, ref.getMessage(), null, new Throwable("duplicate paged in from store for " + destination));
}
}
}
} finally {
pagedInMessagesLock.writeLock().unlock();
}
} else {
// Avoid return null list, if condition is not validated
resultList = new OrderedPendingList();
} return resultList;
} //分发消息
private void doDispatch(PendingList list) throws Exception {
boolean doWakeUp = false; pagedInPendingDispatchLock.writeLock().lock();
try {
//存在需要重新发送的消息
if (!redeliveredWaitingDispatch.isEmpty()) {
// Try first to dispatch redelivered messages to keep an
// proper order
redeliveredWaitingDispatch = doActualDispatch(redeliveredWaitingDispatch);
}
//存在没有分发的分页消息
if (!pagedInPendingDispatch.isEmpty()) {
// Next dispatch anything that had not been
// dispatched before.
pagedInPendingDispatch = doActualDispatch(pagedInPendingDispatch);
}
// and now see if we can dispatch the new stuff.. and append to
// the pending
// list anything that does not actually get dispatched.
if (list != null && !list.isEmpty()) {
if (pagedInPendingDispatch.isEmpty()) {
//doActualDispatch进行实际的分发消息:
//分发给消费者的消息,会从list中删除,list中保存剩下的消息,doActualDispatch返回list
pagedInPendingDispatch.addAll(doActualDispatch(list));
} else {
for (MessageReference qmr : list) {
if (!pagedInPendingDispatch.contains(qmr)) {
pagedInPendingDispatch.addMessageLast(qmr);
}
}
doWakeUp = true;
}
}
} finally {
pagedInPendingDispatchLock.writeLock().unlock();
} if (doWakeUp) {
// avoid lock order contention
asyncWakeup();
}
} // 实际分发消息
private PendingList doActualDispatch(PendingList list) throws Exception {
List<Subscription> consumers;
consumersLock.writeLock().lock(); try {
if (this.consumers.isEmpty()) {
// slave dispatch happens in processDispatchNotification
return list;
}
consumers = new ArrayList<Subscription>(this.consumers);
} finally {
consumersLock.writeLock().unlock();
} Set<Subscription> fullConsumers = new HashSet<Subscription>(this.consumers.size()); for (Iterator<MessageReference> iterator = list.iterator(); iterator.hasNext();) { MessageReference node = iterator.next();
Subscription target = null;
for (Subscription s : consumers) {
if (s instanceof QueueBrowserSubscription) {
continue;
}
if (!fullConsumers.contains(s)) {
if (!s.isFull()) {
if (dispatchSelector.canSelect(s, node) && assignMessageGroup(s, (QueueMessageReference)node) && !((QueueMessageReference) node).isAcked() ) {
// Dispatch it.
s.add(node);
LOG.trace("assigned {} to consumer {}", node.getMessageId(), s.getConsumerInfo().getConsumerId());
//从list中删除
iterator.remove();
target = s;
break;
}
} else {
// no further dispatch of list to a full consumer to
// avoid out of order message receipt
fullConsumers.add(s);
LOG.trace("Subscription full {}", s);
}
}
} if (target == null && node.isDropped()) {
iterator.remove();
} // return if there are no consumers or all consumers are full
if (target == null && consumers.size() == fullConsumers.size()) {
return list;
} // If it got dispatched, rotate the consumer list to get round robin
// distribution.
if (target != null && !strictOrderDispatch && consumers.size() > 1
&& !dispatchSelector.isExclusiveConsumer(target)) {
consumersLock.writeLock().lock();
try {
if (removeFromConsumerList(target)) {
addToConsumerList(target);
consumers = new ArrayList<Subscription>(this.consumers);
}
} finally {
consumersLock.writeLock().unlock();
}
}
} return list;
}

ActiveMQ queue 分页的更多相关文章

  1. ActiveMQ Queue vs Topic vs VirtualTopic

    之前写过一篇文章讨论VirtualTopic,但觉得不够透彻,这里再根据实验结果进行一次横向对比破除模糊和选择困难症. 文章中核心对比要素是:消息副本和负载均衡 Queue的特点和优势 ActiveM ...

  2. ActiveMQ queue和topic,持久订阅和非持久订阅

    消息的 destination 分为 queue 和 topic,而消费者称为 subscriber(订阅者).queue 中的消息只会发送给一个订阅者,而 topic 的消息,会发送给每一个订阅者. ...

  3. ActiveMQ queue 代码示例

    生产者: package com.111.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; impo ...

  4. ActiveMQ Queue示例

    一.Queue 发送 public class JmsSend { public static void main(String[] args) throws JMSException { Conne ...

  5. spring整合activemq发送MQ消息[queue模式]实例

    queue类型消息 pom依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</ ...

  6. Spring整合ActiveMQ及多个Queue消息监听的配置

        消息队列(MQ)越来越火,在java开发的项目也属于比较常见的技术,MQ的相关使用也成java开发人员必备的技能.笔者公司采用的MQ是ActiveMQ,且消息都是用的点对点的模式.本文记录了实 ...

  7. ActiveMQ发消息和收消息

    来自:http://blog.163.com/chengwei_1104/blog/static/53645274201382315625329/ ActiveMQ 是Apache出品,最流行的,能力 ...

  8. ActiveMQ, RabbitMQ和ZeroMQ 选型关注点

    选择MQ时,主要关注的特性,可能就以下几个: 通信模式(是否满足业务场景): ActiveMQ: queue(producer/consumer), topic(publisher/subsriber ...

  9. ActiveMQ:使用Python访问ActiveMQ

    Windows 10家庭中文版,Python 3.6.4,stomp.py 4.1.21 ActiveMQ支持Python访问,提供了基于STOMP协议(端口为61613)的库. ActiveMQ的官 ...

随机推荐

  1. Python深入:Distutils发布Python模块--转载

    https://blog.csdn.net/gqtcgq/article/details/49255995 Distutils可以用来在Python环境中构建和安装额外的模块.新的模块可以是纯Pyth ...

  2. 关于页面的跳转添加参数(比如id啥的)

    最近一些新手老是问我一些关于页面之间的传递跳转,怎么带参数这件事,(比如说一个列表页到详情页面数据是怎么传输的),今个没事就在这说一些! 这里拿列表页面到详情页面来阐述下哈! 首先在列表页,我们通过a ...

  3. CSS垂直居中查询宝典

    一.垂直居中的用处 设计稿需求 当我们抱怨设计反复不定的时候,试着理解一下.每一位开发者也会是一位用户,请多多用'用户'的角色去开发.就比如下面这图,你会更稀饭哪种格式呢? 如果我们使用一个webap ...

  4. 1.0 poi单元格合合并及写入

    最近项目中用到poi生成Excel时,用到了单元格合并,于是参考了http://www.anyrt.com/blog/list/poiexcel.html写的文章,但是其中有些地方不是很清楚,于是自己 ...

  5. django特殊的标签和过滤器

    国际化标签和过滤器 Django还提供了一些模板标签和过滤器,用以控制模板中国际化的每个方面.它们允许对翻译,格式化和时区转换进行粒度控制. 1. i18n 此标签允许在模板中指定可翻译文本.要启用它 ...

  6. ASP.net MVC模式介绍(一)

    一.ASP.NET 支持三种不同的开发模式:Web Pages(Web 页面).MVC(Model View Controller 模型-视图-控制器)表现层.Web Forms(Web 窗体) mv ...

  7. Qt5_当前exe所在路径

    可以通过以下方式来获取: 1. #include <QDir>#include <QDebug> QDir dir; qDebug() << "curre ...

  8. psql常用命令

    cmd命令 pg_ctl --version:查看pgsl版本 pg_ctl -D /xx/pgdata start:启动pgsl数据库 注:必须在环境变量中设置了PGDATA后才能省略-D参数 ,可 ...

  9. MySQL字段拼接Concat

    有时候,从数据库中拿出的数据并不是我们想要的格式,比如,有以下的vendors表 如果,想以 name (location)的格式展现出来,那么就要用到MySQL的Concat了. Concat()拼 ...

  10. 学习笔记49—matlab FDR校正

    matlab自带函数mafdr,当ttest数较多时,可直接用[FDR, Q]=mafdr(P):但是Storey procedure在p值少于1000个时会崩溃,此时应改用BH FDR方法:mafd ...