blob: 2b8208b66a13c37a1bafeb2d3a778fd66d9dabed [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 <math.h>
#include <set>
#include <string>
#include <iostream>
#include <vector>
#include "MQClientFactory.h"
#include "RemoteClientConfig.h"
#include "ClientRemotingProcessor.h"
#include "MQClientAPIImpl.h"
#include "MQAdminImpl.h"
#include "DefaultMQProducer.h"
#include "PullMessageService.h"
#include "RebalanceService.h"
#include "ScopedLock.h"
#include "KPRUtil.h"
#include "DefaultMQProducerImpl.h"
#include "DefaultMQPushConsumerImpl.h"
#include "MQClientException.h"
#include "MQConsumerInner.h"
#include "MQProducerInner.h"
#include "UtilAll.h"
#include "PermName.h"
#include "MQClientManager.h"
#include "ConsumerStatManage.h"
#include "TopicPublishInfo.h"
#include "MQVersion.h"
namespace rmq
{
long MQClientFactory::LockTimeoutMillis = 3000;
MQClientFactory::MQClientFactory(ClientConfig& clientConfig, int factoryIndex, const std::string& clientId)
{
m_clientConfig = clientConfig;
m_factoryIndex = factoryIndex;
m_pRemoteClientConfig = new RemoteClientConfig();
m_pRemoteClientConfig->clientCallbackExecutorThreads = clientConfig.getClientCallbackExecutorThreads();
m_pClientRemotingProcessor = new ClientRemotingProcessor(this);
m_pMQClientAPIImpl = new MQClientAPIImpl(m_clientConfig, *m_pRemoteClientConfig, m_pClientRemotingProcessor);
if (!m_clientConfig.getNamesrvAddr().empty())
{
m_pMQClientAPIImpl->updateNameServerAddressList(m_clientConfig.getNamesrvAddr());
RMQ_INFO("user specified name server address: {%s}", m_clientConfig.getNamesrvAddr().c_str());
}
m_clientId = clientId;
m_pMQAdminImpl = new MQAdminImpl(this);
m_pPullMessageService = new PullMessageService(this);
m_pRebalanceService = new RebalanceService(this);
m_pDefaultMQProducer = new DefaultMQProducer(MixAll::CLIENT_INNER_PRODUCER_GROUP);
m_pDefaultMQProducer->resetClientConfig(clientConfig);
m_bootTimestamp = KPRUtil::GetCurrentTimeMillis();
m_pFetchNameServerAddrTask = new ScheduledTask(this, &MQClientFactory::fetchNameServerAddr);
m_pUpdateTopicRouteInfoFromNameServerTask = new ScheduledTask(this, &MQClientFactory::updateTopicRouteInfoFromNameServerTask);
m_pCleanBrokerTask = new ScheduledTask(this, &MQClientFactory::cleanBroker);
m_pPersistAllConsumerOffsetTask = new ScheduledTask(this, &MQClientFactory::persistAllConsumerOffsetTask);
m_pRecordSnapshotPeriodicallyTask = new ScheduledTask(this, &MQClientFactory::recordSnapshotPeriodicallyTask);
m_pLogStatsPeriodicallyTask = new ScheduledTask(this, &MQClientFactory::logStatsPeriodicallyTask);
m_serviceState = CREATE_JUST;
RMQ_INFO("created a new client Instance, FactoryIndex: {%d} ClinetID: {%s} Config: {%s} Version: {%s}",
m_factoryIndex,
m_clientId.c_str(),
m_clientConfig.toString().c_str(),
MQVersion::getVersionDesc(MQVersion::s_CurrentVersion));
}
MQClientFactory::~MQClientFactory()
{
delete m_pRemoteClientConfig;
delete m_pClientRemotingProcessor;
delete m_pMQClientAPIImpl;
delete m_pMQAdminImpl;
delete m_pPullMessageService;
delete m_pRebalanceService;
delete m_pDefaultMQProducer;
}
void MQClientFactory::start()
{
RMQ_DEBUG("MQClientFactory::start()");
kpr::ScopedLock<kpr::Mutex> lock(m_mutex);
switch (m_serviceState)
{
case CREATE_JUST:
makesureInstanceNameIsOnly(m_clientConfig.getInstanceName());
m_serviceState = START_FAILED;
if (m_clientConfig.getNamesrvAddr().empty())
{
m_clientConfig.setNamesrvAddr(m_pMQClientAPIImpl->fetchNameServerAddr());
}
m_pMQClientAPIImpl->start();
m_timerTaskManager.Init(5, 1000);
startScheduledTask();
m_pPullMessageService->Start();
m_pRebalanceService->Start();
m_pDefaultMQProducer->getDefaultMQProducerImpl()->start(false);
RMQ_INFO("the client factory [%s] start OK", m_clientId.c_str());
m_serviceState = RUNNING;
break;
case RUNNING:
RMQ_WARN("MQClientFactory is already running.");
break;
case SHUTDOWN_ALREADY:
RMQ_ERROR("MQClientFactory should have already been shutted down");
break;
case START_FAILED:
RMQ_ERROR("MQClientFactory started failed.");
THROW_MQEXCEPTION(MQClientException, "The Factory object start failed", -1);
default:
break;
}
}
void MQClientFactory::shutdown()
{
RMQ_DEBUG("MQClientFactory::shutdown()");
// Consumer
if (!m_consumerTable.empty())
{
return;
}
// AdminExt
if (!m_adminExtTable.empty())
{
return;
}
// Producer
if (m_producerTable.size() > 1)
{
return;
}
RMQ_DEBUG("MQClientFactory::shutdown_begin");
{
kpr::ScopedLock<kpr::Mutex> lock(m_mutex);
switch (m_serviceState)
{
case CREATE_JUST:
break;
case RUNNING:
m_pDefaultMQProducer->getDefaultMQProducerImpl()->shutdown(false);
for (int i = 0; i < 6; i++)
{
m_timerTaskManager.UnRegisterTimer(m_scheduledTaskIds[i]);
}
m_timerTaskManager.Stop();
m_pPullMessageService->stop();
m_pPullMessageService->Join();
m_pMQClientAPIImpl->shutdown();
m_pRebalanceService->stop();
m_pRebalanceService->Join();
//closesocket(m_datagramSocket);
MQClientManager::getInstance()->removeClientFactory(m_clientId);
m_serviceState = SHUTDOWN_ALREADY;
break;
case SHUTDOWN_ALREADY:
break;
default:
break;
}
}
}
void MQClientFactory::sendHeartbeatToAllBrokerWithLock()
{
RMQ_DEBUG("TryLock m_lockHeartbeat: %p", &m_lockHeartbeat);
if (m_lockHeartbeat.TryLock())
{
try
{
RMQ_DEBUG("TryLock m_lockHeartbeat ok");
sendHeartbeatToAllBroker();
}
catch (...)
{
RMQ_ERROR("sendHeartbeatToAllBroker exception");
}
m_lockHeartbeat.Unlock();
}
else
{
RMQ_WARN("TryLock heartBeat fail");
}
}
void MQClientFactory::updateTopicRouteInfoFromNameServer()
{
std::set<std::string> topicList;
// Consumer
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
std::set<SubscriptionData> subList = inner->subscriptions();
std::set<SubscriptionData>::iterator it1 = subList.begin();
for (; it1 != subList.end(); it1++)
{
topicList.insert((*it1).getTopic());
}
}
}
// Producer
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_producerTableLock);
std::map<std::string, MQProducerInner*>::iterator it = m_producerTable.begin();
for (; it != m_producerTable.end(); it++)
{
MQProducerInner* inner = it->second;
std::set<std::string> pubList = inner->getPublishTopicList();
topicList.insert(pubList.begin(), pubList.end());
}
}
std::set<std::string>::iterator it2 = topicList.begin();
for (; it2 != topicList.end(); it2++)
{
updateTopicRouteInfoFromNameServer(*it2);
}
}
bool MQClientFactory::updateTopicRouteInfoFromNameServer(const std::string& topic)
{
return updateTopicRouteInfoFromNameServer(topic, false, NULL);
}
bool MQClientFactory::updateTopicRouteInfoFromNameServer(const std::string& topic,
bool isDefault,
DefaultMQProducer* pDefaultMQProducer)
{
RMQ_DEBUG("TryLock m_lockNamesrv: 0x%p, topic: [%s]", &m_lockNamesrv, topic.c_str());
if (m_lockNamesrv.TryLock(MQClientFactory::LockTimeoutMillis))
{
RMQ_DEBUG("TryLock m_lockNamesrv ok");
TopicRouteDataPtr topicRouteData = NULL;
try
{
if (isDefault && pDefaultMQProducer != NULL)
{
topicRouteData =
m_pMQClientAPIImpl->getDefaultTopicRouteInfoFromNameServer(
pDefaultMQProducer->getCreateTopicKey(), 1000 * 3);
if (topicRouteData.ptr() != NULL)
{
std::list<QueueData> dataList = topicRouteData->getQueueDatas();
std::list<QueueData>::iterator it = dataList.begin();
for (; it != dataList.end(); it++)
{
QueueData data = *it;
int queueNums =
std::min<int>(pDefaultMQProducer->getDefaultTopicQueueNums(),
data.readQueueNums);
data.readQueueNums = (queueNums);
data.writeQueueNums = (queueNums);
}
}
}
else
{
topicRouteData =
m_pMQClientAPIImpl->getTopicRouteInfoFromNameServer(topic, 1000 * 3);
}
if (topicRouteData.ptr() != NULL)
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_topicRouteTableLock);
std::map<std::string, TopicRouteData>::iterator it = m_topicRouteTable.find(topic);
bool changed = false;
if (it != m_topicRouteTable.end())
{
changed = topicRouteDataIsChange(it->second, *topicRouteData);
if (!changed)
{
changed = isNeedUpdateTopicRouteInfo(topic);
if (changed)
{
RMQ_INFO("the topic[{%s}] route info changed, old[{%s}] ,new[{%s}]",
topic.c_str(), it->second.toString().c_str(),
topicRouteData->toString().c_str());
}
}
}
else
{
changed = true;
}
if (changed)
{
TopicRouteData cloneTopicRouteData = *topicRouteData;
std::list<BrokerData> dataList = topicRouteData->getBrokerDatas();
std::list<BrokerData>::iterator it = dataList.begin();
for (; it != dataList.end(); it++)
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
m_brokerAddrTable[(*it).brokerName] = (*it).brokerAddrs;
}
{
TopicPublishInfoPtr publishInfo =
topicRouteData2TopicPublishInfo(topic, *topicRouteData);
publishInfo->setHaveTopicRouterInfo(true);
kpr::ScopedRLock<kpr::RWMutex> lock(m_producerTableLock);
std::map<std::string, MQProducerInner*>::iterator it = m_producerTable.begin();
for (; it != m_producerTable.end(); it++)
{
MQProducerInner* impl = it->second;
if (impl)
{
impl->updateTopicPublishInfo(topic, *publishInfo);
}
}
}
{
std::set<MessageQueue>* subscribeInfo =
topicRouteData2TopicSubscribeInfo(topic, *topicRouteData);
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* impl = it->second;
if (impl)
{
impl->updateTopicSubscribeInfo(topic, *subscribeInfo);
}
}
delete subscribeInfo;
}
m_topicRouteTable[topic] = cloneTopicRouteData;
m_lockNamesrv.Unlock();
RMQ_DEBUG("UnLock m_lockNamesrv ok");
RMQ_INFO("topicRouteTable.put[%s] = TopicRouteData[%s]",
topic.c_str(), cloneTopicRouteData.toString().c_str());
return true;
}
}
else
{
//TODO log?
RMQ_WARN("updateTopicRouteInfoFromNameServer, getTopicRouteInfoFromNameServer return null, Topic: {%s}",
topic.c_str());
}
}
catch (const std::exception& e)
{
if (!(topic.find(MixAll::RETRY_GROUP_TOPIC_PREFIX) == 0) && topic != MixAll::DEFAULT_TOPIC)
{
RMQ_WARN("updateTopicRouteInfoFromNameServer Exception: %s", e.what());
}
}
catch (...)
{
RMQ_WARN("updateTopicRouteInfoFromNameServer unknow Exception");
}
m_lockNamesrv.Unlock();
RMQ_DEBUG("UnLock m_lockNamesrv ok");
}
else
{
RMQ_WARN("TryLock m_lockNamesrv timeout %ldms", MQClientFactory::LockTimeoutMillis);
}
return false;
}
TopicPublishInfo* MQClientFactory::topicRouteData2TopicPublishInfo(const std::string& topic,
TopicRouteData& route)
{
TopicPublishInfo* info = new TopicPublishInfo();
if (!route.getOrderTopicConf().empty())
{
std::vector<std::string> brokers;
UtilAll::Split(brokers, route.getOrderTopicConf(), ";");
for (size_t i = 0; i < brokers.size(); i++)
{
std::vector<std::string> item;
UtilAll::Split(item, brokers[i], ":");
int nums = atoi(item[1].c_str());
for (int i = 0; i < nums; i++)
{
MessageQueue mq(topic, item[0], i);
info->getMessageQueueList().push_back(mq);
}
}
info->setOrderTopic(true);
}
else
{
std::list<QueueData> qds = route.getQueueDatas();
qds.sort();
std::list<QueueData>::iterator it = qds.begin();
for (; it != qds.end(); it++)
{
QueueData& qd = (*it);
if (PermName::isWriteable(qd.perm))
{
bool find = false;
BrokerData brokerData;
std::list<BrokerData> bds = route.getBrokerDatas();
std::list<BrokerData>::iterator it1 = bds.begin();
for (; it1 != bds.end(); it1++)
{
BrokerData& bd = (*it1);
if (bd.brokerName == qd.brokerName)
{
brokerData = bd;
find = true;
break;
}
}
if (!find)
{
continue;
}
if (brokerData.brokerAddrs.find(MixAll::MASTER_ID) == brokerData.brokerAddrs.end())
{
continue;
}
for (int i = 0; i < qd.writeQueueNums; i++)
{
MessageQueue mq(topic, qd.brokerName, i);
info->getMessageQueueList().push_back(mq);
}
}
}
info->setOrderTopic(false);
}
return info;
}
std::set<MessageQueue>* MQClientFactory::topicRouteData2TopicSubscribeInfo(const std::string& topic,
TopicRouteData& route)
{
std::set<MessageQueue>* mqList = new std::set<MessageQueue>();
std::list<QueueData> qds = route.getQueueDatas();
std::list<QueueData>::iterator it = qds.begin();
for (; it != qds.end(); it++)
{
QueueData& qd = (*it);
if (PermName::isReadable(qd.perm))
{
for (int i = 0; i < qd.readQueueNums; i++)
{
MessageQueue mq(topic, qd.brokerName, i);
mqList->insert(mq);
}
}
}
return mqList;
}
bool MQClientFactory::registerConsumer(const std::string& group, MQConsumerInner* pConsumer)
{
if (group.empty() || pConsumer == NULL)
{
return false;
}
kpr::ScopedWLock<kpr::RWMutex> lock(m_consumerTableLock);
if (m_consumerTable.find(group) != m_consumerTable.end())
{
return false;
}
m_consumerTable[group] = pConsumer;
return true;
}
void MQClientFactory::unregisterConsumer(const std::string& group)
{
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_consumerTableLock);
m_consumerTable.erase(group);
}
unregisterClientWithLock("", group);
}
bool MQClientFactory::registerProducer(const std::string& group, DefaultMQProducerImpl* pProducer)
{
if (group.empty() || pProducer == NULL)
{
return false;
}
kpr::ScopedWLock<kpr::RWMutex> lock(m_producerTableLock);
if (m_producerTable.find(group) != m_producerTable.end())
{
return false;
}
m_producerTable[group] = pProducer;
return true;
}
void MQClientFactory::unregisterProducer(const std::string& group)
{
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_producerTableLock);
m_producerTable.erase(group);
}
unregisterClientWithLock(group, "");
}
bool MQClientFactory::registerAdminExt(const std::string& group, MQAdminExtInner* pAdmin)
{
if (group.empty() || pAdmin == NULL)
{
return false;
}
kpr::ScopedWLock<kpr::RWMutex> lock(m_adminExtTableLock);
if (m_adminExtTable.find(group) != m_adminExtTable.end())
{
return false;
}
m_adminExtTable[group] = pAdmin;
return true;
}
void MQClientFactory::unregisterAdminExt(const std::string& group)
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_adminExtTableLock);
m_adminExtTable.erase(group);
}
void MQClientFactory::rebalanceImmediately()
{
m_pRebalanceService->wakeup();
}
void MQClientFactory::doRebalance()
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* impl = it->second;
if (impl != NULL)
{
try
{
impl->doRebalance();
}
catch (std::exception& e)
{
RMQ_ERROR("doRebalance exception, %s", e.what());
}
catch (...)
{
RMQ_ERROR("doRebalance unknow exception");
}
}
}
}
MQProducerInner* MQClientFactory::selectProducer(const std::string& group)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_producerTableLock);
std::map<std::string, MQProducerInner*>::iterator it = m_producerTable.find(group);
if (it != m_producerTable.end())
{
return it->second;
}
return NULL;
}
MQConsumerInner* MQClientFactory::selectConsumer(const std::string& group)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.find(group);
if (it != m_consumerTable.end())
{
return it->second;
}
return NULL;
}
FindBrokerResult MQClientFactory::findBrokerAddressInAdmin(const std::string& brokerName)
{
//TODO
FindBrokerResult result;
std::string brokerAddr;
bool slave = false;
bool found = false;
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
typeof(m_brokerAddrTable.begin()) it = m_brokerAddrTable.find(brokerName);
if (it != m_brokerAddrTable.end())
{
// TODO more slave
typeof(it->second.begin()) it1 = it->second.begin();
for (; it1 != it->second.end(); it1++)
{
int brockerId = it1->first;
brokerAddr = it1->second;
if (!brokerAddr.empty())
{
found = true;
if (MixAll::MASTER_ID == brockerId)
{
slave = false;
}
else
{
slave = true;
}
break;
}
}
}
if (found)
{
result.brokerAddr = brokerAddr;
result.slave = slave;
}
return result;
}
std::string MQClientFactory::findBrokerAddressInPublish(const std::string& brokerName)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
std::map<std::string, std::map<int, std::string> >::iterator it = m_brokerAddrTable.find(brokerName);
if (it != m_brokerAddrTable.end())
{
std::map<int, std::string>::iterator it1 = it->second.find(MixAll::MASTER_ID);
if (it1 != it->second.end())
{
return it1->second;
}
}
return "";
}
FindBrokerResult MQClientFactory::findBrokerAddressInSubscribe(const std::string& brokerName,
long brokerId,
bool onlyThisBroker)
{
std::string brokerAddr = "";
bool slave = false;
bool found = false;
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
std::map<std::string, std::map<int, std::string> >::iterator it = m_brokerAddrTable.find(brokerName);
if (it != m_brokerAddrTable.end())
{
std::map<int, std::string>::iterator it1 = it->second.find(brokerId);
if (it1 != it->second.end())
{
brokerAddr = it1->second;
slave = (brokerId != MixAll::MASTER_ID);
found = true;
}
else
{
it1 = it->second.begin();
brokerAddr = it1->second;
slave = (brokerId != MixAll::MASTER_ID);
found = true;
}
}
FindBrokerResult result;
result.brokerAddr = brokerAddr;
result.slave = slave;
return result;
}
std::list<std::string> MQClientFactory::findConsumerIdList(const std::string& topic, const std::string& group)
{
std::string brokerAddr = findBrokerAddrByTopic(topic);
if (brokerAddr.empty())
{
updateTopicRouteInfoFromNameServer(topic);
brokerAddr = findBrokerAddrByTopic(topic);
}
if (!brokerAddr.empty())
{
try
{
return m_pMQClientAPIImpl->getConsumerIdListByGroup(brokerAddr, group, 3000);
}
catch (...)
{
RMQ_WARN("getConsumerIdListByGroup exception, %s, %s", brokerAddr.c_str(), group.c_str());
}
}
std::list<std::string> ids;
return ids;
}
std::string MQClientFactory::findBrokerAddrByTopic(const std::string& topic)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_topicRouteTableLock);
std::map<std::string, TopicRouteData>::iterator it = m_topicRouteTable.find(topic);
if (it != m_topicRouteTable.end())
{
const std::list<BrokerData>& brokers = it->second.getBrokerDatas();
if (!brokers.empty())
{
BrokerData bd = brokers.front();
return TopicRouteData::selectBrokerAddr(bd);
}
}
return "";
}
TopicRouteData MQClientFactory::getAnExistTopicRouteData(const std::string& topic)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_topicRouteTableLock);
std::map<std::string, TopicRouteData>::iterator it = m_topicRouteTable.find(topic);
if (it != m_topicRouteTable.end())
{
return it->second;
}
TopicRouteData data;
return data;
}
MQClientAPIImpl* MQClientFactory::getMQClientAPIImpl()
{
return m_pMQClientAPIImpl;
}
MQAdminImpl* MQClientFactory::getMQAdminImpl()
{
return m_pMQAdminImpl;
}
std::string MQClientFactory::getClientId()
{
return m_clientId;
}
long long MQClientFactory::getBootTimestamp()
{
return m_bootTimestamp;
}
PullMessageService* MQClientFactory::getPullMessageService()
{
return m_pPullMessageService;
}
DefaultMQProducer* MQClientFactory::getDefaultMQProducer()
{
return m_pDefaultMQProducer;
}
void MQClientFactory::sendHeartbeatToAllBroker()
{
RMQ_DEBUG("sendHeartbeatToAllBroker begin");
HeartbeatData heartbeatData;
this->prepareHeartbeatData(heartbeatData);
bool producerEmpty = heartbeatData.getProducerDataSet().empty();
bool consumerEmpty = heartbeatData.getConsumerDataSet().empty();
if (producerEmpty && consumerEmpty)
{
RMQ_ERROR("sending hearbeat, but no consumer and no producer");
return;
}
RMQ_DEBUG("clientId=%s, m_brokerAddrTable=%u", heartbeatData.getClientID().c_str(), (unsigned)m_brokerAddrTable.size());
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
std::map<std::string, std::map<int, std::string> >::iterator it = m_brokerAddrTable.begin();
for (; it != m_brokerAddrTable.end(); it++)
{
std::map<int, std::string>::iterator it1 = it->second.begin();
for (; it1 != it->second.end(); it1++)
{
std::string& addr = it1->second;
if (!addr.empty())
{
if (consumerEmpty)
{
if (it1->first != MixAll::MASTER_ID)
{
continue;
}
}
try
{
m_pMQClientAPIImpl->sendHearbeat(addr, &heartbeatData, 3000);
RMQ_INFO("send heartbeat to broker[{%s} {%d} {%s}] success",
it->first.c_str(), it1->first, addr.c_str());
RMQ_INFO("HeartbeatData %s", heartbeatData.toString().c_str());
}
catch (...)
{
RMQ_ERROR("send heart beat to broker exception");
}
}
}
}
RMQ_DEBUG("sendHeartbeatToAllBroker end");
}
void MQClientFactory::prepareHeartbeatData(HeartbeatData& heartbeatData)
{
// clientID
heartbeatData.setClientID(m_clientId);
// Consumer
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
if (inner)
{
ConsumerData consumerData;
consumerData.groupName = inner->groupName();
consumerData.consumeType = inner->consumeType();
consumerData.messageModel = inner->messageModel();
consumerData.consumeFromWhere = inner->consumeFromWhere();
consumerData.subscriptionDataSet = inner->subscriptions();
heartbeatData.getConsumerDataSet().insert(consumerData);
}
}
}
// Producer
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_producerTableLock);
std::map<std::string, MQProducerInner*>::iterator it = m_producerTable.begin();
for (; it != m_producerTable.end(); it++)
{
MQProducerInner* inner = it->second;
if (inner)
{
ProducerData producerData;
producerData.groupName = (it->first);
heartbeatData.getProducerDataSet().insert(producerData);
}
}
}
return;
}
void MQClientFactory::makesureInstanceNameIsOnly(const std::string& instanceName)
{
//TODO
}
void MQClientFactory::fetchNameServerAddr()
{
//1000 * 10, 1000 * 60 * 2
try
{
RMQ_DEBUG("Task: fetchNameServerAddr");
m_pMQClientAPIImpl->fetchNameServerAddr();
}
catch (...)
{
RMQ_ERROR("Task: fetchNameServerAddr exception");
}
}
void MQClientFactory::updateTopicRouteInfoFromNameServerTask()
{
//10, 1000 * 30, m_clientConfig.getPollNameServerInteval()
try
{
RMQ_DEBUG("Task: updateTopicRouteInfoFromNameServerTask");
updateTopicRouteInfoFromNameServer();
}
catch (...)
{
RMQ_ERROR("Task: fetchNameServerAddr exception");
}
}
void MQClientFactory::cleanBroker()
{
//1000, 1000 * 30, m_clientConfig.getHeartbeatBrokerInterval()
try
{
RMQ_DEBUG("Task: cleanBroker");
cleanOfflineBroker();
sendHeartbeatToAllBrokerWithLock();
}
catch (...)
{
RMQ_ERROR("Task: cleanBroker exception");
}
}
void MQClientFactory::persistAllConsumerOffsetTask()
{
//1000 * 10, 1000 * 5, m_clientConfig.getPersistConsumerOffsetInterval()
try
{
RMQ_DEBUG("Task: persistAllConsumerOffsetTask");
persistAllConsumerOffset();
}
catch (...)
{
RMQ_ERROR("Task: persistAllConsumerOffsetTask exception");
}
}
void MQClientFactory::recordSnapshotPeriodicallyTask()
{
// 1000 * 10, 1000,
try
{
//RMQ_DEBUG("Task: recordSnapshotPeriodicallyTask");
recordSnapshotPeriodically();
}
catch (...)
{
RMQ_ERROR("Task: recordSnapshotPeriodically exception");
}
}
void MQClientFactory::logStatsPeriodicallyTask()
{
// 1000 * 10, 1000 * 60
try
{
RMQ_DEBUG("Task: logStatsPeriodicallyTask");
logStatsPeriodically();
}
catch (...)
{
RMQ_ERROR("Task: logStatsPeriodicallyTask exception");
}
}
void MQClientFactory::startScheduledTask()
{
m_scheduledTaskIds[0] = m_timerTaskManager.RegisterTimer(1000 * 10, 1000 * 60 * 2, m_pFetchNameServerAddrTask);
m_scheduledTaskIds[1] = m_timerTaskManager.RegisterTimer(10, m_clientConfig.getPollNameServerInterval(), m_pUpdateTopicRouteInfoFromNameServerTask);
m_scheduledTaskIds[2] = m_timerTaskManager.RegisterTimer(1000, m_clientConfig.getHeartbeatBrokerInterval(), m_pCleanBrokerTask);
m_scheduledTaskIds[3] = m_timerTaskManager.RegisterTimer(1000 * 10, m_clientConfig.getPersistConsumerOffsetInterval(), m_pPersistAllConsumerOffsetTask);
m_scheduledTaskIds[4] = m_timerTaskManager.RegisterTimer(1000 * 10, 1000, m_pRecordSnapshotPeriodicallyTask);
m_scheduledTaskIds[5] = m_timerTaskManager.RegisterTimer(1000 * 10, 1000 * 60, m_pLogStatsPeriodicallyTask);
}
void MQClientFactory::cleanOfflineBroker()
{
RMQ_DEBUG("TryLock m_lockNamesrv: 0x%p", &m_lockNamesrv);
if (m_lockNamesrv.TryLock(MQClientFactory::LockTimeoutMillis))
{
RMQ_DEBUG("TryLock m_lockNamesrv ok");
std::map<std::string, std::map<int, std::string> > updatedTable;
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
std::map<std::string, std::map<int, std::string> >::iterator it = m_brokerAddrTable.begin();
for (; it != m_brokerAddrTable.end(); it++)
{
std::map<int, std::string> cloneTable = it->second;
std::map<int, std::string>::iterator it1 = cloneTable.begin();
for (; it1 != cloneTable.end();)
{
std::string& addr = it1->second;
if (!isBrokerAddrExistInTopicRouteTable(addr))
{
std::map<int, std::string>::iterator itTmp = it1;
it1++;
cloneTable.erase(itTmp);
continue;
}
it1++;
}
if (!cloneTable.empty())
{
updatedTable[it->first] = cloneTable;
}
}
}
{
kpr::ScopedWLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
m_brokerAddrTable.clear();
m_brokerAddrTable = updatedTable;
}
m_lockNamesrv.Unlock();
RMQ_DEBUG("UnLock m_lockNamesrv ok");
}
else
{
RMQ_DEBUG("TryLock m_lockNamesrv fail");
}
}
bool MQClientFactory::isBrokerAddrExistInTopicRouteTable(const std::string& addr)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_topicRouteTableLock);
std::map<std::string, TopicRouteData>::iterator it = m_topicRouteTable.begin();
for (; it != m_topicRouteTable.end(); it++)
{
const std::list<BrokerData>& brokers = it->second.getBrokerDatas();
std::list<BrokerData>::const_iterator it1 = brokers.begin();
for (; it1 != brokers.end(); it1++)
{
std::map<int, std::string>::const_iterator it2 = (*it1).brokerAddrs.begin();
for (; it2 != (*it1).brokerAddrs.end(); it2++)
{
if (it2->second.find(addr) != std::string::npos)
{
return true;
}
}
}
}
return false;
}
void MQClientFactory::recordSnapshotPeriodically()
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
if (inner)
{
DefaultMQPushConsumerImpl* consumer = dynamic_cast<DefaultMQPushConsumerImpl*>(inner);
if (consumer)
{
consumer->getConsumerStatManager()->recordSnapshotPeriodically();
}
}
}
}
void MQClientFactory::logStatsPeriodically()
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
if (inner)
{
DefaultMQPushConsumerImpl* consumer = dynamic_cast<DefaultMQPushConsumerImpl*>(inner);
if (consumer)
{
std::string group = it->first;
consumer->getConsumerStatManager()->logStatsPeriodically(group, m_clientId);
}
}
}
}
void MQClientFactory::persistAllConsumerOffset()
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
RMQ_DEBUG("persistAllConsumerOffset, m_consumerTable.size=%u", (unsigned)m_consumerTable.size());
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
if (inner)
{
inner->persistConsumerOffset();
}
}
}
bool MQClientFactory::topicRouteDataIsChange(TopicRouteData& olddata, TopicRouteData& nowdata)
{
TopicRouteData old = olddata;
TopicRouteData now = nowdata;
old.getQueueDatas().sort();
old.getBrokerDatas().sort();
now.getQueueDatas().sort();
now.getBrokerDatas().sort();
return !(old == now);
}
bool MQClientFactory::isNeedUpdateTopicRouteInfo(const std::string& topic)
{
bool result = false;
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_producerTableLock);
std::map<std::string, MQProducerInner*>::iterator it = m_producerTable.begin();
for (; it != m_producerTable.end(); it++)
{
MQProducerInner* inner = it->second;
if (inner)
{
result = inner->isPublishTopicNeedUpdate(topic);
}
}
}
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_consumerTableLock);
std::map<std::string, MQConsumerInner*>::iterator it = m_consumerTable.begin();
for (; it != m_consumerTable.end(); it++)
{
MQConsumerInner* inner = it->second;
if (inner)
{
result = inner->isSubscribeTopicNeedUpdate(topic);
}
}
}
return result;
}
void MQClientFactory::unregisterClientWithLock(const std::string& producerGroup, const std::string& consumerGroup)
{
RMQ_DEBUG("TryLock m_lockHeartbeat: 0x%p", &m_lockHeartbeat);
if (m_lockHeartbeat.TryLock(MQClientFactory::LockTimeoutMillis))
{
try
{
RMQ_DEBUG("TryLock m_lockHeartbeat ok");
unregisterClient(producerGroup, consumerGroup);
}
catch (...)
{
RMQ_ERROR("unregisterClientWithLock exception, %s %s",
producerGroup.c_str(), consumerGroup.c_str());
}
m_lockHeartbeat.Unlock();
RMQ_DEBUG("Unlock m_lockHeartbeat ok");
}
else
{
RMQ_WARN("TryLock m_lockHeartbeat fail");
}
}
void MQClientFactory::unregisterClient(const std::string& producerGroup, const std::string& consumerGroup)
{
kpr::ScopedRLock<kpr::RWMutex> lock(m_brokerAddrTableLock);
std::map<std::string, std::map<int, std::string> >::iterator it = m_brokerAddrTable.begin();
for (; it != m_brokerAddrTable.end(); it++)
{
std::map<int, std::string>::iterator it1 = it->second.begin();
for (; it1 != it->second.end(); it1++)
{
std::string& addr = it1->second;
if (!addr.empty())
{
try
{
m_pMQClientAPIImpl->unregisterClient(addr, m_clientId, producerGroup,
consumerGroup, 3000);
}
catch (...)
{
RMQ_ERROR("unregister client exception from broker: %s", addr.c_str());
}
}
}
}
}
}