blob: 1c4fd2301f4fd63a1835694c01f6eb4ff148b71a [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 "RemoteBrokerOffsetStore.h"
#include "MQClientFactory.h"
#include "ScopedLock.h"
#include "MQClientException.h"
#include "CommandCustomHeader.h"
#include "MQClientAPIImpl.h"
namespace rmq
{
RemoteBrokerOffsetStore::RemoteBrokerOffsetStore(MQClientFactory* pMQClientFactory, const std::string& groupName)
{
m_pMQClientFactory = pMQClientFactory;
m_groupName = groupName;
}
void RemoteBrokerOffsetStore::load()
{
}
void RemoteBrokerOffsetStore::updateOffset(const MessageQueue& mq, long long offset, bool increaseOnly)
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_tableMutex);
typeof(m_offsetTable.begin()) it = m_offsetTable.find(mq);
if (it == m_offsetTable.end())
{
m_offsetTable[mq] = offset;
it = m_offsetTable.find(mq);
}
kpr::AtomicLong& offsetOld = it->second;
if (increaseOnly)
{
MixAll::compareAndIncreaseOnly(offsetOld, offset);
}
else
{
offsetOld.set(offset);
}
}
long long RemoteBrokerOffsetStore::readOffset(const MessageQueue& mq, ReadOffsetType type)
{
RMQ_DEBUG("readOffset, MQ:%s, type:%d", mq.toString().c_str(), type);
switch (type)
{
case MEMORY_FIRST_THEN_STORE:
case READ_FROM_MEMORY:
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_tableMutex);
typeof(m_offsetTable.begin()) it = m_offsetTable.find(mq);
if (it != m_offsetTable.end())
{
return it->second.get();
}
else if (READ_FROM_MEMORY == type)
{
RMQ_DEBUG("No offset in memory, MQ:%s", mq.toString().c_str());
return -1;
}
}
case READ_FROM_STORE:
{
try
{
long long brokerOffset = this->fetchConsumeOffsetFromBroker(mq);
RMQ_DEBUG("fetchConsumeOffsetFromBroker, MQ:%s, brokerOffset:%lld",
mq.toString().c_str(), brokerOffset);
if (brokerOffset >= 0)
{
this->updateOffset(mq, brokerOffset, false);
}
return brokerOffset;
}
// No offset in broker
catch (const MQBrokerException& e)
{
RMQ_WARN("No offset in broker, MQ:%s, exception:%s", mq.toString().c_str(), e.what());
return -1;
}
catch (const std::exception& e)
{
RMQ_ERROR("fetchConsumeOffsetFromBroker exception, MQ:%s, msg:%s",
mq.toString().c_str(), e.what());
return -2;
}
catch (...)
{
RMQ_ERROR("fetchConsumeOffsetFromBroker unknow exception, MQ:%s",
mq.toString().c_str());
return -2;
}
}
default:
break;
}
return -1;
}
void RemoteBrokerOffsetStore::persistAll(std::set<MessageQueue>& mqs)
{
if (mqs.empty())
{
return;
}
std::set<MessageQueue> unusedMQ;
long long times = m_storeTimesTotal.fetchAndAdd(1);
kpr::ScopedRLock<kpr::RWMutex> lock(m_tableMutex);
for (typeof(m_offsetTable.begin()) it = m_offsetTable.begin();
it != m_offsetTable.end(); it++)
{
MessageQueue mq = it->first;
kpr::AtomicLong& offset = it->second;
if (mqs.find(mq) != mqs.end())
{
try
{
this->updateConsumeOffsetToBroker(mq, offset.get());
if ((times % 12) == 0)
{
RMQ_INFO("updateConsumeOffsetToBroker, Group: {%s} ClientId: {%s} mq:{%s} offset {%llu}",
m_groupName.c_str(),
m_pMQClientFactory->getClientId().c_str(),
mq.toString().c_str(),
offset.get());
}
}
catch (...)
{
RMQ_ERROR("updateConsumeOffsetToBroker exception, mq=%s", mq.toString().c_str());
}
}
else
{
unusedMQ.insert(mq);
}
}
if (!unusedMQ.empty())
{
for (typeof(unusedMQ.begin()) it = unusedMQ.begin(); it != unusedMQ.end(); it++)
{
m_offsetTable.erase(*it);
RMQ_INFO("remove unused mq, %s, %s", it->toString().c_str(), m_groupName.c_str());
}
}
}
void RemoteBrokerOffsetStore::persist(const MessageQueue& mq)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_tableMutex);
typeof(m_offsetTable.begin()) it = m_offsetTable.find(mq);
if (it != m_offsetTable.end())
{
try
{
this->updateConsumeOffsetToBroker(mq, it->second.get());
RMQ_DEBUG("updateConsumeOffsetToBroker ok, mq=%s, offset=%lld", mq.toString().c_str(), it->second.get());
}
catch (...)
{
RMQ_ERROR("updateConsumeOffsetToBroker exception, mq=%s", mq.toString().c_str());
}
}
}
void RemoteBrokerOffsetStore::removeOffset(const MessageQueue& mq)
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_tableMutex);
m_offsetTable.erase(mq);
RMQ_INFO("remove unnecessary messageQueue offset. mq=%s, offsetTableSize=%u",
mq.toString().c_str(), (unsigned)m_offsetTable.size());
}
std::map<MessageQueue, long long> RemoteBrokerOffsetStore::cloneOffsetTable(const std::string& topic)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_tableMutex);
std::map<MessageQueue, long long> cloneOffsetTable;
RMQ_FOR_EACH(m_offsetTable, it)
{
MessageQueue mq = it->first;
kpr::AtomicLong& offset = it->second;
if (topic == mq.getTopic())
{
cloneOffsetTable[mq] = offset.get();
}
}
return cloneOffsetTable;
}
void RemoteBrokerOffsetStore::updateConsumeOffsetToBroker(const MessageQueue& mq, long long offset)
{
FindBrokerResult findBrokerResult = m_pMQClientFactory->findBrokerAddressInAdmin(mq.getBrokerName());
if (findBrokerResult.brokerAddr.empty())
{
m_pMQClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic());
findBrokerResult = m_pMQClientFactory->findBrokerAddressInAdmin(mq.getBrokerName());
}
if (!findBrokerResult.brokerAddr.empty())
{
UpdateConsumerOffsetRequestHeader* requestHeader = new UpdateConsumerOffsetRequestHeader();
requestHeader->topic = mq.getTopic();
requestHeader->consumerGroup = this->m_groupName;
requestHeader->queueId = mq.getQueueId();
requestHeader->commitOffset = offset;
m_pMQClientFactory->getMQClientAPIImpl()->updateConsumerOffsetOneway(
findBrokerResult.brokerAddr, requestHeader, 1000 * 5);
}
else
{
THROW_MQEXCEPTION(MQClientException, "The broker[" + mq.getBrokerName() + "] not exist", -1);
}
}
long long RemoteBrokerOffsetStore::fetchConsumeOffsetFromBroker(const MessageQueue& mq)
{
FindBrokerResult findBrokerResult = m_pMQClientFactory->findBrokerAddressInAdmin(mq.getBrokerName());
if (findBrokerResult.brokerAddr.empty())
{
// TODO Here may be heavily overhead for Name Server,need tuning
m_pMQClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic());
findBrokerResult = m_pMQClientFactory->findBrokerAddressInAdmin(mq.getBrokerName());
}
if (!findBrokerResult.brokerAddr.empty())
{
QueryConsumerOffsetRequestHeader* requestHeader = new QueryConsumerOffsetRequestHeader();
requestHeader->topic = mq.getTopic();
requestHeader->consumerGroup = this->m_groupName;
requestHeader->queueId = mq.getQueueId();
return m_pMQClientFactory->getMQClientAPIImpl()->queryConsumerOffset(
findBrokerResult.brokerAddr, requestHeader, 1000 * 5);
}
else
{
THROW_MQEXCEPTION(MQClientException, "The broker[" + mq.getBrokerName() + "] not exist", -1);
}
}
}