blob: f90e502121cbe8004525db2634d095e34bab968a [file]
/**
* Copyright (C) 2013 kangliqiang ,kangliq@163.com
*
* 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.
*/
#include "ProcessQueue.h"
#include "MessageExt.h"
#include "KPRUtil.h"
#include "UtilAll.h"
#include "ScopedLock.h"
#include "DefaultMQPushConsumer.h"
#include "DefaultMQPushConsumerImpl.h"
namespace rmq
{
ProcessQueue::ProcessQueue()
{
m_lastPullTimestamp = KPRUtil::GetCurrentTimeMillis();
m_lastConsumeTimestamp = KPRUtil::GetCurrentTimeMillis();
m_queueOffsetMax = 0L;
m_msgCount = 0;
m_dropped = false;
m_locked = false;
m_lastLockTimestamp = KPRUtil::GetCurrentTimeMillis();
m_consuming = false;
}
bool ProcessQueue::isLockExpired()
{
bool result = (KPRUtil::GetCurrentTimeMillis() - m_lastLockTimestamp) >
s_RebalanceLockMaxLiveTime;
return result;
}
bool ProcessQueue::isPullExpired()
{
bool result = (KPRUtil::GetCurrentTimeMillis() - m_lastPullTimestamp) >
s_PullMaxIdleTime;
return result;
}
void ProcessQueue::cleanExpiredMsg(DefaultMQPushConsumer* pPushConsumer)
{
if (pPushConsumer->getDefaultMQPushConsumerImpl()->isConsumeOrderly())
{
return;
}
long long now = KPRUtil::GetCurrentTimeMillis();
int loop = m_msgTreeMap.size() < 16 ? m_msgTreeMap.size() : 16;
for (int i = 0; i < loop; i++)
{
MessageExt* msg = NULL;
try
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_lockTreeMap);
if (m_msgTreeMap.empty())
{
return;
}
MessageExt* firstMsg = m_msgTreeMap.begin()->second;
long long startTimestamp = UtilAll::str2ll(firstMsg->getProperty(Message::PROPERTY_CONSUME_START_TIMESTAMP).c_str());
if (startTimestamp > 0 && (now - startTimestamp) > (pPushConsumer->getConsumeTimeout() * 60 * 1000))
{
msg = firstMsg;
}
else
{
return;
}
}
catch (...)
{
RMQ_ERROR("getExpiredMsg exception");
}
try
{
pPushConsumer->sendMessageBack((*msg), 3);
RMQ_WARN("send expire msg back. topic={%s}, msgId={%s}, storeHost={%s}, queueId={%d}, queueOffset={%lld}",
msg->getTopic().c_str(), msg->getMsgId().c_str(), msg->getStoreHostString().c_str(),
msg->getQueueId(), msg->getQueueOffset());
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
if (!m_msgTreeMap.empty() && msg->getQueueOffset() == m_msgTreeMap.begin()->first)
{
try
{
m_msgTreeMap.erase(m_msgTreeMap.begin());
m_msgCount -= 1;
// if free msg, may be coredump
//delete msg;
}
catch (...)
{
RMQ_ERROR("send expired msg exception");
}
}
}
catch (...)
{
RMQ_ERROR("delExpiredMsg exception");
}
}
catch (...)
{
RMQ_ERROR("send expired msg exception");
}
}
}
bool ProcessQueue::putMessage(const std::list<MessageExt *> &msgs)
{
bool dispathToConsume = false;
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
int validMsgCnt = 0;
std::list<MessageExt *>::const_iterator it = msgs.begin();
for (; it != msgs.end(); it++)
{
MessageExt *msg = (*it);
if (m_msgTreeMap.find(msg->getQueueOffset()) == m_msgTreeMap.end())
{
validMsgCnt++;
m_queueOffsetMax = msg->getQueueOffset();
}
m_msgTreeMap[msg->getQueueOffset()] = msg;
}
m_msgCount += validMsgCnt;
if (!m_msgTreeMap.empty() && !m_consuming)
{
dispathToConsume = true;
m_consuming = true;
}
}
catch (...)
{
RMQ_ERROR("putMessage exception");
}
return dispathToConsume;
}
long long ProcessQueue::getMaxSpan()
{
try
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_lockTreeMap);
if (!m_msgTreeMap.empty())
{
std::map<long long, MessageExt *>::iterator it1 = m_msgTreeMap.begin();
std::map<long long, MessageExt *>::iterator it2 = m_msgTreeMap.end();
it2--;
return it2->first - it1->first;
}
}
catch (...)
{
RMQ_ERROR("getMaxSpan exception");
}
return 0;
}
long long ProcessQueue::removeMessage(std::list<MessageExt *> &msgs)
{
long long result = -1;
unsigned long long now = KPRUtil::GetCurrentTimeMillis();
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
m_lastConsumeTimestamp = now;
if (!m_msgTreeMap.empty())
{
result = m_queueOffsetMax + 1;
int removedCnt = 0;
std::list<MessageExt *>::iterator it = msgs.begin();
for (; it != msgs.end();)
{
MessageExt *msg = (*it);
if (m_msgTreeMap.find(msg->getQueueOffset()) != m_msgTreeMap.end())
{
removedCnt++;
}
m_msgTreeMap.erase(msg->getQueueOffset());
//TODO delete message?
it = msgs.erase(it);
delete msg;
}
m_msgCount -= removedCnt;
if (!m_msgTreeMap.empty())
{
std::map<long long, MessageExt *>::iterator it = m_msgTreeMap.begin();
result = it->first;
}
}
}
catch (...)
{
RMQ_ERROR("removeMessage exception");
}
return result;
}
void ProcessQueue::clear()
{
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
m_msgTreeMap.clear();
m_msgTreeMapTemp.clear();
m_msgCount.set(0);
m_queueOffsetMax = 0;
}
catch (...)
{
RMQ_ERROR("clear exception");
}
return;
}
std::map<long long, MessageExt *> ProcessQueue::getMsgTreeMap()
{
return m_msgTreeMap;
}
kpr::AtomicInteger ProcessQueue::getMsgCount()
{
return m_msgCount;
}
bool ProcessQueue::isDropped()
{
return m_dropped;
}
void ProcessQueue::setDropped(bool dropped)
{
m_dropped = dropped;
}
unsigned long long ProcessQueue::getLastPullTimestamp()
{
return m_lastPullTimestamp;
}
void ProcessQueue::setLastPullTimestamp(unsigned long long lastPullTimestamp)
{
m_lastPullTimestamp = lastPullTimestamp;
}
unsigned long long ProcessQueue::getLastConsumeTimestamp()
{
return m_lastConsumeTimestamp;
}
void ProcessQueue::setLastConsumeTimestamp(unsigned long long
lastConsumeTimestamp)
{
m_lastConsumeTimestamp = lastConsumeTimestamp;
}
/**
* ========================================================================
*/
kpr::Mutex &ProcessQueue::getLockConsume()
{
return m_lockConsume;
}
void ProcessQueue::setLocked(bool locked)
{
m_locked = locked;
}
bool ProcessQueue::isLocked()
{
return m_locked;
}
long long ProcessQueue::getTryUnlockTimes()
{
return m_tryUnlockTimes.get();
}
void ProcessQueue::incTryUnlockTimes()
{
m_tryUnlockTimes++;
}
void ProcessQueue::rollback()
{
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
m_msgTreeMap = m_msgTreeMapTemp;
m_msgTreeMapTemp.clear();
}
catch (...)
{
RMQ_ERROR("rollback exception");
}
}
long long ProcessQueue::commit()
{
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
if (!m_msgTreeMapTemp.empty())
{
std::map<long long, MessageExt *>::iterator it = m_msgTreeMapTemp.end();
it--;
long long offset = it->first;
m_msgCount -= m_msgTreeMapTemp.size();
m_msgTreeMapTemp.clear();
return offset + 1;
}
}
catch (...)
{
RMQ_ERROR("commit exception");
}
return -1;
}
void ProcessQueue::makeMessageToCosumeAgain(const std::list<MessageExt *> &msgs)
{
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
std::list<MessageExt *>::const_iterator it = msgs.begin();
for (; it != msgs.end(); it++)
{
MessageExt *msg = (*it);
m_msgTreeMapTemp.erase(msg->getQueueOffset());
m_msgTreeMap[msg->getQueueOffset()] = msg;
}
}
catch (...)
{
RMQ_ERROR("makeMessageToCosumeAgain exception");
}
}
std::list<MessageExt *> ProcessQueue::takeMessages(int batchSize)
{
std::list<MessageExt *> result;
unsigned long long now = KPRUtil::GetCurrentTimeMillis();
try
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_lockTreeMap);
m_lastConsumeTimestamp = now;
if (!m_msgTreeMap.empty())
{
for (int i = 0; i < batchSize; i++)
{
std::map<long long, MessageExt *>::iterator it = m_msgTreeMap.begin();
if (it != m_msgTreeMap.end())
{
result.push_back(it->second);
m_msgTreeMapTemp[it->first] = it->second;
m_msgTreeMap.erase(it);
}
else
{
break;
}
}
if (result.empty())
{
m_consuming = false;
}
}
}
catch (...)
{
RMQ_ERROR("takeMessags exception");
}
return result;
}
long long ProcessQueue::getLastLockTimestamp()
{
return m_lastLockTimestamp;
}
void ProcessQueue::setLastLockTimestamp(long long lastLockTimestamp)
{
m_lastLockTimestamp = lastLockTimestamp;
}
}