All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.rocketmq.client.impl.consumer.ProcessQueue Maven / Gradle / Ivy

There is a newer version: 3.6.2.Final
Show newest version
/**
 * Copyright (C) 2010-2013 Alibaba Group Holding Limited
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.rocketmq.client.impl.consumer; import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; import com.alibaba.rocketmq.client.log.ClientLogger; import com.alibaba.rocketmq.common.message.MessageAccessor; import com.alibaba.rocketmq.common.message.MessageConst; import com.alibaba.rocketmq.common.message.MessageExt; import com.alibaba.rocketmq.common.protocol.body.ProcessQueueInfo; import org.slf4j.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Queue consumption snapshot * * @author shijia.wxr * @since 2013-7-24 */ public class ProcessQueue { public final static long RebalanceLockMaxLiveTime = Long.parseLong(System.getProperty("rocketmq.client.rebalance.lockMaxLiveTime", "30000")); public final static long RebalanceLockInterval = Long.parseLong(System.getProperty("rocketmq.client.rebalance.lockInterval", "20000")); private final static long PullMaxIdleTime = Long.parseLong(System.getProperty("rocketmq.client.pull.pullMaxIdleTime", "120000")); private final Logger log = ClientLogger.getLog(); private final ReadWriteLock lockTreeMap = new ReentrantReadWriteLock(); private final TreeMap msgTreeMap = new TreeMap(); private final AtomicLong msgCount = new AtomicLong(); private final Lock lockConsume = new ReentrantLock(); private final TreeMap msgTreeMapTemp = new TreeMap(); private final AtomicLong tryUnlockTimes = new AtomicLong(0); private volatile long queueOffsetMax = 0L; private volatile boolean dropped = false; private volatile long lastPullTimestamp = System.currentTimeMillis(); private volatile long lastConsumeTimestamp = System.currentTimeMillis(); private volatile boolean locked = false; private volatile long lastLockTimestamp = System.currentTimeMillis(); private volatile boolean consuming = false; private volatile long msgAccCnt = 0; /** * 一条消息消费的超时时间(默认:10分钟) */ private long consumeTimeout = 10 * 60 * 1000; public boolean isLockExpired() { boolean result = (System.currentTimeMillis() - this.lastLockTimestamp) > RebalanceLockMaxLiveTime; return result; } public boolean isPullExpired() { boolean result = (System.currentTimeMillis() - this.lastPullTimestamp) > PullMaxIdleTime; return result; } /** * 检查缓冲队列中是否有过期的消息,每次最多检查32条消息. * * @param pushConsumer */ public void cleanExpiredMsg(DefaultMQPushConsumer pushConsumer) { int loop = msgTreeMap.size() < 16 ? msgTreeMap.size() : 16; for (int i = 0; i < loop; i++) { MessageExt msg = null; try { this.lockTreeMap.readLock().lockInterruptibly(); try { if (!msgTreeMap.isEmpty() && System.currentTimeMillis() - Long.valueOf(MessageAccessor.getConsumeStartTimeStamp(msgTreeMap.firstEntry().getValue())) > consumeTimeout) { msg = msgTreeMap.firstEntry().getValue(); } else { // 不再有过期的消息,退出检查 break; } } finally { this.lockTreeMap.readLock().unlock(); } } catch (InterruptedException e) { log.error("getExpiredMsg exception", e); } try { // 过期的消息进入重试队列 pushConsumer.sendMessageBack(msg, 0); try { this.lockTreeMap.writeLock().lockInterruptibly(); try { if (!msgTreeMap.isEmpty() && msg.getQueueOffset() == msgTreeMap.firstKey()) { try { msgTreeMap.remove(msgTreeMap.firstKey()); } catch (Exception e) { log.error("send expired msg exception", e); } } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("getExpiredMsg exception", e); } } catch (Exception e) { log.error("send expired msg exception", e); } } } public boolean putMessage(final List msgs) { boolean dispatchToConsume = false; try { this.lockTreeMap.writeLock().lockInterruptibly(); try { int validMsgCnt = 0; for (MessageExt msg : msgs) { MessageExt old = msgTreeMap.put(msg.getQueueOffset(), msg); if (null == old) { validMsgCnt++; this.queueOffsetMax = msg.getQueueOffset(); } } msgCount.addAndGet(validMsgCnt); if (!msgTreeMap.isEmpty() && !this.consuming) { dispatchToConsume = true; this.consuming = true; } if (!msgs.isEmpty()) { MessageExt messageExt = msgs.get(msgs.size() - 1); String property = messageExt.getProperty(MessageConst.PROPERTY_MAX_OFFSET); if (property != null) { long accTotal = Long.parseLong(property) - messageExt.getQueueOffset(); if (accTotal > 0) { this.msgAccCnt = accTotal; } } } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("putMessage exception", e); } return dispatchToConsume; } public long getMaxSpan() { try { this.lockTreeMap.readLock().lockInterruptibly(); try { if (!this.msgTreeMap.isEmpty()) { return this.msgTreeMap.lastKey() - this.msgTreeMap.firstKey(); } } finally { this.lockTreeMap.readLock().unlock(); } } catch (InterruptedException e) { log.error("getMaxSpan exception", e); } return 0; } public long removeMessage(final List msgs) { long result = -1; final long now = System.currentTimeMillis(); try { this.lockTreeMap.writeLock().lockInterruptibly(); this.lastConsumeTimestamp = now; try { if (!msgTreeMap.isEmpty()) { result = this.queueOffsetMax + 1; int removedCnt = 0; for (MessageExt msg : msgs) { MessageExt prev = msgTreeMap.remove(msg.getQueueOffset()); if (prev != null) { removedCnt--; } } msgCount.addAndGet(removedCnt); if (!msgTreeMap.isEmpty()) { result = msgTreeMap.firstKey(); } } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (Throwable t) { log.error("removeMessage exception", t); } return result; } public TreeMap getMsgTreeMap() { return msgTreeMap; } public AtomicLong getMsgCount() { return msgCount; } public boolean isDropped() { return dropped; } public void setDropped(boolean dropped) { this.dropped = dropped; } public boolean isLocked() { return locked; } public void setLocked(boolean locked) { this.locked = locked; } public void rollback() { try { this.lockTreeMap.writeLock().lockInterruptibly(); try { this.msgTreeMap.putAll(this.msgTreeMapTemp); this.msgTreeMapTemp.clear(); } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("rollback exception", e); } } public long commit() { try { this.lockTreeMap.writeLock().lockInterruptibly(); try { Long offset = this.msgTreeMapTemp.lastKey(); msgCount.addAndGet(this.msgTreeMapTemp.size() * (-1)); this.msgTreeMapTemp.clear(); if (offset != null) { return offset + 1; } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("commit exception", e); } return -1; } public void makeMessageToCosumeAgain(List msgs) { try { this.lockTreeMap.writeLock().lockInterruptibly(); try { for (MessageExt msg : msgs) { this.msgTreeMapTemp.remove(msg.getQueueOffset()); this.msgTreeMap.put(msg.getQueueOffset(), msg); } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("makeMessageToCosumeAgain exception", e); } } public List takeMessags(final int batchSize) { List result = new ArrayList(batchSize); final long now = System.currentTimeMillis(); try { this.lockTreeMap.writeLock().lockInterruptibly(); this.lastConsumeTimestamp = now; try { if (!this.msgTreeMap.isEmpty()) { for (int i = 0; i < batchSize; i++) { Map.Entry entry = this.msgTreeMap.pollFirstEntry(); if (entry != null) { result.add(entry.getValue()); msgTreeMapTemp.put(entry.getKey(), entry.getValue()); } else { break; } } } if (result.isEmpty()) { consuming = false; } } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("take Messages exception", e); } return result; } public boolean hasTempMessage() { try { this.lockTreeMap.readLock().lockInterruptibly(); try { return !this.msgTreeMap.isEmpty(); } finally { this.lockTreeMap.readLock().unlock(); } } catch (InterruptedException e) { } return true; } public void clear() { try { this.lockTreeMap.writeLock().lockInterruptibly(); try { this.msgTreeMap.clear(); this.msgTreeMapTemp.clear(); this.msgCount.set(0); this.queueOffsetMax = 0L; } finally { this.lockTreeMap.writeLock().unlock(); } } catch (InterruptedException e) { log.error("rollback exception", e); } } public long getLastLockTimestamp() { return lastLockTimestamp; } public void setLastLockTimestamp(long lastLockTimestamp) { this.lastLockTimestamp = lastLockTimestamp; } public Lock getLockConsume() { return lockConsume; } public long getLastPullTimestamp() { return lastPullTimestamp; } public void setLastPullTimestamp(long lastPullTimestamp) { this.lastPullTimestamp = lastPullTimestamp; } public long getMsgAccCnt() { return msgAccCnt; } public void setMsgAccCnt(long msgAccCnt) { this.msgAccCnt = msgAccCnt; } public long getTryUnlockTimes() { return this.tryUnlockTimes.get(); } public void incTryUnlockTimes() { this.tryUnlockTimes.incrementAndGet(); } public void fillProcessQueueInfo(final ProcessQueueInfo info) { try { this.lockTreeMap.readLock().lockInterruptibly(); if (!this.msgTreeMap.isEmpty()) { info.setCachedMsgMinOffset(this.msgTreeMap.firstKey()); info.setCachedMsgMaxOffset(this.msgTreeMap.lastKey()); info.setCachedMsgCount(this.msgTreeMap.size()); } if (!this.msgTreeMapTemp.isEmpty()) { info.setTransactionMsgMinOffset(this.msgTreeMapTemp.firstKey()); info.setTransactionMsgMaxOffset(this.msgTreeMapTemp.lastKey()); info.setTransactionMsgCount(this.msgTreeMapTemp.size()); } info.setLocked(this.locked); info.setTryUnlockTimes(this.tryUnlockTimes.get()); info.setLastLockTimestamp(this.lastLockTimestamp); info.setDroped(this.dropped); info.setLastPullTimestamp(this.lastPullTimestamp); info.setLastConsumeTimestamp(this.lastConsumeTimestamp); } catch (Exception e) { } finally { this.lockTreeMap.readLock().unlock(); } } public long getLastConsumeTimestamp() { return lastConsumeTimestamp; } public void setLastConsumeTimestamp(long lastConsumeTimestamp) { this.lastConsumeTimestamp = lastConsumeTimestamp; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy