first commit

This commit is contained in:
lnk
2026-07-10 14:13:02 +08:00
commit b61388443f
459 changed files with 143602 additions and 0 deletions

View File

@@ -0,0 +1,939 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MQClientAPIImpl.h"
#include <assert.h>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <fstream>
#include "CommunicationMode.h"
#include "Logging.h"
#include "MQDecoder.h"
#include "PullResultExt.h"
namespace rocketmq {
//<!************************************************************************
MQClientAPIImpl::MQClientAPIImpl(const string& mqClientId, bool enableSsl, const std::string& sslPropertyFile)
: m_firstFetchNameSrv(true), m_mqClientId(mqClientId) {}
MQClientAPIImpl::MQClientAPIImpl(const string& mqClientId,
ClientRemotingProcessor* clientRemotingProcessor,
int pullThreadNum,
uint64_t tcpConnectTimeout,
uint64_t tcpTransportTryLockTimeout,
string unitName,
bool enableSsl,
const std::string& sslPropertyFile)
: m_firstFetchNameSrv(true), m_mqClientId(mqClientId) {
m_pRemotingClient.reset(
new TcpRemotingClient(pullThreadNum, tcpConnectTimeout, tcpTransportTryLockTimeout, enableSsl, sslPropertyFile));
m_pRemotingClient->registerProcessor(CHECK_TRANSACTION_STATE, clientRemotingProcessor);
m_pRemotingClient->registerProcessor(RESET_CONSUMER_CLIENT_OFFSET, clientRemotingProcessor);
m_pRemotingClient->registerProcessor(GET_CONSUMER_STATUS_FROM_CLIENT, clientRemotingProcessor);
m_pRemotingClient->registerProcessor(GET_CONSUMER_RUNNING_INFO, clientRemotingProcessor);
m_pRemotingClient->registerProcessor(NOTIFY_CONSUMER_IDS_CHANGED, clientRemotingProcessor);
m_pRemotingClient->registerProcessor(CONSUME_MESSAGE_DIRECTLY, clientRemotingProcessor);
m_topAddressing.reset(new TopAddressing(unitName));
}
MQClientAPIImpl::~MQClientAPIImpl() {
m_pRemotingClient = NULL;
m_topAddressing = NULL;
}
void MQClientAPIImpl::stopAllTcpTransportThread() {
m_pRemotingClient->stopAllTcpTransportThread();
}
bool MQClientAPIImpl::writeDataToFile(string filename, string data, bool isSync) {
if (data.size() == 0)
return false;
FILE* pFd = fopen(filename.c_str(), "w+");
if (NULL == pFd) {
LOG_ERROR("fopen failed, filename:%s", filename.c_str());
return false;
}
int byte_write = 0;
int byte_left = data.size();
const char* pData = data.c_str();
while (byte_left > 0) {
byte_write = fwrite(pData, sizeof(char), byte_left, pFd);
if (byte_write == byte_left) {
if (ferror(pFd)) {
LOG_ERROR("write data fail, data len:" SIZET_FMT ", file:%s, msg:%s", data.size(), filename.c_str(),
strerror(errno));
fclose(pFd);
return false;
}
}
byte_left -= byte_write;
pData += byte_write;
}
pData = NULL;
if (isSync) {
LOG_INFO("fsync with filename:%s", filename.c_str());
fflush(pFd);
}
fclose(pFd);
return true;
}
string MQClientAPIImpl::fetchNameServerAddr(const string& NSDomain) {
try {
string homeDir(UtilAll::getHomeDirectory());
string storePath = homeDir + "/logs/rocketmq-cpp/snapshot";
boost::filesystem::path dir(storePath);
boost::system::error_code ec;
if (!boost::filesystem::exists(dir, ec)) {
if (!boost::filesystem::create_directory(dir, ec)) {
LOG_ERROR("create data dir:%s error", storePath.c_str());
return "";
}
}
string file(storePath);
string fileBak(storePath);
vector<string> ret_;
int retSize = UtilAll::Split(ret_, m_mqClientId, "@");
if (retSize == 2) {
file.append("/nameserver_addr-").append(ret_[retSize - 1]);
} else {
LOG_ERROR("split mqClientId:%s fail", m_mqClientId.c_str());
file.append("/nameserver_addr-DEFAULT");
}
boost::filesystem::path snapshot_file(file);
fileBak.append("/nameserver_addr.bak");
const string addrs = m_topAddressing->fetchNSAddr(NSDomain);
if (addrs.empty()) {
if (m_nameSrvAddr.empty()) {
LOG_INFO("Load the name server snapshot local file:%s", file.c_str());
if (boost::filesystem::exists(snapshot_file)) {
ifstream snapshot_file(file, ios::binary);
istreambuf_iterator<char> beg(snapshot_file), end;
string filecontent(beg, end);
updateNameServerAddr(filecontent);
m_nameSrvAddr = filecontent;
} else {
LOG_WARN("The name server snapshot local file not exists");
}
}
} else {
if (m_firstFetchNameSrv == true) {
// it is the first time, so need to create the name server snapshot
// local file
m_firstFetchNameSrv = false;
}
if (addrs.compare(m_nameSrvAddr) != 0) {
LOG_INFO("name server address changed, old: %s, new: %s", m_nameSrvAddr.c_str(), addrs.c_str());
updateNameServerAddr(addrs);
m_nameSrvAddr = addrs;
} else {
if (!m_firstFetchNameSrv)
return m_nameSrvAddr;
}
// update the snapshot local file if nameSrv changes or
// m_firstFetchNameSrv==true
if (writeDataToFile(fileBak, addrs, true)) {
if (!UtilAll::ReplaceFile(fileBak, file))
LOG_ERROR("could not rename bak file:%s", strerror(errno));
}
}
if (!boost::filesystem::exists(snapshot_file)) {
// the name server snapshot local file maybe deleted by force, create it
if (writeDataToFile(fileBak, m_nameSrvAddr, true)) {
if (!UtilAll::ReplaceFile(fileBak, file))
LOG_ERROR("could not rename bak file:%s", strerror(errno));
}
}
} catch (...) {
}
return m_nameSrvAddr;
}
void MQClientAPIImpl::updateNameServerAddr(const string& addrs) {
if (m_pRemotingClient != NULL)
m_pRemotingClient->updateNameServerAddressList(addrs);
}
void MQClientAPIImpl::callSignatureBeforeRequest(const string& addr,
RemotingCommand& request,
const SessionCredentials& session_credentials) {
ClientRPCHook rpcHook(session_credentials);
rpcHook.doBeforeRequest(addr, request);
}
// Note: all request rules: throw exception if got broker error response,
// exclude getTopicRouteInfoFromNameServer and unregisterClient
void MQClientAPIImpl::createTopic(const string& addr,
const string& defaultTopic,
TopicConfig topicConfig,
const SessionCredentials& sessionCredentials) {
string topicWithProjectGroup = topicConfig.getTopicName();
CreateTopicRequestHeader* requestHeader = new CreateTopicRequestHeader();
requestHeader->topic = (topicWithProjectGroup);
requestHeader->defaultTopic = (defaultTopic);
requestHeader->readQueueNums = (topicConfig.getReadQueueNums());
requestHeader->writeQueueNums = (topicConfig.getWriteQueueNums());
requestHeader->perm = (topicConfig.getPerm());
requestHeader->topicFilterType = (topicConfig.getTopicFilterType());
RemotingCommand request(UPDATE_AND_CREATE_TOPIC, requestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE:
return;
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
void MQClientAPIImpl::endTransactionOneway(std::string addr,
EndTransactionRequestHeader* requestHeader,
std::string remark,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(END_TRANSACTION, requestHeader);
request.setRemark(remark);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
m_pRemotingClient->invokeOneway(addr, request);
return;
}
SendResult MQClientAPIImpl::sendMessage(const string& addr,
const string& brokerName,
const MQMessage& msg,
SendMessageRequestHeader* pRequestHeader,
int timeoutMillis,
int maxRetrySendTimes,
int communicationMode,
SendCallback* pSendCallback,
const SessionCredentials& sessionCredentials) {
// RemotingCommand request(SEND_MESSAGE, pRequestHeader);
// Using MQ V2 Protocol to end messages.
SendMessageRequestHeaderV2* pRequestHeaderV2 = new SendMessageRequestHeaderV2(*pRequestHeader);
RemotingCommand request(SEND_MESSAGE_V2, pRequestHeaderV2);
delete pRequestHeader; // delete to avoid memory leak.
string body = msg.getBody();
request.SetBody(body.c_str(), body.length());
request.setMsgBody(body);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
switch (communicationMode) {
case ComMode_ONEWAY:
m_pRemotingClient->invokeOneway(addr, request);
break;
case ComMode_ASYNC:
sendMessageAsync(addr, brokerName, msg, request, pSendCallback, timeoutMillis, maxRetrySendTimes, 1);
break;
case ComMode_SYNC:
return sendMessageSync(addr, brokerName, msg, request, timeoutMillis);
default:
break;
}
return SendResult();
}
void MQClientAPIImpl::sendHeartbeat(const string& addr,
HeartbeatData* pHeartbeatData,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(HEART_BEAT, NULL);
string body;
pHeartbeatData->Encode(body);
request.SetBody(body.data(), body.length());
request.setMsgBody(body);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
if (m_pRemotingClient->invokeHeartBeat(addr, request)) {
LOG_DEBUG("sendHeartbeat to broker:%s success", addr.c_str());
} else {
LOG_WARN("sendHeartbeat to broker:%s failed", addr.c_str());
}
}
void MQClientAPIImpl::unregisterClient(const string& addr,
const string& clientID,
const string& producerGroup,
const string& consumerGroup,
const SessionCredentials& sessionCredentials) {
LOG_INFO("unregisterClient to broker:%s", addr.c_str());
RemotingCommand request(UNREGISTER_CLIENT, new UnregisterClientRequestHeader(clientID, producerGroup, consumerGroup));
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE:
LOG_INFO("unregisterClient to:%s success", addr.c_str());
return;
default:
break;
}
LOG_WARN("unregisterClient fail:%s,%d", response->getRemark().c_str(), response->getCode());
}
}
// return NULL if got no response or error response
TopicRouteData* MQClientAPIImpl::getTopicRouteInfoFromNameServer(const string& topic,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(GET_ROUTEINTO_BY_TOPIC, new GetRouteInfoRequestHeader(topic));
callSignatureBeforeRequest("", request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync("", request, timeoutMillis));
if (pResponse != NULL) {
if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) {
switch (pResponse->getCode()) {
case SUCCESS_VALUE: {
const MemoryBlock* pbody = pResponse->GetBody();
if (pbody->getSize()) {
TopicRouteData* topicRoute = TopicRouteData::Decode(pbody);
return topicRoute;
}
}
case TOPIC_NOT_EXIST: {
LOG_WARN("Get topic[%s] route failed [TOPIC_NOT_EXIST].", topic.c_str());
return NULL;
}
default:
break;
}
LOG_WARN("%s,%d", pResponse->getRemark().c_str(), pResponse->getCode());
return NULL;
}
}
LOG_WARN("Get topic[%s] route failed [Null Response].", topic.c_str());
return NULL;
}
TopicList* MQClientAPIImpl::getTopicListFromNameServer(const SessionCredentials& sessionCredentials) {
RemotingCommand request(GET_ALL_TOPIC_LIST_FROM_NAMESERVER, NULL);
callSignatureBeforeRequest("", request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync("", request));
if (pResponse != NULL) {
if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) {
switch (pResponse->getCode()) {
case SUCCESS_VALUE: {
const MemoryBlock* pbody = pResponse->GetBody();
if (pbody->getSize()) {
TopicList* topicList = TopicList::Decode(pbody);
return topicList;
}
}
default:
break;
}
THROW_MQEXCEPTION(MQClientException, pResponse->getRemark(), pResponse->getCode());
}
}
return NULL;
}
int MQClientAPIImpl::wipeWritePermOfBroker(const string& namesrvAddr, const string& brokerName, int timeoutMillis) {
return 0;
}
void MQClientAPIImpl::deleteTopicInBroker(const string& addr, const string& topic, int timeoutMillis) {}
void MQClientAPIImpl::deleteTopicInNameServer(const string& addr, const string& topic, int timeoutMillis) {}
void MQClientAPIImpl::deleteSubscriptionGroup(const string& addr, const string& groupName, int timeoutMillis) {}
string MQClientAPIImpl::getKVConfigByValue(const string& projectNamespace,
const string& projectGroup,
int timeoutMillis) {
return "";
}
KVTable MQClientAPIImpl::getKVListByNamespace(const string& projectNamespace, int timeoutMillis) {
return KVTable();
}
void MQClientAPIImpl::deleteKVConfigByValue(const string& projectNamespace,
const string& projectGroup,
int timeoutMillis) {}
SendResult MQClientAPIImpl::sendMessageSync(const string& addr,
const string& brokerName,
const MQMessage& msg,
RemotingCommand& request,
int timeoutMillis) {
//<!block util response;
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (pResponse != NULL) {
try {
SendResult result = processSendResponse(brokerName, msg, pResponse.get());
LOG_DEBUG("sendMessageSync success:%s to addr:%s,brokername:%s, send status:%d", msg.toString().c_str(),
addr.c_str(), brokerName.c_str(), (int)result.getSendStatus());
return result;
} catch (...) {
LOG_ERROR("send error");
}
}
THROW_MQEXCEPTION(MQClientException, "response is null", -1);
}
void MQClientAPIImpl::sendMessageAsync(const string& addr,
const string& brokerName,
const MQMessage& msg,
RemotingCommand& request,
SendCallback* pSendCallback,
int64 timeoutMilliseconds,
int maxRetryTimes,
int retrySendTimes) {
int64 begin_time = UtilAll::currentTimeMillis();
//<!delete in future;
// AsyncCallbackWrap* cbw = new SendCallbackWrap(brokerName, msg, pSendCallback, this);
LOG_DEBUG("sendMessageAsync request:%s, timeout:%lld, maxRetryTimes:%d retrySendTimes:%d", request.ToString().data(),
timeoutMilliseconds, maxRetryTimes, retrySendTimes);
// Use smart ptr to control cbw.
std::shared_ptr<AsyncCallbackWrap> cbw = std::make_shared<SendCallbackWrap>(brokerName, msg, pSendCallback, this);
if (m_pRemotingClient->invokeAsync(addr, request, cbw, timeoutMilliseconds, maxRetryTimes, retrySendTimes) == false) {
LOG_WARN("invokeAsync failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d", addr.c_str(),
msg.getTopic().data(), timeoutMilliseconds, maxRetryTimes, retrySendTimes);
// when getTcp return false, need consider retrySendTimes
int retry_time = retrySendTimes + 1;
int64 time_out = timeoutMilliseconds - (UtilAll::currentTimeMillis() - begin_time);
while (retry_time < maxRetryTimes && time_out > 0) {
begin_time = UtilAll::currentTimeMillis();
if (m_pRemotingClient->invokeAsync(addr, request, cbw, time_out, maxRetryTimes, retry_time) == false) {
retry_time += 1;
time_out = time_out - (UtilAll::currentTimeMillis() - begin_time);
LOG_WARN("invokeAsync retry failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d",
addr.c_str(), msg.getTopic().data(), time_out, maxRetryTimes, retry_time);
continue;
} else {
return; // invokeAsync success
}
}
LOG_ERROR("sendMessageAsync failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d",
addr.c_str(), msg.getTopic().data(), time_out, maxRetryTimes, retrySendTimes);
if (cbw && pSendCallback != nullptr) {
cbw->onException();
// deleteAndZero(cbw);
} else {
THROW_MQEXCEPTION(MQClientException, "sendMessageAsync failed", -1);
}
}
}
PullResult* MQClientAPIImpl::pullMessage(const string& addr,
PullMessageRequestHeader* pRequestHeader,
int timeoutMillis,
int communicationMode,
PullCallback* pullCallback,
void* pArg,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(PULL_MESSAGE, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
switch (communicationMode) {
case ComMode_ONEWAY:
break;
case ComMode_ASYNC:
pullMessageAsync(addr, request, timeoutMillis, pullCallback, pArg);
break;
case ComMode_SYNC:
return pullMessageSync(addr, request, timeoutMillis);
default:
break;
}
return NULL;
}
void MQClientAPIImpl::pullMessageAsync(const string& addr,
RemotingCommand& request,
int timeoutMillis,
PullCallback* pullCallback,
void* pArg) {
// AsyncCallbackWrap* cbw = new PullCallbackWrap(pullCallback, this, pArg);
std::shared_ptr<AsyncCallbackWrap> cbw = std::make_shared<PullCallbackWrap>(pullCallback, this, pArg);
if (m_pRemotingClient->invokeAsync(addr, request, cbw, timeoutMillis) == false) {
LOG_ERROR("pullMessageAsync failed of addr:%s, mq:%s", addr.c_str(),
static_cast<AsyncArg*>(pArg)->mq.toString().data());
// deleteAndZero(cbw);
THROW_MQEXCEPTION(MQClientException, "pullMessageAsync failed", -1);
}
}
PullResult* MQClientAPIImpl::pullMessageSync(const string& addr, RemotingCommand& request, int timeoutMillis) {
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (pResponse != NULL) {
if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) {
try {
PullResult* pullResult = processPullResponse(pResponse.get()); // pullMessage will handle
// exception from
// processPullResponse
return pullResult;
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
return NULL;
}
}
}
return NULL;
}
SendResult MQClientAPIImpl::processSendResponse(const string& brokerName,
const MQMessage& msg,
RemotingCommand* pResponse) {
SendStatus sendStatus = SEND_OK;
int res = 0;
switch (pResponse->getCode()) {
case FLUSH_DISK_TIMEOUT:
sendStatus = SEND_FLUSH_DISK_TIMEOUT;
break;
case FLUSH_SLAVE_TIMEOUT:
sendStatus = SEND_FLUSH_SLAVE_TIMEOUT;
break;
case SLAVE_NOT_AVAILABLE:
sendStatus = SEND_SLAVE_NOT_AVAILABLE;
break;
case SUCCESS_VALUE:
sendStatus = SEND_OK;
break;
default:
res = -1;
break;
}
if (res == 0) {
SendMessageResponseHeader* responseHeader = (SendMessageResponseHeader*)pResponse->getCommandHeader();
MQMessageQueue messageQueue(msg.getTopic(), brokerName, responseHeader->queueId);
string unique_msgId = msg.getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX);
return SendResult(sendStatus, unique_msgId, responseHeader->msgId, messageQueue, responseHeader->queueOffset,
responseHeader->regionId);
}
LOG_ERROR("processSendResponse error remark:%s, error code:%d", (pResponse->getRemark()).c_str(),
pResponse->getCode());
THROW_MQEXCEPTION(MQClientException, pResponse->getRemark(), pResponse->getCode());
}
PullResult* MQClientAPIImpl::processPullResponse(RemotingCommand* pResponse) {
PullStatus pullStatus = NO_NEW_MSG;
switch (pResponse->getCode()) {
case SUCCESS_VALUE:
pullStatus = FOUND;
break;
case PULL_NOT_FOUND:
pullStatus = NO_NEW_MSG;
break;
case PULL_RETRY_IMMEDIATELY:
pullStatus = NO_MATCHED_MSG;
break;
case PULL_OFFSET_MOVED:
pullStatus = OFFSET_ILLEGAL;
break;
default:
THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode());
break;
}
PullMessageResponseHeader* responseHeader = static_cast<PullMessageResponseHeader*>(pResponse->getCommandHeader());
if (!responseHeader) {
LOG_ERROR("processPullResponse:responseHeader is NULL");
THROW_MQEXCEPTION(MQClientException, "processPullResponse:responseHeader is NULL", -1);
}
//<!get body,delete outsite;
MemoryBlock bodyFromResponse = *(pResponse->GetBody()); // response data judgement had been done outside
// of processPullResponse
if (bodyFromResponse.getSize() == 0) {
if (pullStatus != FOUND) {
return new PullResultExt(pullStatus, responseHeader->nextBeginOffset, responseHeader->minOffset,
responseHeader->maxOffset, (int)responseHeader->suggestWhichBrokerId);
} else {
THROW_MQEXCEPTION(MQClientException, "memoryBody size is 0, but pullStatus equals found", -1);
}
} else {
return new PullResultExt(pullStatus, responseHeader->nextBeginOffset, responseHeader->minOffset,
responseHeader->maxOffset, (int)responseHeader->suggestWhichBrokerId, bodyFromResponse);
}
}
//<!***************************************************************************
int64 MQClientAPIImpl::getMinOffset(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
GetMinOffsetRequestHeader* pRequestHeader = new GetMinOffsetRequestHeader();
pRequestHeader->topic = topic;
pRequestHeader->queueId = queueId;
RemotingCommand request(GET_MIN_OFFSET, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
GetMinOffsetResponseHeader* responseHeader = (GetMinOffsetResponseHeader*)response->getCommandHeader();
int64 offset = responseHeader->offset;
return offset;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
int64 MQClientAPIImpl::getMaxOffset(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
GetMaxOffsetRequestHeader* pRequestHeader = new GetMaxOffsetRequestHeader();
pRequestHeader->topic = topic;
pRequestHeader->queueId = queueId;
RemotingCommand request(GET_MAX_OFFSET, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
GetMaxOffsetResponseHeader* responseHeader = (GetMaxOffsetResponseHeader*)response->getCommandHeader();
int64 offset = responseHeader->offset;
return offset;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
int64 MQClientAPIImpl::searchOffset(const string& addr,
const string& topic,
int queueId,
uint64_t timestamp,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
SearchOffsetRequestHeader* pRequestHeader = new SearchOffsetRequestHeader();
pRequestHeader->topic = topic;
pRequestHeader->queueId = queueId;
pRequestHeader->timestamp = timestamp;
RemotingCommand request(SEARCH_OFFSET_BY_TIMESTAMP, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
SearchOffsetResponseHeader* responseHeader = (SearchOffsetResponseHeader*)response->getCommandHeader();
int64 offset = responseHeader->offset;
return offset;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
MQMessageExt* MQClientAPIImpl::viewMessage(const string& addr,
int64 phyoffset,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
ViewMessageRequestHeader* pRequestHeader = new ViewMessageRequestHeader();
pRequestHeader->offset = phyoffset;
RemotingCommand request(VIEW_MESSAGE_BY_ID, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
int64 MQClientAPIImpl::getEarliestMsgStoretime(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
GetEarliestMsgStoretimeRequestHeader* pRequestHeader = new GetEarliestMsgStoretimeRequestHeader();
pRequestHeader->topic = topic;
pRequestHeader->queueId = queueId;
RemotingCommand request(GET_EARLIEST_MSG_STORETIME, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
GetEarliestMsgStoretimeResponseHeader* responseHeader =
(GetEarliestMsgStoretimeResponseHeader*)response->getCommandHeader();
int64 timestamp = responseHeader->timestamp;
return timestamp;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
void MQClientAPIImpl::getConsumerIdListByGroup(const string& addr,
const string& consumerGroup,
vector<string>& cids,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
GetConsumerListByGroupRequestHeader* pRequestHeader = new GetConsumerListByGroupRequestHeader();
pRequestHeader->consumerGroup = consumerGroup;
RemotingCommand request(GET_CONSUMER_LIST_BY_GROUP, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (pResponse != NULL) {
if ((pResponse->GetBody()->getSize() == 0) || (pResponse->GetBody()->getData() != NULL)) {
switch (pResponse->getCode()) {
case SUCCESS_VALUE: {
const MemoryBlock* pbody = pResponse->GetBody();
if (pbody->getSize()) {
GetConsumerListByGroupResponseBody::Decode(pbody, cids);
return;
}
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode());
}
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
int64 MQClientAPIImpl::queryConsumerOffset(const string& addr,
QueryConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(QUERY_CONSUMER_OFFSET, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
QueryConsumerOffsetResponseHeader* responseHeader =
(QueryConsumerOffsetResponseHeader*)response->getCommandHeader();
int64 consumerOffset = responseHeader->offset;
return consumerOffset;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
return -1;
}
void MQClientAPIImpl::updateConsumerOffset(const string& addr,
UpdateConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(UPDATE_CONSUMER_OFFSET, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
return;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
void MQClientAPIImpl::updateConsumerOffsetOneway(const string& addr,
UpdateConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(UPDATE_CONSUMER_OFFSET, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
m_pRemotingClient->invokeOneway(addr, request);
}
void MQClientAPIImpl::consumerSendMessageBack(const string addr,
MQMessageExt& msg,
const string& consumerGroup,
int delayLevel,
int timeoutMillis,
int maxReconsumeTimes,
const SessionCredentials& sessionCredentials) {
ConsumerSendMsgBackRequestHeader* pRequestHeader = new ConsumerSendMsgBackRequestHeader();
pRequestHeader->group = consumerGroup;
pRequestHeader->offset = msg.getCommitLogOffset();
pRequestHeader->delayLevel = delayLevel;
pRequestHeader->unitMode = false;
pRequestHeader->originTopic = msg.getTopic();
pRequestHeader->originMsgId = msg.getMsgId();
pRequestHeader->maxReconsumeTimes = maxReconsumeTimes;
// string addr = socketAddress2IPPort(msg.getStoreHost());
RemotingCommand request(CONSUMER_SEND_MSG_BACK, pRequestHeader);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (response) {
switch (response->getCode()) {
case SUCCESS_VALUE: {
return;
}
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
void MQClientAPIImpl::lockBatchMQ(const string& addr,
LockBatchRequestBody* requestBody,
vector<MQMessageQueue>& mqs,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(LOCK_BATCH_MQ, NULL);
string body;
requestBody->Encode(body);
request.SetBody(body.data(), body.length());
request.setMsgBody(body);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (pResponse != NULL) {
if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) {
switch (pResponse->getCode()) {
case SUCCESS_VALUE: {
const MemoryBlock* pbody = pResponse->GetBody();
if (pbody->getSize()) {
LockBatchResponseBody::Decode(pbody, mqs);
}
return;
} break;
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode());
}
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
void MQClientAPIImpl::unlockBatchMQ(const string& addr,
UnlockBatchRequestBody* requestBody,
int timeoutMillis,
const SessionCredentials& sessionCredentials) {
RemotingCommand request(UNLOCK_BATCH_MQ, NULL);
string body;
requestBody->Encode(body);
request.SetBody(body.data(), body.length());
request.setMsgBody(body);
callSignatureBeforeRequest(addr, request, sessionCredentials);
request.Encode();
unique_ptr<RemotingCommand> pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis));
if (pResponse != NULL) {
switch (pResponse->getCode()) {
case SUCCESS_VALUE: {
return;
} break;
default:
break;
}
THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode());
}
THROW_MQEXCEPTION(MQBrokerException, "response is null", -1);
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,233 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQCLIENTAPIIMPL_H__
#define __MQCLIENTAPIIMPL_H__
#include "AsyncCallback.h"
#include "ClientRPCHook.h"
#include "ClientRemotingProcessor.h"
#include "CommandHeader.h"
#include "HeartbeatData.h"
#include "KVTable.h"
#include "LockBatchBody.h"
#include "MQClientException.h"
#include "MQMessageExt.h"
#include "MQProtos.h"
#include "SendResult.h"
#include "SocketUtil.h"
#include "TcpRemotingClient.h"
#include "TopAddressing.h"
#include "TopicConfig.h"
#include "TopicList.h"
#include "TopicRouteData.h"
#include "UtilAll.h"
#include "VirtualEnvUtil.h"
namespace rocketmq {
//<!wrap all API to net ;
//<!************************************************************************
class MQClientAPIImpl {
public:
MQClientAPIImpl(const string& mqClientId, bool enableSsl, const std::string& sslPropertyFile);
MQClientAPIImpl(const string& mqClientId,
ClientRemotingProcessor* clientRemotingProcessor,
int pullThreadNum,
uint64_t tcpConnectTimeout,
uint64_t tcpTransportTryLockTimeout,
string unitName,
bool enableSsl,
const std::string& sslPropertyFile);
virtual ~MQClientAPIImpl();
virtual void stopAllTcpTransportThread();
virtual bool writeDataToFile(string filename, string data, bool isSync);
virtual string fetchNameServerAddr(const string& NSDomain);
virtual void updateNameServerAddr(const string& addrs);
virtual void callSignatureBeforeRequest(const string& addr,
RemotingCommand& request,
const SessionCredentials& session_credentials);
virtual void createTopic(const string& addr,
const string& defaultTopic,
TopicConfig topicConfig,
const SessionCredentials& sessionCredentials);
virtual void endTransactionOneway(std::string addr,
EndTransactionRequestHeader* requestHeader,
std::string remark,
const SessionCredentials& sessionCredentials);
virtual SendResult sendMessage(const string& addr,
const string& brokerName,
const MQMessage& msg,
SendMessageRequestHeader* pRequestHeader,
int timeoutMillis,
int maxRetrySendTimes,
int communicationMode,
SendCallback* pSendCallback,
const SessionCredentials& sessionCredentials);
virtual PullResult* pullMessage(const string& addr,
PullMessageRequestHeader* pRequestHeader,
int timeoutMillis,
int communicationMode,
PullCallback* pullCallback,
void* pArg,
const SessionCredentials& sessionCredentials);
virtual void sendHeartbeat(const string& addr,
HeartbeatData* pHeartbeatData,
const SessionCredentials& sessionCredentials);
virtual void unregisterClient(const string& addr,
const string& clientID,
const string& producerGroup,
const string& consumerGroup,
const SessionCredentials& sessionCredentials);
virtual TopicRouteData* getTopicRouteInfoFromNameServer(const string& topic,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual TopicList* getTopicListFromNameServer(const SessionCredentials& sessionCredentials);
virtual int wipeWritePermOfBroker(const string& namesrvAddr, const string& brokerName, int timeoutMillis);
virtual void deleteTopicInBroker(const string& addr, const string& topic, int timeoutMillis);
virtual void deleteTopicInNameServer(const string& addr, const string& topic, int timeoutMillis);
virtual void deleteSubscriptionGroup(const string& addr, const string& groupName, int timeoutMillis);
virtual string getKVConfigByValue(const string& projectNamespace, const string& projectGroup, int timeoutMillis);
virtual KVTable getKVListByNamespace(const string& projectNamespace, int timeoutMillis);
virtual void deleteKVConfigByValue(const string& projectNamespace, const string& projectGroup, int timeoutMillis);
virtual SendResult processSendResponse(const string& brokerName, const MQMessage& msg, RemotingCommand* pResponse);
virtual PullResult* processPullResponse(RemotingCommand* pResponse);
virtual int64 getMinOffset(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual int64 getMaxOffset(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual int64 searchOffset(const string& addr,
const string& topic,
int queueId,
uint64_t timestamp,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual MQMessageExt* viewMessage(const string& addr,
int64 phyoffset,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual int64 getEarliestMsgStoretime(const string& addr,
const string& topic,
int queueId,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void getConsumerIdListByGroup(const string& addr,
const string& consumerGroup,
vector<string>& cids,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual int64 queryConsumerOffset(const string& addr,
QueryConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void updateConsumerOffset(const string& addr,
UpdateConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void updateConsumerOffsetOneway(const string& addr,
UpdateConsumerOffsetRequestHeader* pRequestHeader,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void consumerSendMessageBack(const string addr,
MQMessageExt& msg,
const string& consumerGroup,
int delayLevel,
int timeoutMillis,
int maxReconsumeTimes,
const SessionCredentials& sessionCredentials);
virtual void lockBatchMQ(const string& addr,
LockBatchRequestBody* requestBody,
vector<MQMessageQueue>& mqs,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void unlockBatchMQ(const string& addr,
UnlockBatchRequestBody* requestBody,
int timeoutMillis,
const SessionCredentials& sessionCredentials);
virtual void sendMessageAsync(const string& addr,
const string& brokerName,
const MQMessage& msg,
RemotingCommand& request,
SendCallback* pSendCallback,
int64 timeoutMilliseconds,
int maxRetryTimes = 1,
int retrySendTimes = 1);
private:
SendResult sendMessageSync(const string& addr,
const string& brokerName,
const MQMessage& msg,
RemotingCommand& request,
int timeoutMillis);
/*
void sendMessageAsync(const string& addr, const string& brokerName,
const MQMessage& msg, RemotingCommand& request,
SendCallback* pSendCallback, int64 timeoutMilliseconds);
*/
PullResult* pullMessageSync(const string& addr, RemotingCommand& request, int timeoutMillis);
void pullMessageAsync(const string& addr,
RemotingCommand& request,
int timeoutMillis,
PullCallback* pullCallback,
void* pArg);
protected:
unique_ptr<TcpRemotingClient> m_pRemotingClient;
private:
unique_ptr<TopAddressing> m_topAddressing;
string m_nameSrvAddr;
bool m_firstFetchNameSrv;
string m_mqClientId;
};
} // namespace rocketmq
//<!***************************************************************************
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQCLIENTFACTORY_H__
#define __MQCLIENTFACTORY_H__
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
#include "FindBrokerResult.h"
#include "MQClientAPIImpl.h"
#include "MQClientException.h"
#include "MQConsumer.h"
#include "MQDecoder.h"
#include "MQMessageQueue.h"
#include "MQProducer.h"
#include "PermName.h"
#include "QueryResult.h"
#include "ServiceState.h"
#include "SocketUtil.h"
#include "TopicConfig.h"
#include "TopicRouteData.h"
namespace rocketmq {
//<!************************************************************************
class TopicPublishInfo;
class MQClientFactory {
public:
MQClientFactory(const string& clientID,
int pullThreadNum,
uint64_t tcpConnectTimeout,
uint64_t tcpTransportTryLockTimeout,
string unitName,
bool enableSsl,
const std::string& sslPropertyFile);
MQClientFactory(const string& clientID, bool enableSsl, const std::string& sslPropertyFile);
virtual ~MQClientFactory();
virtual void start();
virtual void shutdown();
virtual bool registerProducer(MQProducer* pProducer);
virtual void unregisterProducer(MQProducer* pProducer);
virtual bool registerConsumer(MQConsumer* pConsumer);
virtual void unregisterConsumer(MQConsumer* pConsumer);
void createTopic(const string& key,
const string& newTopic,
int queueNum,
const SessionCredentials& session_credentials);
int64 minOffset(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
int64 maxOffset(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
int64 searchOffset(const MQMessageQueue& mq, int64 timestamp, const SessionCredentials& session_credentials);
int64 earliestMsgStoreTime(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
MQMessageExt* viewMessage(const string& msgId, const SessionCredentials& session_credentials);
QueryResult queryMessage(const string& topic,
const string& key,
int maxNum,
int64 begin,
int64 end,
const SessionCredentials& session_credentials);
void endTransactionOneway(const MQMessageQueue& mq,
EndTransactionRequestHeader* requestHeader,
const SessionCredentials& sessionCredentials);
void checkTransactionState(const std::string& addr,
const MQMessageExt& message,
const CheckTransactionStateRequestHeader& checkRequestHeader);
virtual MQClientAPIImpl* getMQClientAPIImpl();
MQProducer* selectProducer(const string& group);
MQConsumer* selectConsumer(const string& group);
boost::shared_ptr<TopicPublishInfo> topicRouteData2TopicPublishInfo(const string& topic, TopicRouteData* pRoute);
void topicRouteData2TopicSubscribeInfo(const string& topic, TopicRouteData* pRoute, vector<MQMessageQueue>& mqs);
FindBrokerResult* findBrokerAddressInSubscribe(const string& brokerName, int brokerId, bool onlyThisBroker);
FindBrokerResult* findBrokerAddressInAdmin(const string& brokerName);
virtual string findBrokerAddressInPublish(const string& brokerName);
virtual boost::shared_ptr<TopicPublishInfo> tryToFindTopicPublishInfo(const string& topic,
const SessionCredentials& session_credentials);
void fetchSubscribeMessageQueues(const string& topic,
vector<MQMessageQueue>& mqs,
const SessionCredentials& session_credentials);
bool updateTopicRouteInfoFromNameServer(const string& topic,
const SessionCredentials& session_credentials,
bool isDefault = false);
void rebalanceImmediately();
void doRebalanceByConsumerGroup(const string& consumerGroup);
virtual void sendHeartbeatToAllBroker();
void cleanOfflineBrokers();
void findConsumerIds(const string& topic,
const string& group,
vector<string>& cids,
const SessionCredentials& session_credentials);
void resetOffset(const string& group, const string& topic, const map<MQMessageQueue, int64>& offsetTable);
ConsumerRunningInfo* consumerRunningInfo(const string& consumerGroup);
bool getSessionCredentialFromConsumer(const string& consumerGroup, SessionCredentials& sessionCredentials);
void addBrokerToAddrMap(const string& brokerName, map<int, string>& brokerAddrs);
map<string, map<int, string>> getBrokerAddrMap();
void clearBrokerAddrMap();
bool isBrokerAddressInUse(const std::string& address);
private:
void unregisterClient(const string& producerGroup,
const string& consumerGroup,
const SessionCredentials& session_credentials);
TopicRouteData* getTopicRouteData(const string& topic);
void addTopicRouteData(const string& topic, TopicRouteData* pTopicRouteData);
HeartbeatData* prepareHeartbeatData();
void startScheduledTask(bool startFetchNSService = true);
//<!timer async callback
void fetchNameServerAddr(boost::system::error_code& ec, boost::shared_ptr<boost::asio::deadline_timer> t);
void updateTopicRouteInfo(boost::system::error_code& ec, boost::shared_ptr<boost::asio::deadline_timer> t);
void timerCB_sendHeartbeatToAllBroker(boost::system::error_code& ec,
boost::shared_ptr<boost::asio::deadline_timer> t);
void timerCB_cleanOfflineBrokers(boost::system::error_code& ec, boost::shared_ptr<boost::asio::deadline_timer> t);
// consumer related operation
void consumer_timerOperation();
void persistAllConsumerOffset(boost::system::error_code& ec, boost::shared_ptr<boost::asio::deadline_timer> t);
void doRebalance();
void timerCB_doRebalance(boost::system::error_code& ec, boost::shared_ptr<boost::asio::deadline_timer> t);
bool getSessionCredentialFromConsumerTable(SessionCredentials& sessionCredentials);
void eraseConsumerFromTable(const string& consumerName);
int getConsumerTableSize();
void getTopicListFromConsumerSubscription(set<string>& topicList);
void updateConsumerSubscribeTopicInfo(const string& topic, vector<MQMessageQueue> mqs);
void insertConsumerInfoToHeartBeatData(HeartbeatData* pHeartbeatData);
// producer related operation
bool getSessionCredentialFromProducerTable(SessionCredentials& sessionCredentials);
void eraseProducerFromTable(const string& producerName);
int getProducerTableSize();
void insertProducerInfoToHeartBeatData(HeartbeatData* pHeartbeatData);
// topicPublishInfo related operation
void addTopicInfoToTable(const string& topic, boost::shared_ptr<TopicPublishInfo> pTopicPublishInfo);
void eraseTopicInfoFromTable(const string& topic);
bool isTopicInfoValidInTable(const string& topic);
boost::shared_ptr<TopicPublishInfo> getTopicPublishInfoFromTable(const string& topic);
void getTopicListFromTopicPublishInfo(set<string>& topicList);
void getSessionCredentialsFromOneOfProducerOrConsumer(SessionCredentials& session_credentials);
protected:
string m_clientId;
unique_ptr<MQClientAPIImpl> m_pClientAPIImpl;
unique_ptr<ClientRemotingProcessor> m_pClientRemotingProcessor;
bool addProducerToTable(const string& producerName, MQProducer* pMQProducer);
bool addConsumerToTable(const string& consumerName, MQConsumer* pMQConsumer);
private:
string m_nameSrvDomain; // per clientId
ServiceState m_serviceState;
bool m_bFetchNSService;
//<! group --> MQProducer;
typedef map<string, MQProducer*> MQPMAP;
boost::mutex m_producerTableMutex;
MQPMAP m_producerTable;
//<! group --> MQConsumer;
typedef map<string, MQConsumer*> MQCMAP;
// Changed to recursive mutex due to avoid deadlock issue:
boost::recursive_mutex m_consumerTableMutex;
MQCMAP m_consumerTable;
//<! Topic---> TopicRouteData
typedef map<string, TopicRouteData*> TRDMAP;
boost::mutex m_topicRouteTableMutex;
TRDMAP m_topicRouteTable;
//<!-----brokerName
//<! ------brokerid;
//<! ------add;
boost::mutex m_brokerAddrlock;
typedef map<string, map<int, string>> BrokerAddrMAP;
BrokerAddrMAP m_brokerAddrTable;
//<!topic ---->TopicPublishInfo> ;
typedef map<string, boost::shared_ptr<TopicPublishInfo>> TPMap;
boost::mutex m_topicPublishInfoTableMutex;
TPMap m_topicPublishInfoTable;
boost::mutex m_factoryLock;
boost::mutex m_topicPublishInfoLock;
boost::asio::io_service m_async_ioService;
unique_ptr<boost::thread> m_async_service_thread;
boost::asio::io_service m_consumer_async_ioService;
unique_ptr<boost::thread> m_consumer_async_service_thread;
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MQClientManager.h"
#include "Logging.h"
namespace rocketmq {
//<!************************************************************************
MQClientManager::MQClientManager() {}
MQClientManager::~MQClientManager() {
m_factoryTable.clear();
}
MQClientManager* MQClientManager::getInstance() {
static MQClientManager instance;
return &instance;
}
MQClientFactory* MQClientManager::getMQClientFactory(const string& clientId,
int pullThreadNum,
uint64_t tcpConnectTimeout,
uint64_t tcpTransportTryLockTimeout,
string unitName,
bool enableSsl,
const std::string& sslPropertyFile) {
FTMAP::iterator it = m_factoryTable.find(clientId);
if (it != m_factoryTable.end()) {
return it->second;
} else {
MQClientFactory* factory = new MQClientFactory(clientId, pullThreadNum, tcpConnectTimeout,
tcpTransportTryLockTimeout, unitName, enableSsl, sslPropertyFile);
m_factoryTable[clientId] = factory;
return factory;
}
}
void MQClientManager::removeClientFactory(const string& clientId) {
FTMAP::iterator it = m_factoryTable.find(clientId);
if (it != m_factoryTable.end()) {
deleteAndZero(it->second);
m_factoryTable.erase(it);
}
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQCLIENTMANAGER_H__
#define __MQCLIENTMANAGER_H__
#include <map>
#include <string>
#include "Logging.h"
#include "MQClientFactory.h"
namespace rocketmq {
//<!***************************************************************************
class MQClientManager {
public:
virtual ~MQClientManager();
virtual MQClientFactory* getMQClientFactory(const string& clientId,
int pullThreadNum,
uint64_t tcpConnectTimeout,
uint64_t tcpTransportTryLockTimeout,
string unitName,
bool enableSsl,
const std::string& sslPropertyFile);
void removeClientFactory(const string& clientId);
static MQClientManager* getInstance();
private:
MQClientManager();
private:
typedef map<string, MQClientFactory*> FTMAP;
FTMAP m_factoryTable;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "Arg_helper.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
Arg_helper::Arg_helper(int argc, char* argv[]) {
for (int i = 0; i < argc; i++) {
m_args.push_back(argv[i]);
}
}
Arg_helper::Arg_helper(string arg_str_) {
vector<string> v;
UtilAll::Split(v, arg_str_, " ");
m_args.insert(m_args.end(), v.begin(), v.end());
}
string Arg_helper::get_option(int idx_) const {
if ((size_t)idx_ >= m_args.size()) {
return "";
}
return m_args[idx_];
}
bool Arg_helper::is_enable_option(string opt_) const {
for (size_t i = 0; i < m_args.size(); ++i) {
if (opt_ == m_args[i]) {
return true;
}
}
return false;
}
string Arg_helper::get_option_value(string opt_) const {
string ret = "";
for (size_t i = 0; i < m_args.size(); ++i) {
if (opt_ == m_args[i]) {
size_t value_idx = ++i;
if (value_idx >= m_args.size()) {
return ret;
}
ret = m_args[value_idx];
return ret;
}
}
return ret;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef _AsyncArg_H_
#define _AsyncArg_H_
#include "MQMessageQueue.h"
#include "PullAPIWrapper.h"
#include "SubscriptionData.h"
namespace rocketmq {
//<!***************************************************************************
struct AsyncArg {
MQMessageQueue mq;
SubscriptionData subData;
PullAPIWrapper* pPullWrapper;
};
//<!***************************************************************************
} // namespace rocketmq
#endif //<! _AsyncArg_H_

View File

@@ -0,0 +1,192 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "AsyncCallbackWrap.h"
#include "Logging.h"
#include "MQClientAPIImpl.h"
#include "MQDecoder.h"
#include "MQMessageQueue.h"
#include "PullAPIWrapper.h"
#include "PullResultExt.h"
#include "ResponseFuture.h"
namespace rocketmq {
//<!***************************************************************************
AsyncCallbackWrap::AsyncCallbackWrap(AsyncCallback* pAsyncCallback, MQClientAPIImpl* pclientAPI)
: m_pAsyncCallBack(pAsyncCallback), m_pClientAPI(pclientAPI) {}
AsyncCallbackWrap::~AsyncCallbackWrap() {
m_pAsyncCallBack = NULL;
m_pClientAPI = NULL;
}
//<!************************************************************************
SendCallbackWrap::SendCallbackWrap(const string& brokerName,
const MQMessage& msg,
AsyncCallback* pAsyncCallback,
MQClientAPIImpl* pclientAPI)
: AsyncCallbackWrap(pAsyncCallback, pclientAPI), m_msg(msg), m_brokerName(brokerName) {}
void SendCallbackWrap::onException() {
if (m_pAsyncCallBack == NULL)
return;
SendCallback* pCallback = static_cast<SendCallback*>(m_pAsyncCallBack);
if (pCallback) {
unique_ptr<MQException> exception(
new MQException("send msg failed due to wait response timeout or network error", -1, __FILE__, __LINE__));
pCallback->onException(*exception);
if (pCallback->getSendCallbackType() == autoDeleteSendCallback) {
deleteAndZero(pCallback);
}
}
}
void SendCallbackWrap::operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest) {
unique_ptr<RemotingCommand> pResponse(pResponseFuture->getCommand());
if (m_pAsyncCallBack == NULL) {
return;
}
int opaque = pResponseFuture->getOpaque();
SendCallback* pCallback = static_cast<SendCallback*>(m_pAsyncCallBack);
if (!pResponse) {
string err = "unknow reseaon";
if (!pResponseFuture->isSendRequestOK()) {
err = "send request failed";
} else if (pResponseFuture->isTimeOut()) {
// pResponseFuture->setAsyncResponseFlag();
err = "wait response timeout";
}
if (pCallback) {
MQException exception(err, -1, __FILE__, __LINE__);
pCallback->onException(exception);
}
LOG_ERROR("send failed of:%d", pResponseFuture->getOpaque());
} else {
try {
SendResult ret = m_pClientAPI->processSendResponse(m_brokerName, m_msg, pResponse.get());
if (pCallback) {
LOG_DEBUG("operationComplete: processSendResponse success, opaque:%d, maxRetryTime:%d, retrySendTimes:%d",
opaque, pResponseFuture->getMaxRetrySendTimes(), pResponseFuture->getRetrySendTimes());
pCallback->onSuccess(ret);
}
} catch (MQException& e) {
LOG_ERROR("operationComplete: processSendResponse exception: %s", e.what());
// broker may return exception, need consider retry send
int maxRetryTimes = pResponseFuture->getMaxRetrySendTimes();
int retryTimes = pResponseFuture->getRetrySendTimes();
if (pResponseFuture->getAsyncFlag() && retryTimes < maxRetryTimes && maxRetryTimes > 1) {
int64 left_timeout_ms = pResponseFuture->leftTime();
string brokerAddr = pResponseFuture->getBrokerAddr();
const RemotingCommand& requestCommand = pResponseFuture->getRequestCommand();
retryTimes += 1;
LOG_WARN("retry send, opaque:%d, sendTimes:%d, maxRetryTimes:%d, left_timeout:%lld, brokerAddr:%s, msg:%s",
opaque, retryTimes, maxRetryTimes, left_timeout_ms, brokerAddr.data(), m_msg.toString().data());
bool exception_flag = false;
try {
m_pClientAPI->sendMessageAsync(pResponseFuture->getBrokerAddr(), m_brokerName, m_msg,
(RemotingCommand&)requestCommand, pCallback, left_timeout_ms, maxRetryTimes,
retryTimes);
} catch (MQClientException& e) {
LOG_ERROR("retry send exception:%s, opaque:%d, retryTimes:%d, msg:%s, not retry send again", e.what(), opaque,
retryTimes, m_msg.toString().data());
exception_flag = true;
}
if (exception_flag == false) {
return; // send retry again, here need return
}
}
if (pCallback) {
MQException exception("process send response error", -1, __FILE__, __LINE__);
pCallback->onException(exception);
}
}
}
if (pCallback && pCallback->getSendCallbackType() == autoDeleteSendCallback) {
deleteAndZero(pCallback);
}
}
//<!************************************************************************
PullCallbackWrap::PullCallbackWrap(AsyncCallback* pAsyncCallback, MQClientAPIImpl* pclientAPI, void* pArg)
: AsyncCallbackWrap(pAsyncCallback, pclientAPI) {
m_pArg = *static_cast<AsyncArg*>(pArg);
}
PullCallbackWrap::~PullCallbackWrap() {}
void PullCallbackWrap::onException() {
if (m_pAsyncCallBack == NULL)
return;
PullCallback* pCallback = static_cast<PullCallback*>(m_pAsyncCallBack);
if (pCallback) {
MQException exception("wait response timeout", -1, __FILE__, __LINE__);
pCallback->onException(exception);
} else {
LOG_ERROR("PullCallback is NULL, AsyncPull could not continue");
}
}
void PullCallbackWrap::operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest) {
unique_ptr<RemotingCommand> pResponse(pResponseFuture->getCommand());
if (m_pAsyncCallBack == NULL) {
LOG_ERROR("m_pAsyncCallBack is NULL, AsyncPull could not continue");
return;
}
PullCallback* pCallback = static_cast<PullCallback*>(m_pAsyncCallBack);
if (!pResponse) {
string err = "unknow reseaon";
if (!pResponseFuture->isSendRequestOK()) {
err = "send request failed";
} else if (pResponseFuture->isTimeOut()) {
// pResponseFuture->setAsyncResponseFlag();
err = "wait response timeout";
}
MQException exception(err, -1, __FILE__, __LINE__);
LOG_ERROR("Async pull exception of opaque:%d", pResponseFuture->getOpaque());
if (pCallback && bProducePullRequest)
pCallback->onException(exception);
} else {
try {
if (m_pArg.pPullWrapper) {
unique_ptr<PullResult> pullResult(m_pClientAPI->processPullResponse(pResponse.get()));
PullResult result = m_pArg.pPullWrapper->processPullResult(m_pArg.mq, pullResult.get(), &m_pArg.subData);
if (pCallback)
pCallback->onSuccess(m_pArg.mq, result, bProducePullRequest);
} else {
LOG_ERROR("pPullWrapper had been destroyed with consumer");
}
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
MQException exception("pullResult error", -1, __FILE__, __LINE__);
if (pCallback && bProducePullRequest)
pCallback->onException(exception);
}
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __ASYNCCALLBACKWRAP_H__
#define __ASYNCCALLBACKWRAP_H__
#include "AsyncArg.h"
#include "AsyncCallback.h"
#include "MQMessage.h"
#include "RemotingCommand.h"
#include "UtilAll.h"
namespace rocketmq {
class ResponseFuture;
class MQClientAPIImpl;
// class DefaultMQProducer;
//<!***************************************************************************
enum asyncCallBackType { asyncCallbackWrap = 0, sendCallbackWrap = 1, pullCallbackWrap = 2 };
struct AsyncCallbackWrap {
public:
AsyncCallbackWrap(AsyncCallback* pAsyncCallback, MQClientAPIImpl* pclientAPI);
virtual ~AsyncCallbackWrap();
virtual void operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest) = 0;
virtual void onException() = 0;
virtual asyncCallBackType getCallbackType() = 0;
protected:
AsyncCallback* m_pAsyncCallBack;
MQClientAPIImpl* m_pClientAPI;
};
//<!************************************************************************
class SendCallbackWrap : public AsyncCallbackWrap {
public:
SendCallbackWrap(const string& brokerName,
const MQMessage& msg,
AsyncCallback* pAsyncCallback,
MQClientAPIImpl* pClientAPI);
virtual ~SendCallbackWrap(){};
virtual void operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest);
virtual void onException();
virtual asyncCallBackType getCallbackType() { return sendCallbackWrap; }
private:
MQMessage m_msg;
string m_brokerName;
};
//<!***************************************************************************
class PullCallbackWrap : public AsyncCallbackWrap {
public:
PullCallbackWrap(AsyncCallback* pAsyncCallback, MQClientAPIImpl* pClientAPI, void* pArg);
virtual ~PullCallbackWrap();
virtual void operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest);
virtual void onException();
virtual asyncCallBackType getCallbackType() { return pullCallbackWrap; }
private:
AsyncArg m_pArg;
};
//<!***************************************************************************
} // namespace rocketmq
#endif // __ASYNCCALLBACKWRAP_H__

View File

@@ -0,0 +1,217 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef BYTEORDER_H_INCLUDED
#define BYTEORDER_H_INCLUDED
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <boost/detail/endian.hpp>
#include "RocketMQClient.h"
#include "UtilAll.h"
//==============================================================================
/** Contains static methods for converting the byte order between different
endiannesses.
*/
namespace rocketmq {
class ROCKETMQCLIENT_API ByteOrder {
public:
//==============================================================================
/** Swaps the upper and lower bytes of a 16-bit integer. */
static uint16 swap(uint16 value);
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static uint32 swap(uint32 value);
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static uint64 swap(uint64 value);
//==============================================================================
/** Swaps the byte order of a 16-bit int if the CPU is big-endian */
static uint16 swapIfBigEndian(uint16 value);
/** Swaps the byte order of a 32-bit int if the CPU is big-endian */
static uint32 swapIfBigEndian(uint32 value);
/** Swaps the byte order of a 64-bit int if the CPU is big-endian */
static uint64 swapIfBigEndian(uint64 value);
/** Swaps the byte order of a 16-bit int if the CPU is little-endian */
static uint16 swapIfLittleEndian(uint16 value);
/** Swaps the byte order of a 32-bit int if the CPU is little-endian */
static uint32 swapIfLittleEndian(uint32 value);
/** Swaps the byte order of a 64-bit int if the CPU is little-endian */
static uint64 swapIfLittleEndian(uint64 value);
//==============================================================================
/** Turns 4 bytes into a little-endian integer. */
static uint32 littleEndianInt(const void* bytes);
/** Turns 8 bytes into a little-endian integer. */
static uint64 littleEndianInt64(const void* bytes);
/** Turns 2 bytes into a little-endian integer. */
static uint16 littleEndianShort(const void* bytes);
/** Turns 4 bytes into a big-endian integer. */
static uint32 bigEndianInt(const void* bytes);
/** Turns 8 bytes into a big-endian integer. */
static uint64 bigEndianInt64(const void* bytes);
/** Turns 2 bytes into a big-endian integer. */
static uint16 bigEndianShort(const void* bytes);
//==============================================================================
/** Converts 3 little-endian bytes into a signed 24-bit value (which is
* sign-extended to 32 bits). */
static int littleEndian24Bit(const void* bytes);
/** Converts 3 big-endian bytes into a signed 24-bit value (which is
* sign-extended to 32 bits). */
static int bigEndian24Bit(const void* bytes);
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars(int value, void* destBytes);
/** Copies a 24-bit number to 3 big-endian bytes. */
static void bigEndian24BitToChars(int value, void* destBytes);
//==============================================================================
/** Returns true if the current CPU is big-endian. */
static bool isBigEndian();
};
//==============================================================================
inline uint16 ByteOrder::swap(uint16 n) {
return static_cast<uint16>((n << 8) | (n >> 8));
}
inline uint32 ByteOrder::swap(uint32 n) {
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
}
inline uint64 ByteOrder::swap(uint64 value) {
return (((uint64)swap((uint32)value)) << 32) | swap((uint32)(value >> 32));
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ //__BYTE_ORDER__ is defined by GCC
inline uint16 ByteOrder::swapIfBigEndian(const uint16 v) {
return v;
}
inline uint32 ByteOrder::swapIfBigEndian(const uint32 v) {
return v;
}
inline uint64 ByteOrder::swapIfBigEndian(const uint64 v) {
return v;
}
inline uint16 ByteOrder::swapIfLittleEndian(const uint16 v) {
return swap(v);
}
inline uint32 ByteOrder::swapIfLittleEndian(const uint32 v) {
return swap(v);
}
inline uint64 ByteOrder::swapIfLittleEndian(const uint64 v) {
return swap(v);
}
inline uint32 ByteOrder::littleEndianInt(const void* const bytes) {
return *static_cast<const uint32*>(bytes);
}
inline uint64 ByteOrder::littleEndianInt64(const void* const bytes) {
return *static_cast<const uint64*>(bytes);
}
inline uint16 ByteOrder::littleEndianShort(const void* const bytes) {
return *static_cast<const uint16*>(bytes);
}
inline uint32 ByteOrder::bigEndianInt(const void* const bytes) {
return swap(*static_cast<const uint32*>(bytes));
}
inline uint64 ByteOrder::bigEndianInt64(const void* const bytes) {
return swap(*static_cast<const uint64*>(bytes));
}
inline uint16 ByteOrder::bigEndianShort(const void* const bytes) {
return swap(*static_cast<const uint16*>(bytes));
}
inline bool ByteOrder::isBigEndian() {
return false;
}
#else
inline uint16 ByteOrder::swapIfBigEndian(const uint16 v) {
return swap(v);
}
inline uint32 ByteOrder::swapIfBigEndian(const uint32 v) {
return swap(v);
}
inline uint64 ByteOrder::swapIfBigEndian(const uint64 v) {
return swap(v);
}
inline uint16 ByteOrder::swapIfLittleEndian(const uint16 v) {
return v;
}
inline uint32 ByteOrder::swapIfLittleEndian(const uint32 v) {
return v;
}
inline uint64 ByteOrder::swapIfLittleEndian(const uint64 v) {
return v;
}
inline uint32 ByteOrder::littleEndianInt(const void* const bytes) {
return swap(*static_cast<const uint32*>(bytes));
}
inline uint64 ByteOrder::littleEndianInt64(const void* const bytes) {
return swap(*static_cast<const uint64*>(bytes));
}
inline uint16 ByteOrder::littleEndianShort(const void* const bytes) {
return swap(*static_cast<const uint16*>(bytes));
}
inline uint32 ByteOrder::bigEndianInt(const void* const bytes) {
return *static_cast<const uint32*>(bytes);
}
inline uint64 ByteOrder::bigEndianInt64(const void* const bytes) {
return *static_cast<const uint64*>(bytes);
}
inline uint16 ByteOrder::bigEndianShort(const void* const bytes) {
return *static_cast<const uint16*>(bytes);
}
inline bool ByteOrder::isBigEndian() {
return true;
}
#endif
inline int ByteOrder::littleEndian24Bit(const void* const bytes) {
return (((int)static_cast<const int8*>(bytes)[2]) << 16) | (((int)static_cast<const uint8*>(bytes)[1]) << 8) |
((int)static_cast<const uint8*>(bytes)[0]);
}
inline int ByteOrder::bigEndian24Bit(const void* const bytes) {
return (((int)static_cast<const int8*>(bytes)[0]) << 16) | (((int)static_cast<const uint8*>(bytes)[1]) << 8) |
((int)static_cast<const uint8*>(bytes)[2]);
}
inline void ByteOrder::littleEndian24BitToChars(const int value, void* const destBytes) {
static_cast<uint8*>(destBytes)[0] = (uint8)value;
static_cast<uint8*>(destBytes)[1] = (uint8)(value >> 8);
static_cast<uint8*>(destBytes)[2] = (uint8)(value >> 16);
}
inline void ByteOrder::bigEndian24BitToChars(const int value, void* const destBytes) {
static_cast<uint8*>(destBytes)[0] = (uint8)(value >> 16);
static_cast<uint8*>(destBytes)[1] = (uint8)(value >> 8);
static_cast<uint8*>(destBytes)[2] = (uint8)value;
}
} // namespace rocketmq
#endif // BYTEORDER_H_INCLUDED

View File

@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "ClientRPCHook.h"
#include "CommandHeader.h"
#include "Logging.h"
extern "C" {
#include "spas_client.h"
}
#include "string"
namespace rocketmq {
const string SessionCredentials::AccessKey = "AccessKey";
const string SessionCredentials::SecretKey = "SecretKey";
const string SessionCredentials::Signature = "Signature";
const string SessionCredentials::SignatureMethod = "SignatureMethod";
const string SessionCredentials::ONSChannelKey = "OnsChannel";
void ClientRPCHook::doBeforeRequest(const string& remoteAddr, RemotingCommand& request) {
CommandHeader* header = request.getCommandHeader();
map<string, string> requestMap;
string totalMsg;
requestMap.insert(pair<string, string>(SessionCredentials::AccessKey, sessionCredentials.getAccessKey()));
requestMap.insert(pair<string, string>(SessionCredentials::ONSChannelKey, sessionCredentials.getAuthChannel()));
LOG_DEBUG("before insert declared filed,MAP SIZE is:" SIZET_FMT "", requestMap.size());
if (header != NULL) {
header->SetDeclaredFieldOfCommandHeader(requestMap);
}
LOG_DEBUG("after insert declared filed, MAP SIZE is:" SIZET_FMT "", requestMap.size());
map<string, string>::iterator it = requestMap.begin();
for (; it != requestMap.end(); ++it) {
totalMsg.append(it->second);
}
if (request.getMsgBody().length() > 0) {
LOG_DEBUG("msgBody is:%s, msgBody length is:" SIZET_FMT "", request.getMsgBody().c_str(),
request.getMsgBody().length());
totalMsg.append(request.getMsgBody());
}
LOG_DEBUG("total msg info are:%s, size is:" SIZET_FMT "", totalMsg.c_str(), totalMsg.size());
char* pSignature =
rocketmqSignature::spas_sign(totalMsg.c_str(), totalMsg.size(), sessionCredentials.getSecretKey().c_str());
// char *pSignature = spas_sign(totalMsg.c_str(),
// sessionCredentials.getSecretKey().c_str());
if (pSignature != NULL) {
string signature(static_cast<const char*>(pSignature));
request.addExtField(SessionCredentials::Signature, signature);
request.addExtField(SessionCredentials::AccessKey, sessionCredentials.getAccessKey());
request.addExtField(SessionCredentials::ONSChannelKey, sessionCredentials.getAuthChannel());
rocketmqSignature::spas_mem_free(pSignature);
} else {
LOG_ERROR("signature for request failed");
}
}
} // namespace rocketmq

View File

@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __CLIENTRPCHOOK_H__
#define __CLIENTRPCHOOK_H__
#include "RemotingCommand.h"
#include "SessionCredentials.h"
namespace rocketmq {
class RPCHook {
public:
RPCHook() {}
virtual ~RPCHook() {}
virtual void doBeforeRequest(const string& remoteAddr, RemotingCommand& request) = 0;
virtual void doAfterResponse(RemotingCommand& request, RemotingCommand& response) = 0;
};
class ClientRPCHook : public RPCHook {
private:
SessionCredentials sessionCredentials;
public:
ClientRPCHook(const SessionCredentials& session_credentials) : sessionCredentials(session_credentials) {}
virtual ~ClientRPCHook() {}
virtual void doBeforeRequest(const string& remoteAddr, RemotingCommand& request);
virtual void doAfterResponse(RemotingCommand& request, RemotingCommand& response) {}
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __COMMUNICATIONMODE_H__
#define __COMMUNICATIONMODE_H__
namespace rocketmq {
//<!***************************************************************************
enum CommunicationMode { ComMode_SYNC, ComMode_ASYNC, ComMode_ONEWAY };
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,275 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "DefaultMQClient.h"
#include "Logging.h"
#include "MQClientFactory.h"
#include "MQClientManager.h"
#include "NameSpaceUtil.h"
#include "TopicPublishInfo.h"
#include "UtilAll.h"
namespace rocketmq {
// hard code first.
#define ROCKETMQCPP_VERSION "2.2.0"
#define BUILD_DATE "17:30:34 03-26-2020"
// display version: strings bin/librocketmq.so |grep VERSION
const char* rocketmq_build_time = "CPP CORE VERSION: " ROCKETMQCPP_VERSION ", BUILD TIME: " BUILD_DATE;
//<!************************************************************************
DefaultMQClient::DefaultMQClient() {
string NAMESRV_ADDR_ENV = "NAMESRV_ADDR";
if (const char* addr = getenv(NAMESRV_ADDR_ENV.c_str()))
m_namesrvAddr = addr;
else
m_namesrvAddr = "";
m_instanceName = "DEFAULT";
m_nameSpace = "";
m_clientFactory = NULL;
m_serviceState = CREATE_JUST;
m_pullThreadNum = std::thread::hardware_concurrency();
m_tcpConnectTimeout = 3000; // 3s
m_tcpTransportTryLockTimeout = 3; // 3s
m_unitName = "";
m_messageTrace = false;
}
DefaultMQClient::~DefaultMQClient() {}
string DefaultMQClient::getMQClientId() const {
string clientIP = UtilAll::getLocalAddress();
string processId = UtilAll::to_string(getpid());
// return processId + "-" + clientIP + "@" + m_instanceName;
return clientIP + "@" + processId + "#" + m_instanceName;
}
// version
string DefaultMQClient::getClientVersionString() const {
string version(rocketmq_build_time);
return version;
}
//<!groupName;
const string& DefaultMQClient::getGroupName() const {
return m_GroupName;
}
void DefaultMQClient::setGroupName(const string& groupname) {
m_GroupName = groupname;
}
const string& DefaultMQClient::getNamesrvAddr() const {
return m_namesrvAddr;
}
void DefaultMQClient::setNamesrvAddr(const string& namesrvAddr) {
m_namesrvAddr = NameSpaceUtil::formatNameServerURL(namesrvAddr);
}
const string& DefaultMQClient::getNamesrvDomain() const {
return m_namesrvDomain;
}
void DefaultMQClient::setNamesrvDomain(const string& namesrvDomain) {
m_namesrvDomain = namesrvDomain;
}
const string& DefaultMQClient::getInstanceName() const {
return m_instanceName;
}
void DefaultMQClient::setInstanceName(const string& instanceName) {
m_instanceName = instanceName;
}
const string& DefaultMQClient::getNameSpace() const {
return m_nameSpace;
}
void DefaultMQClient::setNameSpace(const string& nameSpace) {
m_nameSpace = nameSpace;
}
void DefaultMQClient::createTopic(const string& key, const string& newTopic, int queueNum) {
try {
getFactory()->createTopic(key, newTopic, queueNum, m_SessionCredentials);
} catch (MQException& e) {
LOG_ERROR(e.what());
}
}
int64 DefaultMQClient::earliestMsgStoreTime(const MQMessageQueue& mq) {
return getFactory()->earliestMsgStoreTime(mq, m_SessionCredentials);
}
QueryResult DefaultMQClient::queryMessage(const string& topic, const string& key, int maxNum, int64 begin, int64 end) {
return getFactory()->queryMessage(topic, key, maxNum, begin, end, m_SessionCredentials);
}
int64 DefaultMQClient::minOffset(const MQMessageQueue& mq) {
return getFactory()->minOffset(mq, m_SessionCredentials);
}
int64 DefaultMQClient::maxOffset(const MQMessageQueue& mq) {
return getFactory()->maxOffset(mq, m_SessionCredentials);
}
int64 DefaultMQClient::searchOffset(const MQMessageQueue& mq, uint64_t timestamp) {
return getFactory()->searchOffset(mq, timestamp, m_SessionCredentials);
}
MQMessageExt* DefaultMQClient::viewMessage(const string& msgId) {
return getFactory()->viewMessage(msgId, m_SessionCredentials);
}
vector<MQMessageQueue> DefaultMQClient::getTopicMessageQueueInfo(const string& topic) {
boost::weak_ptr<TopicPublishInfo> weak_topicPublishInfo(
getFactory()->tryToFindTopicPublishInfo(topic, m_SessionCredentials));
boost::shared_ptr<TopicPublishInfo> topicPublishInfo(weak_topicPublishInfo.lock());
if (topicPublishInfo) {
return topicPublishInfo->getMessageQueueList();
}
THROW_MQEXCEPTION(MQClientException, "could not find MessageQueue Info of topic: [" + topic + "].", -1);
}
void DefaultMQClient::start() {
if (getFactory() == NULL) {
m_clientFactory = MQClientManager::getInstance()->getMQClientFactory(
getMQClientId(), m_pullThreadNum, m_tcpConnectTimeout, m_tcpTransportTryLockTimeout, m_unitName, m_enableSsl,
m_sslPropertyFile);
}
LOG_INFO(
"MQClient "
"start,groupname:%s,clientID:%s,instanceName:%s,nameserveraddr:%s",
getGroupName().c_str(), getMQClientId().c_str(), getInstanceName().c_str(), getNamesrvAddr().c_str());
}
void DefaultMQClient::shutdown() {
m_clientFactory->shutdown();
m_clientFactory = NULL;
}
MQClientFactory* DefaultMQClient::getFactory() const {
return m_clientFactory;
}
void DefaultMQClient::setFactory(MQClientFactory* factory) {
m_clientFactory = factory;
}
bool DefaultMQClient::isServiceStateOk() {
return m_serviceState == RUNNING;
}
void DefaultMQClient::setLogLevel(elogLevel inputLevel) {
ALOG_ADAPTER->setLogLevel(inputLevel);
}
elogLevel DefaultMQClient::getLogLevel() {
return ALOG_ADAPTER->getLogLevel();
}
void DefaultMQClient::setLogFileSizeAndNum(int fileNum, long perFileSize) {
ALOG_ADAPTER->setLogFileNumAndSize(fileNum, perFileSize);
}
void DefaultMQClient::setTcpTransportPullThreadNum(int num) {
if (num > m_pullThreadNum) {
m_pullThreadNum = num;
}
}
int DefaultMQClient::getTcpTransportPullThreadNum() const {
return m_pullThreadNum;
}
void DefaultMQClient::setTcpTransportConnectTimeout(uint64_t timeout) {
m_tcpConnectTimeout = timeout;
}
uint64_t DefaultMQClient::getTcpTransportConnectTimeout() const {
return m_tcpConnectTimeout;
}
void DefaultMQClient::setTcpTransportTryLockTimeout(uint64_t timeout) {
if (timeout < 1000) {
timeout = 1000;
}
m_tcpTransportTryLockTimeout = timeout / 1000;
}
uint64_t DefaultMQClient::getTcpTransportTryLockTimeout() const {
return m_tcpTransportTryLockTimeout;
}
void DefaultMQClient::setUnitName(string unitName) {
m_unitName = unitName;
}
const string& DefaultMQClient::getUnitName() const {
return m_unitName;
}
bool DefaultMQClient::getMessageTrace() const {
return m_messageTrace;
}
void DefaultMQClient::setMessageTrace(bool mMessageTrace) {
m_messageTrace = mMessageTrace;
}
void DefaultMQClient::setSessionCredentials(const string& input_accessKey,
const string& input_secretKey,
const string& input_onsChannel) {
m_SessionCredentials.setAccessKey(input_accessKey);
m_SessionCredentials.setSecretKey(input_secretKey);
m_SessionCredentials.setAuthChannel(input_onsChannel);
}
const SessionCredentials& DefaultMQClient::getSessionCredentials() const {
return m_SessionCredentials;
}
void DefaultMQClient::setEnableSsl(bool enableSsl) {
m_enableSsl = enableSsl;
}
bool DefaultMQClient::getEnableSsl() const {
return m_enableSsl;
}
void DefaultMQClient::setSslPropertyFile(const std::string& sslPropertyFile) {
m_sslPropertyFile = sslPropertyFile;
}
const std::string& DefaultMQClient::getSslPropertyFile() const {
return m_sslPropertyFile;
}
void DefaultMQClient::showClientConfigs() {
// LOG_WARN("*****************************************************************************");
LOG_WARN("ClientID:%s", getMQClientId().c_str());
LOG_WARN("GroupName:%s", m_GroupName.c_str());
LOG_WARN("NameServer:%s", m_namesrvAddr.c_str());
LOG_WARN("NameServerDomain:%s", m_namesrvDomain.c_str());
LOG_WARN("NameSpace:%s", m_nameSpace.c_str());
LOG_WARN("InstanceName:%s", m_instanceName.c_str());
LOG_WARN("UnitName:%s", m_unitName.c_str());
LOG_WARN("PullThreadNum:%d", m_pullThreadNum);
LOG_WARN("TcpConnectTimeout:%lld ms", m_tcpConnectTimeout);
LOG_WARN("TcpTransportTryLockTimeout:%lld s", m_tcpTransportTryLockTimeout);
LOG_WARN("EnableSsl:%s", m_enableSsl ? "true" : "false");
LOG_WARN("SslPropertyFile:%s", m_sslPropertyFile.c_str());
LOG_WARN("OpenMessageTrace:%s", m_messageTrace ? "true" : "false");
// LOG_WARN("*****************************************************************************");
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __FILTERAPI_H__
#define __FILTERAPI_H__
#include <string>
#include "MQClientException.h"
#include "SubscriptionData.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
class FilterAPI {
public:
static SubscriptionData* buildSubscriptionData(const string topic, const string& subString) {
//<!delete in balance;
SubscriptionData* subscriptionData = new SubscriptionData(topic, subString);
if (subString.empty() || !subString.compare(SUB_ALL)) {
subscriptionData->setSubString(SUB_ALL);
} else {
vector<string> out;
UtilAll::Split(out, subString, "||");
if (out.empty()) {
THROW_MQEXCEPTION(MQClientException, "FilterAPI subString split error", -1);
}
for (size_t i = 0; i < out.size(); i++) {
string tag = out[i];
if (!tag.empty()) {
UtilAll::Trim(tag);
if (!tag.empty()) {
subscriptionData->putTagsSet(tag);
subscriptionData->putCodeSet(tag);
}
}
}
}
return subscriptionData;
}
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "InputStream.h"
#include <algorithm>
#include "MemoryOutputStream.h"
#include "big_endian.h"
namespace rocketmq {
int64 InputStream::getNumBytesRemaining() {
int64 len = getTotalLength();
if (len >= 0)
len -= getPosition();
return len;
}
char InputStream::readByte() {
char temp = 0;
read(&temp, 1);
return temp;
}
bool InputStream::readBool() {
return readByte() != 0;
}
short InputStream::readShortBigEndian() {
char temp[2];
if (read(temp, 2) == 2) {
short int v;
ReadBigEndian(temp, &v);
return v;
}
return 0;
}
int InputStream::readIntBigEndian() {
char temp[4];
if (read(temp, 4) == 4) {
int v;
ReadBigEndian(temp, &v);
return v;
}
return 0;
}
int64 InputStream::readInt64BigEndian() {
char asBytes[8];
uint64 asInt64;
if (read(asBytes, 8) == 8) {
ReadBigEndian(asBytes, &asInt64);
return asInt64;
}
return 0;
}
float InputStream::readFloatBigEndian() {
union {
int32 asInt;
float asFloat;
} n;
n.asInt = (int32)readIntBigEndian();
return n.asFloat;
}
double InputStream::readDoubleBigEndian() {
union {
int64 asInt;
double asDouble;
} n;
n.asInt = readInt64BigEndian();
return n.asDouble;
}
size_t InputStream::readIntoMemoryBlock(MemoryBlock& block, size_t numBytes) {
MemoryOutputStream mo(block, true);
return (size_t)mo.writeFromInputStream(*this, numBytes);
}
//==============================================================================
void InputStream::skipNextBytes(int64 numBytesToSkip) {
if (numBytesToSkip > 0) {
const int skipBufferSize = (int)std::min(numBytesToSkip, (int64)16384);
char* temp = static_cast<char*>(std::malloc(skipBufferSize * sizeof(char)));
while (numBytesToSkip > 0 && !isExhausted())
numBytesToSkip -= read(temp, (int)std::min(numBytesToSkip, (int64)skipBufferSize));
std::free(temp);
}
}
} // namespace rocketmq

View File

@@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef INPUTSTREAM_H_INCLUDED
#define INPUTSTREAM_H_INCLUDED
#include "dataBlock.h"
//==============================================================================
/** The base class for streams that read data.
Input and output streams are used throughout the library - subclasses can
override
some or all of the virtual functions to implement their behaviour.
@see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream
*/
namespace rocketmq {
class ROCKETMQCLIENT_API InputStream {
public:
/** Destructor. */
virtual ~InputStream() {}
//==============================================================================
/** Returns the total number of bytes available for reading in this stream.
Note that this is the number of bytes available from the start of the
stream, not from the current position.
If the size of the stream isn't actually known, this will return -1.
@see getNumBytesRemaining
*/
virtual int64 getTotalLength() = 0;
/** Returns the number of bytes available for reading, or a negative value if
the remaining length is not known.
@see getTotalLength
*/
int64 getNumBytesRemaining();
/** Returns true if the stream has no more data to read. */
virtual bool isExhausted() = 0;
//==============================================================================
/** Reads some data from the stream into a memory buffer.
This is the only read method that subclasses actually need to implement,
as the
InputStream base class implements the other read methods in terms of this
one (although
it's often more efficient for subclasses to implement them directly).
@param destBuffer the destination buffer for the data. This must not
be null.
@param maxBytesToRead the maximum number of bytes to read - make sure
the
memory block passed in is big enough to contain
this
many bytes. This value must not be negative.
@returns the actual number of bytes that were read, which may be less
than
maxBytesToRead if the stream is exhausted before it gets that
far
*/
virtual int read(void* destBuffer, int maxBytesToRead) = 0;
/** Reads a byte from the stream.
If the stream is exhausted, this will return zero.
@see OutputStream::writeByte
*/
virtual char readByte();
/** Reads a boolean from the stream.
The bool is encoded as a single byte - non-zero for true, 0 for false.
If the stream is exhausted, this will return false.
@see OutputStream::writeBool
*/
virtual bool readBool();
/** Reads two bytes from the stream as a little-endian 16-bit value.
If the next two bytes read are byte1 and byte2, this returns (byte2 |
(byte1 << 8)).
If the stream is exhausted partway through reading the bytes, this will
return zero.
@see OutputStream::writeShortBigEndian, readShort
*/
virtual short readShortBigEndian();
/** Reads four bytes from the stream as a big-endian 32-bit value.
If the next four bytes are byte1 to byte4, this returns
(byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)).
If the stream is exhausted partway through reading the bytes, this will
return zero.
@see OutputStream::writeIntBigEndian, readInt
*/
virtual int readIntBigEndian();
/** Reads eight bytes from the stream as a big-endian 64-bit value.
If the next eight bytes are byte1 to byte8, this returns
(byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) |
(byte3 << 40) | (byte2 << 48) | (byte1 << 56)).
If the stream is exhausted partway through reading the bytes, this will
return zero.
@see OutputStream::writeInt64BigEndian, readInt64
*/
virtual int64 readInt64BigEndian();
/** Reads four bytes as a 32-bit floating point value.
The raw 32-bit encoding of the float is read from the stream as a
big-endian int.
If the stream is exhausted partway through reading the bytes, this will
return zero.
@see OutputStream::writeFloatBigEndian, readDoubleBigEndian
*/
virtual float readFloatBigEndian();
/** Reads eight bytes as a 64-bit floating point value.
The raw 64-bit encoding of the double is read from the stream as a
big-endian int64.
If the stream is exhausted partway through reading the bytes, this will
return zero.
@see OutputStream::writeDoubleBigEndian, readFloatBigEndian
*/
virtual double readDoubleBigEndian();
//==============================================================================whole
// stream and turn it into a string.
/** Reads from the stream and appends the data to a MemoryBlock.
@param destBlock the block to append the data onto
@param maxNumBytesToRead if this is a positive value, it sets a limit
to the number
of bytes that will be read - if it's negative,
data
will be read until the stream is exhausted.
@returns the number of bytes that were added to the memory block
*/
virtual size_t readIntoMemoryBlock(MemoryBlock& destBlock, size_t maxNumBytesToRead = -1);
//==============================================================================
/** Returns the offset of the next byte that will be read from the stream.
@see setPosition
*/
virtual int64 getPosition() = 0;
/** Tries to move the current read position of the stream.
The position is an absolute number of bytes from the stream's start.
Some streams might not be able to do this, in which case they should do
nothing and return false. Others might be able to manage it by resetting
themselves and skipping to the correct position, although this is
obviously a bit slow.
@returns true if the stream manages to reposition itself correctly
@see getPosition
*/
virtual bool setPosition(int64 newPosition) = 0;
/** Reads and discards a number of bytes from the stream.
Some input streams might implement this efficiently, but the base
class will just keep reading data until the requisite number of bytes
have been done.
*/
virtual void skipNextBytes(int64 numBytesToSkip);
protected:
//==============================================================================
InputStream() {}
};
} // namespace rocketmq
#endif // INPUTSTREAM_H_INCLUDED

View File

@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MQClientErrorContainer.h"
namespace rocketmq {
thread_local std::string MQClientErrorContainer::t_err;
void MQClientErrorContainer::setErr(const std::string& str) {
t_err = str;
}
const std::string& MQClientErrorContainer::getErr() {
return t_err;
}
} // namespace rocketmq

View File

@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQ_CLIENT_ERROR_CONTAINER_H__
#define __MQ_CLIENT_ERROR_CONTAINER_H__
#include <mutex>
#include <string>
namespace rocketmq {
class MQClientErrorContainer {
public:
static void setErr(const std::string& str);
static const std::string& getErr();
private:
static thread_local std::string t_err;
};
} // namespace rocketmq
#endif // __MQ_CLIENT_ERROR_CONTAINER_H__

View File

@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MQVersion.h"
namespace rocketmq {
int MQVersion::s_CurrentVersion = MQVersion::V4_6_0;
std::string MQVersion::s_CurrentLanguage = "CPP";
//<!************************************************************************
const char* MQVersion::GetVersionDesc(int value) {
int currentVersion = value;
if (value <= V3_0_0_SNAPSHOT) {
currentVersion = V3_0_0_SNAPSHOT;
}
if (value >= HIGHER_VERSION) {
currentVersion = HIGHER_VERSION;
}
return RocketMQCPPClientVersion[currentVersion];
}
//<!***************************************************************************
} // namespace rocketmq

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MemoryInputStream.h"
namespace rocketmq {
MemoryInputStream::MemoryInputStream(const void* const sourceData,
const size_t sourceDataSize,
const bool keepInternalCopy)
: data(sourceData), dataSize(sourceDataSize), position(0), internalCopy(NULL) {
if (keepInternalCopy)
createInternalCopy();
}
MemoryInputStream::MemoryInputStream(const MemoryBlock& sourceData, const bool keepInternalCopy)
: data(sourceData.getData()), dataSize(sourceData.getSize()), position(0), internalCopy(NULL) {
if (keepInternalCopy)
createInternalCopy();
}
void MemoryInputStream::createInternalCopy() {
std::free(internalCopy);
internalCopy = static_cast<char*>(std::malloc(dataSize));
memcpy(internalCopy, data, dataSize);
data = internalCopy;
}
MemoryInputStream::~MemoryInputStream() {
std::free(internalCopy);
}
int64 MemoryInputStream::getTotalLength() {
return (int64)dataSize;
}
int MemoryInputStream::read(void* const buffer, const int howMany) {
const int num = std::min(howMany, (int)(dataSize - position));
if (num <= 0)
return 0;
memcpy((char*)buffer, (char*)data + position, (size_t)num);
position += (unsigned int)num;
return num;
}
bool MemoryInputStream::isExhausted() {
return position >= dataSize;
}
bool MemoryInputStream::setPosition(const int64 pos) {
if (pos < 0)
position = 0;
else
position = (int64)dataSize < pos ? (int64)dataSize : pos;
return true;
}
int64 MemoryInputStream::getPosition() {
return (int64)position;
}
} // namespace rocketmq

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef MEMORYINPUTSTREAM_H_INCLUDED
#define MEMORYINPUTSTREAM_H_INCLUDED
#include "InputStream.h"
namespace rocketmq {
//==============================================================================
/**
Allows a block of data to be accessed as a stream.
This can either be used to refer to a shared block of memory, or can make
its
own internal copy of the data when the MemoryInputStream is created.
*/
class ROCKETMQCLIENT_API MemoryInputStream : public InputStream {
public:
//==============================================================================
/** Creates a MemoryInputStream.
@param sourceData the block of data to use as the stream's
source
@param sourceDataSize the number of bytes in the source data
block
@param keepInternalCopyOfData if false, the stream will just keep a
pointer to
the source data, so this data shouldn't be
changed
for the lifetime of the stream; if this
parameter is
true, the stream will make its own copy of
the
data and use that.
*/
MemoryInputStream(const void* sourceData, size_t sourceDataSize, bool keepInternalCopyOfData);
/** Creates a MemoryInputStream.
@param data a block of data to use as the stream's
source
@param keepInternalCopyOfData if false, the stream will just keep a
reference to
the source data, so this data shouldn't be
changed
for the lifetime of the stream; if this
parameter is
true, the stream will make its own copy of
the
data and use that.
*/
MemoryInputStream(const MemoryBlock& data, bool keepInternalCopyOfData);
/** Destructor. */
~MemoryInputStream();
/** Returns a pointer to the source data block from which this stream is
* reading. */
const void* getData() const { return data; }
/** Returns the number of bytes of source data in the block from which this
* stream is reading. */
size_t getDataSize() const { return dataSize; }
//==============================================================================
int64 getPosition();
bool setPosition(int64 pos);
int64 getTotalLength();
bool isExhausted();
int read(void* destBuffer, int maxBytesToRead);
private:
//==============================================================================
const void* data;
size_t dataSize, position;
char* internalCopy;
void createInternalCopy();
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,156 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MemoryOutputStream.h"
namespace rocketmq {
MemoryOutputStream::MemoryOutputStream(const size_t initialSize)
: blockToUse(&internalBlock), externalData(NULL), position(0), size(0), availableSize(0) {
internalBlock.setSize(initialSize, false);
}
MemoryOutputStream::MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo, const bool appendToExistingBlockContent)
: blockToUse(&memoryBlockToWriteTo), externalData(NULL), position(0), size(0), availableSize(0) {
if (appendToExistingBlockContent)
position = size = memoryBlockToWriteTo.getSize();
}
MemoryOutputStream::MemoryOutputStream(void* destBuffer, size_t destBufferSize)
: blockToUse(NULL), externalData(destBuffer), position(0), size(0), availableSize(destBufferSize) {}
MemoryOutputStream::~MemoryOutputStream() {
trimExternalBlockSize();
}
void MemoryOutputStream::flush() {
trimExternalBlockSize();
}
void MemoryOutputStream::trimExternalBlockSize() {
if (blockToUse != &internalBlock && blockToUse != NULL)
blockToUse->setSize(size, false);
}
void MemoryOutputStream::preallocate(const size_t bytesToPreallocate) {
if (blockToUse != NULL)
blockToUse->ensureSize(bytesToPreallocate + 1);
}
void MemoryOutputStream::reset() {
position = 0;
size = 0;
}
char* MemoryOutputStream::prepareToWrite(size_t numBytes) {
size_t storageNeeded = position + numBytes;
char* data;
if (blockToUse != NULL) {
if (storageNeeded >= (unsigned int)(blockToUse->getSize()))
blockToUse->ensureSize((storageNeeded + std::min(storageNeeded / 2, (size_t)(1024 * 1024)) + 32) & ~31u);
data = static_cast<char*>(blockToUse->getData());
} else {
if (storageNeeded > availableSize)
return NULL;
data = static_cast<char*>(externalData);
}
char* const writePointer = data + position;
position += numBytes;
size = std::max(size, position);
return writePointer;
}
bool MemoryOutputStream::write(const void* const buffer, size_t howMany) {
if (howMany == 0)
return true;
if (char* dest = prepareToWrite(howMany)) {
memcpy(dest, buffer, howMany);
return true;
}
return false;
}
bool MemoryOutputStream::writeRepeatedByte(uint8 byte, size_t howMany) {
if (howMany == 0)
return true;
if (char* dest = prepareToWrite(howMany)) {
memset(dest, byte, howMany);
return true;
}
return false;
}
MemoryBlock MemoryOutputStream::getMemoryBlock() const {
return MemoryBlock(getData(), getDataSize());
}
const void* MemoryOutputStream::getData() const {
if (blockToUse == NULL)
return externalData;
if ((unsigned int)blockToUse->getSize() > size)
static_cast<char*>(blockToUse->getData())[size] = 0;
return blockToUse->getData();
}
bool MemoryOutputStream::setPosition(int64 newPosition) {
if (newPosition <= (int64)size) {
// ok to seek backwards
if (newPosition < 0)
position = 0;
else
position = (int64)size < newPosition ? size : newPosition;
return true;
}
// can't move beyond the end of the stream..
return false;
}
int64 MemoryOutputStream::writeFromInputStream(InputStream& source, int64 maxNumBytesToWrite) {
// before writing from an input, see if we can preallocate to make it more
// efficient..
int64 availableData = source.getTotalLength() - source.getPosition();
if (availableData > 0) {
if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0)
maxNumBytesToWrite = availableData;
if (blockToUse != NULL)
preallocate(blockToUse->getSize() + (size_t)maxNumBytesToWrite);
}
return OutputStream::writeFromInputStream(source, maxNumBytesToWrite);
}
OutputStream& operator<<(OutputStream& stream, const MemoryOutputStream& streamToRead) {
const size_t dataSize = streamToRead.getDataSize();
if (dataSize > 0)
stream.write(streamToRead.getData(), dataSize);
return stream;
}
} // namespace rocketmq

View File

@@ -0,0 +1,130 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef MEMORYOUTPUTSTREAM_H_INCLUDED
#define MEMORYOUTPUTSTREAM_H_INCLUDED
#include "OutputStream.h"
namespace rocketmq {
//==============================================================================
/**
Writes data to an internal memory buffer, which grows as required.
The data that was written into the stream can then be accessed later as
a contiguous block of memory.
*/
class ROCKETMQCLIENT_API MemoryOutputStream : public OutputStream {
public:
//==============================================================================
/** Creates an empty memory stream, ready to be written into.
@param initialSize the intial amount of capacity to allocate for writing
into
*/
MemoryOutputStream(size_t initialSize = 256);
/** Creates a memory stream for writing into into a pre-existing MemoryBlock
object.
Note that the destination block will always be larger than the amount of
data
that has been written to the stream, because the MemoryOutputStream keeps
some
spare capactity at its end. To trim the block's size down to fit the
actual
data, call flush(), or delete the MemoryOutputStream.
@param memoryBlockToWriteTo the block into which new data will
be written.
@param appendToExistingBlockContent if this is true, the contents of
the block will be
kept, and new data will be
appended to it. If false,
the block will be cleared before
use
*/
MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo, bool appendToExistingBlockContent);
/** Creates a MemoryOutputStream that will write into a user-supplied,
fixed-size
block of memory.
When using this mode, the stream will write directly into this memory area
until
it's full, at which point write operations will fail.
*/
MemoryOutputStream(void* destBuffer, size_t destBufferSize);
/** Destructor.
This will free any data that was written to it.
*/
~MemoryOutputStream();
//==============================================================================
/** Returns a pointer to the data that has been written to the stream.
@see getDataSize
*/
const void* getData() const;
/** Returns the number of bytes of data that have been written to the stream.
@see getData
*/
size_t getDataSize() const { return size; }
/** Resets the stream, clearing any data that has been written to it so far.
*/
void reset();
/** Increases the internal storage capacity to be able to contain at least the
specified
amount of data without needing to be resized.
*/
void preallocate(size_t bytesToPreallocate);
/** Returns a copy of the stream's data as a memory block. */
MemoryBlock getMemoryBlock() const;
//==============================================================================
/** If the stream is writing to a user-supplied MemoryBlock, this will trim
any excess
capacity off the block, so that its length matches the amount of actual
data that
has been written so far.
*/
void flush();
bool write(const void*, size_t);
int64 getPosition() { return (int64)position; }
bool setPosition(int64);
int64 writeFromInputStream(InputStream&, int64 maxNumBytesToWrite);
bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat);
private:
//==============================================================================
MemoryBlock* const blockToUse;
MemoryBlock internalBlock;
void* externalData;
size_t position, size, availableSize;
void trimExternalBlockSize();
char* prepareToWrite(size_t);
};
/** Copies all the data that has been written to a MemoryOutputStream into
* another stream. */
OutputStream& operator<<(OutputStream& stream, const MemoryOutputStream& streamToRead);
} // namespace rocketmq
#endif // MEMORYOUTPUTSTREAM_H_INCLUDED

View File

@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MessageAccessor.h"
#include <functional>
#include <vector>
#include "Logging.h"
#include "NameSpaceUtil.h"
using namespace std;
namespace rocketmq {
void MessageAccessor::withNameSpace(MQMessage& msg, const string nameSpace) {
if (!nameSpace.empty()) {
string originTopic = msg.getTopic();
string newTopic = nameSpace + NAMESPACE_SPLIT_FLAG + originTopic;
msg.setTopic(newTopic);
}
}
void MessageAccessor::withoutNameSpaceSingle(MQMessageExt& msg, const string nameSpace) {
if (!nameSpace.empty()) {
string originTopic = msg.getTopic();
auto index = originTopic.find(nameSpace);
if (index != string::npos) {
string newTopic =
originTopic.substr(index + nameSpace.length() + NAMESPACE_SPLIT_FLAG.length(), originTopic.length());
msg.setTopic(newTopic);
LOG_DEBUG("Find Name Space Prefix in MessageID[%s], OriginTopic[%s], NewTopic[%s]", msg.getMsgId().c_str(),
originTopic.c_str(), newTopic.c_str());
}
}
}
void MessageAccessor::withoutNameSpace(vector<MQMessageExt>& msgs, const string nameSpace) {
if (!nameSpace.empty()) {
// for_each(msgs.cbegin(), msgs.cend(), bind2nd(&MessageAccessor::withoutNameSpaceSingle, nameSpace));
for (auto iter = msgs.begin(); iter != msgs.end(); iter++) {
withoutNameSpaceSingle(*iter, nameSpace);
}
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MESSAGE_ACCESSOR_H__
#define __MESSAGE_ACCESSOR_H__
#include <string>
#include <vector>
#include "MQMessage.h"
#include "MQMessageExt.h"
namespace rocketmq {
//<!***************************************************************************
class MessageAccessor {
public:
static void withNameSpace(MQMessage& msg, const std::string nameSpace);
static void withoutNameSpaceSingle(MQMessageExt& msg, const std::string nameSpace);
static void withoutNameSpace(std::vector<MQMessageExt>& msgs, const std::string nameSpace);
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "MessageSysFlag.h"
namespace rocketmq {
int MessageSysFlag::CompressedFlag = (0x1 << 0);
int MessageSysFlag::MultiTagsFlag = (0x1 << 1);
int MessageSysFlag::TransactionNotType = (0x0 << 2);
int MessageSysFlag::TransactionPreparedType = (0x1 << 2);
int MessageSysFlag::TransactionCommitType = (0x2 << 2);
int MessageSysFlag::TransactionRollbackType = (0x3 << 2);
int MessageSysFlag::getTransactionValue(int flag) {
return flag & TransactionRollbackType;
}
int MessageSysFlag::resetTransactionValue(int flag, int type) {
return (flag & (~TransactionRollbackType)) | type;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MESSAGESYSFLAG_H__
#define __MESSAGESYSFLAG_H__
namespace rocketmq {
//<!************************************************************************
class MessageSysFlag {
public:
static int getTransactionValue(int flag);
static int resetTransactionValue(int flag, int type);
public:
static int CompressedFlag;
static int MultiTagsFlag;
static int TransactionNotType;
static int TransactionPreparedType;
static int TransactionCommitType;
static int TransactionRollbackType;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "NameSpaceUtil.h"
#include "Logging.h"
#include "TraceContant.h"
namespace rocketmq {
bool NameSpaceUtil::isEndPointURL(string nameServerAddr) {
if (nameServerAddr.length() >= ENDPOINT_PREFIX_LENGTH && nameServerAddr.find(ENDPOINT_PREFIX) != string::npos) {
return true;
}
return false;
}
string NameSpaceUtil::formatNameServerURL(string nameServerAddr) {
auto index = nameServerAddr.find(ENDPOINT_PREFIX);
if (index != string::npos) {
LOG_DEBUG("Get Name Server from endpoint [%s]",
nameServerAddr.substr(ENDPOINT_PREFIX_LENGTH, nameServerAddr.length() - ENDPOINT_PREFIX_LENGTH).c_str());
return nameServerAddr.substr(ENDPOINT_PREFIX_LENGTH, nameServerAddr.length() - ENDPOINT_PREFIX_LENGTH);
}
return nameServerAddr;
}
string NameSpaceUtil::getNameSpaceFromNsURL(string nameServerAddr) {
LOG_DEBUG("Try to get Name Space from nameServerAddr [%s]", nameServerAddr.c_str());
string nsAddr = formatNameServerURL(nameServerAddr);
string nameSpace;
auto index = nsAddr.find(NAMESPACE_PREFIX);
if (index != string::npos) {
auto indexDot = nsAddr.find('.');
if (indexDot != string::npos && indexDot > index) {
nameSpace = nsAddr.substr(index, indexDot - index);
LOG_INFO("Get Name Space [%s] from nameServerAddr [%s]", nameSpace.c_str(), nameServerAddr.c_str());
return nameSpace;
}
}
return "";
}
bool NameSpaceUtil::checkNameSpaceExistInNsURL(string nameServerAddr) {
if (!isEndPointURL(nameServerAddr)) {
LOG_DEBUG("This nameServerAddr [%s] is not a endpoint. should not get Name Space.", nameServerAddr.c_str());
return false;
}
auto index = nameServerAddr.find(NAMESPACE_PREFIX);
if (index != string::npos) {
LOG_INFO("Find Name Space Prefix in nameServerAddr [%s]", nameServerAddr.c_str());
return true;
}
return false;
}
bool NameSpaceUtil::checkNameSpaceExistInNameServer(string nameServerAddr) {
auto index = nameServerAddr.find(NAMESPACE_PREFIX);
if (index != string::npos) {
LOG_INFO("Find Name Space Prefix in nameServerAddr [%s]", nameServerAddr.c_str());
return true;
}
return false;
}
string NameSpaceUtil::withoutNameSpace(string source, string nameSpace) {
if (!nameSpace.empty()) {
auto index = source.find(nameSpace);
if (index != string::npos) {
return source.substr(index + nameSpace.length() + NAMESPACE_SPLIT_FLAG.length(), source.length());
}
}
return source;
}
string NameSpaceUtil::withNameSpace(string source, string ns) {
if (!ns.empty()) {
return ns + NAMESPACE_SPLIT_FLAG + source;
}
return source;
}
bool NameSpaceUtil::hasNameSpace(string source, string ns) {
if (source.find(TraceContant::TRACE_TOPIC) != string::npos) {
LOG_DEBUG("Find Trace Topic [%s]", source.c_str());
return true;
}
if (!ns.empty() && source.length() >= ns.length() && source.find(ns) != string::npos) {
return true;
}
return false;
}
} // namespace rocketmq

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __NAMESPACEUTIL_H__
#define __NAMESPACEUTIL_H__
#include <string>
using namespace std;
static const string ENDPOINT_PREFIX = "http://";
static const unsigned int ENDPOINT_PREFIX_LENGTH = ENDPOINT_PREFIX.length();
static const string NAMESPACE_PREFIX = "MQ_INST_";
static const int NAMESPACE_PREFIX_LENGTH = NAMESPACE_PREFIX.length();
static const string NAMESPACE_SPLIT_FLAG = "%";
namespace rocketmq {
class NameSpaceUtil {
public:
static bool isEndPointURL(string nameServerAddr);
static string formatNameServerURL(string nameServerAddr);
static string getNameSpaceFromNsURL(string nameServerAddr);
static bool checkNameSpaceExistInNsURL(string nameServerAddr);
static bool checkNameSpaceExistInNameServer(string nameServerAddr);
static string withNameSpace(string source, string ns);
static string withoutNameSpace(string source, string ns);
static bool hasNameSpace(string source, string ns);
};
} // namespace rocketmq
#endif //__NAMESPACEUTIL_H__

View File

@@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __NAMESRVCONFIG_H__
#define __NAMESRVCONFIG_H__
#include <stdlib.h>
#include <string>
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
class NamesrvConfig {
public:
NamesrvConfig() {
m_kvConfigPath = "";
char* home = getenv(rocketmq::ROCKETMQ_HOME_ENV.c_str());
if (home) {
m_rocketmqHome = home;
} else {
m_rocketmqHome = "";
}
}
const string& getRocketmqHome() const { return m_rocketmqHome; }
void setRocketmqHome(const string& rocketmqHome) { m_rocketmqHome = rocketmqHome; }
const string& getKvConfigPath() const { return m_kvConfigPath; }
void setKvConfigPath(const string& kvConfigPath) { m_kvConfigPath = kvConfigPath; }
private:
string m_rocketmqHome;
string m_kvConfigPath;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "OutputStream.h"
#include <limits>
#include "big_endian.h"
namespace rocketmq {
//==============================================================================
OutputStream::OutputStream() {}
OutputStream::~OutputStream() {}
//==============================================================================
bool OutputStream::writeBool(const bool b) {
return writeByte(b ? (char)1 : (char)0);
}
bool OutputStream::writeByte(char byte) {
return write(&byte, 1);
}
bool OutputStream::writeRepeatedByte(uint8 byte, size_t numTimesToRepeat) {
for (size_t i = 0; i < numTimesToRepeat; ++i)
if (!writeByte((char)byte))
return false;
return true;
}
bool OutputStream::writeShortBigEndian(short value) {
unsigned short v;
char pShort[sizeof(v)];
WriteBigEndian(pShort, (unsigned short)value);
return write(pShort, 2);
}
bool OutputStream::writeIntBigEndian(int value) {
unsigned int v;
char pInt[sizeof(v)];
WriteBigEndian(pInt, (unsigned int)value);
return write(pInt, 4);
}
bool OutputStream::writeInt64BigEndian(int64 value) {
uint64 v;
char pUint64[sizeof(v)];
WriteBigEndian(pUint64, (uint64)value);
return write(pUint64, 8);
}
bool OutputStream::writeFloatBigEndian(float value) {
union {
int asInt;
float asFloat;
} n;
n.asFloat = value;
return writeIntBigEndian(n.asInt);
}
bool OutputStream::writeDoubleBigEndian(double value) {
union {
int64 asInt;
double asDouble;
} n;
n.asDouble = value;
return writeInt64BigEndian(n.asInt);
}
int64 OutputStream::writeFromInputStream(InputStream& source, int64 numBytesToWrite) {
if (numBytesToWrite < 0)
numBytesToWrite = std::numeric_limits<int64>::max();
int64 numWritten = 0;
while (numBytesToWrite > 0) {
char buffer[8192];
const int num = source.read(buffer, (int)std::min(numBytesToWrite, (int64)sizeof(buffer)));
if (num <= 0)
break;
write(buffer, (size_t)num);
numBytesToWrite -= num;
numWritten += num;
}
return numWritten;
}
} // namespace rocketmq

View File

@@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef OUTPUTSTREAM_H_INCLUDED
#define OUTPUTSTREAM_H_INCLUDED
#include "InputStream.h"
namespace rocketmq {
//==============================================================================
/**
The base class for streams that write data to some kind of destination.
Input and output streams are used throughout the library - subclasses can
override
some or all of the virtual functions to implement their behaviour.
@see InputStream, MemoryOutputStream, FileOutputStream
*/
class ROCKETMQCLIENT_API OutputStream {
protected:
//==============================================================================
OutputStream();
public:
/** Destructor.
Some subclasses might want to do things like call flush() during their
destructors.
*/
virtual ~OutputStream();
//==============================================================================
/** If the stream is using a buffer, this will ensure it gets written
out to the destination. */
virtual void flush() = 0;
/** Tries to move the stream's output position.
Not all streams will be able to seek to a new position - this will return
false if it fails to work.
@see getPosition
*/
virtual bool setPosition(int64 newPosition) = 0;
/** Returns the stream's current position.
@see setPosition
*/
virtual int64 getPosition() = 0;
//==============================================================================
/** Writes a block of data to the stream.
When creating a subclass of OutputStream, this is the only write method
that needs to be overloaded - the base class has methods for writing other
types of data which use this to do the work.
@param dataToWrite the target buffer to receive the data. This must
not be null.
@param numberOfBytes the number of bytes to write.
@returns false if the write operation fails for some reason
*/
virtual bool write(const void* dataToWrite, size_t numberOfBytes) = 0;
//==============================================================================
/** Writes a single byte to the stream.
@returns false if the write operation fails for some reason
@see InputStream::readByte
*/
virtual bool writeByte(char byte);
/** Writes a boolean to the stream as a single byte.
This is encoded as a binary byte (not as text) with a value of 1 or 0.
@returns false if the write operation fails for some reason
@see InputStream::readBool
*/
virtual bool writeBool(bool boolValue);
/** Writes a 16-bit integer to the stream in a big-endian byte order.
This will write two bytes to the stream: (value >> 8), then (value &
0xff).
@returns false if the write operation fails for some reason
@see InputStream::readShortBigEndian
*/
virtual bool writeShortBigEndian(short value);
/** Writes a 32-bit integer to the stream in a big-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readIntBigEndian
*/
virtual bool writeIntBigEndian(int value);
/** Writes a 64-bit integer to the stream in a big-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readInt64BigEndian
*/
virtual bool writeInt64BigEndian(int64 value);
/** Writes a 32-bit floating point value to the stream in a binary format.
The binary 32-bit encoding of the float is written as a big-endian int.
@returns false if the write operation fails for some reason
@see InputStream::readFloatBigEndian
*/
virtual bool writeFloatBigEndian(float value);
/** Writes a 64-bit floating point value to the stream in a binary format.
The eight raw bytes of the double value are written out as a big-endian
64-bit int.
@see InputStream::readDoubleBigEndian
@returns false if the write operation fails for some reason
*/
virtual bool writeDoubleBigEndian(double value);
/** Writes a byte to the output stream a given number of times.
@returns false if the write operation fails for some reason
*/
virtual bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat);
/** Reads data from an input stream and writes it to this stream.
@param source the stream to read from
@param maxNumBytesToWrite the number of bytes to read from the stream
(if this is
less than zero, it will keep reading until the
input
is exhausted)
@returns the number of bytes written
*/
virtual int64 writeFromInputStream(InputStream& source, int64 maxNumBytesToWrite);
};
} // namespace rocketmq
#endif // OUTPUTSTREAM_H_INCLUDED

View File

@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PermName.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
int PermName::PERM_PRIORITY = 0x1 << 3;
int PermName::PERM_READ = 0x1 << 2;
int PermName::PERM_WRITE = 0x1 << 1;
int PermName::PERM_INHERIT = 0x1 << 0;
bool PermName::isReadable(int perm) {
return (perm & PERM_READ) == PERM_READ;
}
bool PermName::isWriteable(int perm) {
return (perm & PERM_WRITE) == PERM_WRITE;
}
bool PermName::isInherited(int perm) {
return (perm & PERM_INHERIT) == PERM_INHERIT;
}
string PermName::perm2String(int perm) {
string pm("---");
if (isReadable(perm)) {
pm.replace(0, 1, "R");
}
if (isWriteable(perm)) {
pm.replace(1, 2, "W");
}
if (isInherited(perm)) {
pm.replace(2, 3, "X");
}
return pm;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __PERMNAME_H__
#define __PERMNAME_H__
#include <string>
namespace rocketmq {
//<!***************************************************************************
class PermName {
public:
static int PERM_PRIORITY;
static int PERM_READ;
static int PERM_WRITE;
static int PERM_INHERIT;
static bool isReadable(int perm);
static bool isWriteable(int perm);
static bool isInherited(int perm);
static std::string perm2String(int perm);
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PullSysFlag.h"
namespace rocketmq {
//<!************************************************************************
int PullSysFlag::FLAG_COMMIT_OFFSET = 0x1 << 0;
int PullSysFlag::FLAG_SUSPEND = 0x1 << 1;
int PullSysFlag::FLAG_SUBSCRIPTION = 0x1 << 2;
int PullSysFlag::FLAG_CLASS_FILTER = 0x1 << 3;
int PullSysFlag::buildSysFlag(bool commitOffset, bool suspend, bool subscription, bool classFilter) {
int flag = 0;
if (commitOffset) {
flag |= FLAG_COMMIT_OFFSET;
}
if (suspend) {
flag |= FLAG_SUSPEND;
}
if (subscription) {
flag |= FLAG_SUBSCRIPTION;
}
if (classFilter) {
flag |= FLAG_CLASS_FILTER;
}
return flag;
}
int PullSysFlag::clearCommitOffsetFlag(int sysFlag) {
return sysFlag & (~FLAG_COMMIT_OFFSET);
}
bool PullSysFlag::hasCommitOffsetFlag(int sysFlag) {
return (sysFlag & FLAG_COMMIT_OFFSET) == FLAG_COMMIT_OFFSET;
}
bool PullSysFlag::hasSuspendFlag(int sysFlag) {
return (sysFlag & FLAG_SUSPEND) == FLAG_SUSPEND;
}
bool PullSysFlag::hasSubscriptionFlag(int sysFlag) {
return (sysFlag & FLAG_SUBSCRIPTION) == FLAG_SUBSCRIPTION;
}
bool PullSysFlag::hasClassFilterFlag(int sysFlag) {
return (sysFlag & FLAG_CLASS_FILTER) == FLAG_CLASS_FILTER;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __PULLSYSFLAG_H__
#define __PULLSYSFLAG_H__
namespace rocketmq {
//<!************************************************************************
class PullSysFlag {
public:
static int buildSysFlag(bool commitOffset, bool suspend, bool subscription, bool classFilter);
static int clearCommitOffsetFlag(int sysFlag);
static bool hasCommitOffsetFlag(int sysFlag);
static bool hasSuspendFlag(int sysFlag);
static bool hasSubscriptionFlag(int sysFlag);
static bool hasClassFilterFlag(int sysFlag);
private:
static int FLAG_COMMIT_OFFSET;
static int FLAG_SUSPEND;
static int FLAG_SUBSCRIPTION;
static int FLAG_CLASS_FILTER;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __SERVICESTATE_H__
#define __SERVICESTATE_H__
namespace rocketmq {
//<!***************************************************************************
enum ServiceState { CREATE_JUST, RUNNING, SHUTDOWN_ALREADY, START_FAILED };
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __SUBSCRIPTIONGROUPCONFIG_H__
#define __SUBSCRIPTIONGROUPCONFIG_H__
#include <string>
namespace rocketmq {
//<!***************************************************************************
class SubscriptionGroupConfig {
public:
SubscriptionGroupConfig(const string& groupName) {
this->groupName = groupName;
consumeEnable = true;
consumeFromMinEnable = true;
consumeBroadcastEnable = true;
retryQueueNums = 1;
retryMaxTimes = 5;
brokerId = MASTER_ID;
whichBrokerWhenConsumeSlowly = 1;
}
string groupName;
bool consumeEnable;
bool consumeFromMinEnable;
bool consumeBroadcastEnable;
int retryQueueNums;
int retryMaxTimes;
int brokerId;
int whichBrokerWhenConsumeSlowly;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "TopAddressing.h"
#include <vector>
#include "UtilAll.h"
#include "sync_http_client.h"
#include "url.h"
namespace rocketmq {
TopAddressing::TopAddressing(string unitName) : m_unitName(unitName) {}
TopAddressing::~TopAddressing() {}
int TopAddressing::IsIPAddr(const char* sValue) {
if (NULL == sValue)
return -1;
while (*sValue != '\0') {
if ((*sValue < '0' || *sValue > '9') && (*sValue != '.'))
return -1;
sValue++;
}
return 0;
}
void TopAddressing::updateNameServerAddressList(const string& adds) {
boost::lock_guard<boost::mutex> lock(m_addrLock);
vector<string> out;
UtilAll::Split(out, adds, ";");
if (out.size() > 0)
m_addrs.clear();
for (size_t i = 0; i < out.size(); i++) {
string addr = out[i];
UtilAll::Trim(addr);
list<string>::iterator findit = find(m_addrs.begin(), m_addrs.end(), addr);
if (findit == m_addrs.end()) {
string hostName;
short portNumber;
if (UtilAll::SplitURL(addr, hostName, portNumber)) {
LOG_INFO("updateNameServerAddressList:%s", addr.c_str());
m_addrs.push_back(addr);
}
}
}
}
string TopAddressing::fetchNSAddr(const string& NSDomain) {
LOG_DEBUG("fetchNSAddr begin");
string nsAddr = NSDomain.empty() ? WS_ADDR : NSDomain;
if (!m_unitName.empty()) {
nsAddr = nsAddr + "-" + m_unitName + "?nofix=1";
LOG_INFO("NSAddr is:%s", nsAddr.c_str());
}
std::string tmp_nameservers;
std::string nameservers;
Url url_s(nsAddr);
LOG_INFO("fetchNSAddr protocol: %s, port: %s, host:%s, path:%s, ", url_s.protocol_.c_str(), url_s.port_.c_str(),
url_s.host_.c_str(), url_s.path_.c_str());
bool ret = SyncfetchNsAddr(url_s, tmp_nameservers);
if (ret) {
nameservers = clearNewLine(tmp_nameservers);
if (nameservers.empty()) {
LOG_ERROR("fetchNSAddr with domain is empty");
} else {
updateNameServerAddressList(nameservers);
}
} else {
LOG_ERROR("fetchNSAddr with domain failed, connect failure or wrong response");
}
return nameservers;
}
string TopAddressing::clearNewLine(const string& str) {
string newString = str;
size_t index = newString.find("\r");
if (index != string::npos) {
return newString.substr(0, index);
}
index = newString.find("\n");
if (index != string::npos) {
return newString.substr(0, index);
}
return newString;
}
} // namespace rocketmq

View File

@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __TOPADDRESSING_H__
#define __TOPADDRESSING_H__
#include <boost/thread/thread.hpp>
#include <list>
#include <map>
#include <string>
#include "Logging.h"
#include "UtilAll.h"
namespace rocketmq {
class TopAddressing {
public:
TopAddressing(string unitName);
virtual ~TopAddressing();
public:
virtual string fetchNSAddr(const string& NSDomain);
private:
string clearNewLine(const string& str);
void updateNameServerAddressList(const string& adds);
int IsIPAddr(const char* sValue);
private:
boost::mutex m_addrLock;
list<string> m_addrs;
string m_unitName;
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "TopicConfig.h"
#include <stdlib.h>
#include <sstream>
#include "PermName.h"
namespace rocketmq {
//<!***************************************************************************
int TopicConfig::DefaultReadQueueNums = 16;
int TopicConfig::DefaultWriteQueueNums = 16;
string TopicConfig::SEPARATOR = " ";
TopicConfig::TopicConfig()
: m_topicName(""),
m_readQueueNums(DefaultReadQueueNums),
m_writeQueueNums(DefaultWriteQueueNums),
m_perm(PermName::PERM_READ | PermName::PERM_WRITE),
m_topicFilterType(SINGLE_TAG) {}
TopicConfig::TopicConfig(const string& topicName)
: m_topicName(topicName),
m_readQueueNums(DefaultReadQueueNums),
m_writeQueueNums(DefaultWriteQueueNums),
m_perm(PermName::PERM_READ | PermName::PERM_WRITE),
m_topicFilterType(SINGLE_TAG) {}
TopicConfig::TopicConfig(const string& topicName, int readQueueNums, int writeQueueNums, int perm)
: m_topicName(topicName),
m_readQueueNums(readQueueNums),
m_writeQueueNums(writeQueueNums),
m_perm(perm),
m_topicFilterType(SINGLE_TAG) {}
TopicConfig::~TopicConfig() {}
string TopicConfig::encode() {
stringstream ss;
ss << m_topicName << SEPARATOR << m_readQueueNums << SEPARATOR << m_writeQueueNums << SEPARATOR << m_perm << SEPARATOR
<< m_topicFilterType;
return ss.str();
}
bool TopicConfig::decode(const string& in) {
stringstream ss(in);
ss >> m_topicName;
ss >> m_readQueueNums;
ss >> m_writeQueueNums;
ss >> m_perm;
int type;
ss >> type;
m_topicFilterType = (TopicFilterType)type;
return true;
}
const string& TopicConfig::getTopicName() {
return m_topicName;
}
void TopicConfig::setTopicName(const string& topicName) {
m_topicName = topicName;
}
int TopicConfig::getReadQueueNums() {
return m_readQueueNums;
}
void TopicConfig::setReadQueueNums(int readQueueNums) {
m_readQueueNums = readQueueNums;
}
int TopicConfig::getWriteQueueNums() {
return m_writeQueueNums;
}
void TopicConfig::setWriteQueueNums(int writeQueueNums) {
m_writeQueueNums = writeQueueNums;
}
int TopicConfig::getPerm() {
return m_perm;
}
void TopicConfig::setPerm(int perm) {
m_perm = perm;
}
TopicFilterType TopicConfig::getTopicFilterType() {
return m_topicFilterType;
}
void TopicConfig::setTopicFilterType(TopicFilterType topicFilterType) {
m_topicFilterType = topicFilterType;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __TOPICCONFIG_H__
#define __TOPICCONFIG_H__
#include <string>
#include "TopicFilterType.h"
#include "UtilAll.h"
namespace rocketmq {
//<!************************************************************************
class TopicConfig {
public:
TopicConfig();
TopicConfig(const string& topicName);
TopicConfig(const string& topicName, int readQueueNums, int writeQueueNums, int perm);
~TopicConfig();
string encode();
bool decode(const string& in);
const string& getTopicName();
void setTopicName(const string& topicName);
int getReadQueueNums();
void setReadQueueNums(int readQueueNums);
int getWriteQueueNums();
void setWriteQueueNums(int writeQueueNums);
int getPerm();
void setPerm(int perm);
TopicFilterType getTopicFilterType();
void setTopicFilterType(TopicFilterType topicFilterType);
public:
static int DefaultReadQueueNums;
static int DefaultWriteQueueNums;
private:
static string SEPARATOR;
string m_topicName;
int m_readQueueNums;
int m_writeQueueNums;
int m_perm;
TopicFilterType m_topicFilterType;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __TOPICFILTERTYPE_H__
#define __TOPICFILTERTYPE_H__
namespace rocketmq {
//<!***************************************************************************
enum TopicFilterType {
/**
* each msg could only have one tag
*/
SINGLE_TAG,
/**
* not support now
*/
MULTI_TAG
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,386 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "UtilAll.h"
#include <chrono>
namespace rocketmq {
//<!************************************************************************
std::string UtilAll::s_localHostName;
std::string UtilAll::s_localIpAddress;
bool UtilAll::startsWith_retry(const string& topic) {
return topic.find(RETRY_GROUP_TOPIC_PREFIX) == 0;
}
string UtilAll::getRetryTopic(const string& consumerGroup) {
return RETRY_GROUP_TOPIC_PREFIX + consumerGroup;
}
void UtilAll::Trim(string& str) {
str.erase(0, str.find_first_not_of(' ')); // prefixing spaces
str.erase(str.find_last_not_of(' ') + 1); // surfixing spaces
}
bool UtilAll::isBlank(const string& str) {
if (str.empty()) {
return true;
}
string::size_type left = str.find_first_not_of(WHITESPACE);
if (left == string::npos) {
return true;
}
return false;
}
const int hex2int[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
uint64 UtilAll::hexstr2ull(const char* str) {
uint64 num = 0;
unsigned char* ch = (unsigned char*)str;
while (*ch != '\0') {
num = (num << 4) + hex2int[*ch];
ch++;
}
return num;
}
int64 UtilAll::str2ll(const char* str) {
return boost::lexical_cast<int64>(str);
}
string UtilAll::bytes2string(const char* bytes, int len) {
if (bytes == NULL || len <= 0) {
return string();
}
#ifdef WIN32
string buffer;
for (int i = 0; i < len; i++) {
char tmp[3];
sprintf(tmp, "%02X", (unsigned char)bytes[i]);
buffer.append(tmp);
}
return buffer;
#else
static const char hex_str[] = "0123456789ABCDEF";
char result[len * 2 + 1];
result[len * 2] = 0;
for (int i = 0; i < len; i++) {
result[i * 2 + 0] = hex_str[(bytes[i] >> 4) & 0x0F];
result[i * 2 + 1] = hex_str[(bytes[i]) & 0x0F];
}
string buffer(result);
return buffer;
#endif
}
bool UtilAll::SplitURL(const string& serverURL, string& addr, short& nPort) {
size_t pos = serverURL.find(':');
if (pos == string::npos) {
return false;
}
addr = serverURL.substr(0, pos);
if (0 == addr.compare("localhost")) {
addr = "127.0.0.1";
}
pos++;
string port = serverURL.substr(pos, serverURL.length() - pos);
nPort = atoi(port.c_str());
if (nPort == 0) {
return false;
}
return true;
}
int UtilAll::Split(vector<string>& ret_, const string& strIn, const char sep) {
if (strIn.empty())
return 0;
string tmp;
string::size_type pos_begin = strIn.find_first_not_of(sep);
string::size_type comma_pos = 0;
while (pos_begin != string::npos) {
comma_pos = strIn.find(sep, pos_begin);
if (comma_pos != string::npos) {
tmp = strIn.substr(pos_begin, comma_pos - pos_begin);
pos_begin = comma_pos + 1;
} else {
tmp = strIn.substr(pos_begin);
pos_begin = comma_pos;
}
if (!tmp.empty()) {
ret_.push_back(tmp);
tmp.clear();
}
}
return ret_.size();
}
int UtilAll::Split(vector<string>& ret_, const string& strIn, const string& sep) {
if (strIn.empty())
return 0;
string tmp;
string::size_type pos_begin = strIn.find_first_not_of(sep);
string::size_type comma_pos = 0;
while (pos_begin != string::npos) {
comma_pos = strIn.find(sep, pos_begin);
if (comma_pos != string::npos) {
tmp = strIn.substr(pos_begin, comma_pos - pos_begin);
pos_begin = comma_pos + sep.length();
} else {
tmp = strIn.substr(pos_begin);
pos_begin = comma_pos;
}
if (!tmp.empty()) {
ret_.push_back(tmp);
tmp.clear();
}
}
return ret_.size();
}
bool UtilAll::StringToInt32(const std::string& str, int32_t& out) {
out = 0;
if (str.empty()) {
return false;
}
char* end = NULL;
errno = 0;
long l = strtol(str.c_str(), &end, 10);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return false;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return false;
if (*end != '\0')
return false;
out = l;
return true;
}
bool UtilAll::StringToInt64(const std::string& str, int64_t& val) {
char* endptr = NULL;
errno = 0; /* To distinguish success/failure after call */
val = strtoll(str.c_str(), &endptr, 10);
/* Check for various possible errors */
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
return false;
}
/*no digit was found Or Further characters after number*/
if (endptr == str.c_str()) {
return false;
}
/*no digit was found Or Further characters after number*/
if (*endptr != '\0') {
return false;
}
/* If we got here, strtol() successfully parsed a number */
return true;
}
string UtilAll::getLocalHostName() {
if (s_localHostName.empty()) {
// boost::system::error_code error;
// s_localHostName = boost::asio::ip::host_name(error);
char name[1024];
boost::system::error_code ec;
if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) {
return std::string();
}
s_localHostName.append(name, strlen(name));
}
return s_localHostName;
}
string UtilAll::getLocalAddress() {
if (s_localIpAddress.empty()) {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(getLocalHostName(), "");
boost::system::error_code error;
boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query, error);
if (error) {
return "";
}
boost::asio::ip::tcp::resolver::iterator end; // End marker.
boost::asio::ip::tcp::endpoint ep;
while (iter != end) {
ep = *iter++;
}
s_localIpAddress = ep.address().to_string();
}
return s_localIpAddress;
}
string UtilAll::getHomeDirectory() {
#ifndef WIN32
char* homeEnv = getenv("HOME");
string homeDir;
if (homeEnv == NULL) {
homeDir.append(getpwuid(getuid())->pw_dir);
} else {
homeDir.append(homeEnv);
}
#else
string homeDir(getenv("USERPROFILE"));
#endif
return homeDir;
}
string UtilAll::getProcessName() {
#ifndef WIN32
char buf[PATH_MAX + 1] = {0};
int count = PATH_MAX + 1;
char procpath[PATH_MAX + 1] = {0};
sprintf(procpath, "/proc/%d/exe", getpid());
if (access(procpath, F_OK) == -1) {
return "";
}
int retval = readlink(procpath, buf, count - 1);
if ((retval < 0 || retval >= count - 1)) {
return "";
}
if (!strcmp(buf + retval - 10, " (deleted)"))
buf[retval - 10] = '\0'; // remove last " (deleted)"
else
buf[retval] = '\0';
char* process_name = strrchr(buf, '/');
if (process_name) {
return std::string(process_name + 1);
} else {
return "";
}
#else
TCHAR szFileName[MAX_PATH + 1];
GetModuleFileName(NULL, szFileName, MAX_PATH + 1);
return std::string(szFileName);
#endif
}
uint64_t UtilAll::currentTimeMillis() {
auto since_epoch =
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
return static_cast<uint64_t>(since_epoch.count());
}
uint64_t UtilAll::currentTimeSeconds() {
auto since_epoch =
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
return static_cast<uint64_t>(since_epoch.count());
}
bool UtilAll::deflate(std::string& input, std::string& out, int level) {
boost::iostreams::zlib_params zlibParams(level, boost::iostreams::zlib::deflated);
boost::iostreams::filtering_ostream compressingStream;
compressingStream.push(boost::iostreams::zlib_compressor(zlibParams));
compressingStream.push(boost::iostreams::back_inserter(out));
compressingStream << input;
boost::iostreams::close(compressingStream);
return true;
}
bool UtilAll::inflate(std::string& input, std::string& out) {
boost::iostreams::filtering_ostream decompressingStream;
decompressingStream.push(boost::iostreams::zlib_decompressor());
decompressingStream.push(boost::iostreams::back_inserter(out));
decompressingStream << input;
boost::iostreams::close(decompressingStream);
return true;
}
bool UtilAll::ReplaceFile(const std::string& from_path, const std::string& to_path) {
#ifdef WIN32
// Try a simple move first. It will only succeed when |to_path| doesn't
// already exist.
if (::MoveFile(from_path.c_str(), to_path.c_str()))
return true;
// Try the full-blown replace if the move fails, as ReplaceFile will only
// succeed when |to_path| does exist. When writing to a network share, we may
// not be able to change the ACLs. Ignore ACL errors then
// (REPLACEFILE_IGNORE_MERGE_ERRORS).
if (::ReplaceFile(to_path.c_str(), from_path.c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
return true;
}
return false;
#else
if (rename(from_path.c_str(), to_path.c_str()) == 0)
return true;
return false;
#endif
}
std::map<std::string, std::string> UtilAll::ReadProperties(const std::string& path) {
std::map<std::string, std::string> property_map;
std::ifstream property_file;
property_file.open(path);
std::string line_buffer;
if (property_file.is_open()) {
while (!property_file.eof()) {
std::getline(property_file, line_buffer);
std::size_t pos{0};
pos = line_buffer.find('#');
if (pos != string::npos) {
line_buffer = line_buffer.substr(0, pos);
}
if (line_buffer.empty()) {
continue;
}
pos = line_buffer.find('=');
if (pos != string::npos) {
std::string key = boost::trim_copy(line_buffer.substr(0, pos));
std::string value = boost::trim_copy(line_buffer.substr(pos + 1));
property_map[key] = value;
}
}
}
return property_map;
}
} // namespace rocketmq

View File

@@ -0,0 +1,151 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __UTILALL_H__
#define __UTILALL_H__
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <pwd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#endif
#include <boost/algorithm/string/trim.hpp>
#include <boost/asio.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/locale/conversion.hpp>
#include <boost/locale/encoding.hpp>
#include <fstream>
#include <map>
#include <sstream>
#include "RocketMQClient.h"
using namespace std;
namespace rocketmq {
//<!************************************************************************
const string null = "";
const string WHITESPACE = " \t\r\n";
const string SUB_ALL = "*";
const string DEFAULT_TOPIC = "TBW102";
const string BENCHMARK_TOPIC = "BenchmarkTest";
const string DEFAULT_PRODUCER_GROUP = "DEFAULT_PRODUCER";
const string DEFAULT_CONSUMER_GROUP = "DEFAULT_CONSUMER";
const string TOOLS_CONSUMER_GROUP = "TOOLS_CONSUMER";
const string CLIENT_INNER_PRODUCER_GROUP = "CLIENT_INNER_PRODUCER";
const string SELF_TEST_TOPIC = "SELF_TEST_TOPIC";
const string RETRY_GROUP_TOPIC_PREFIX = "%RETRY%";
const string DLQ_GROUP_TOPIC_PREFIX = "%DLQ%";
const string ROCKETMQ_HOME_ENV = "ROCKETMQ_HOME";
const string ROCKETMQ_HOME_PROPERTY = "rocketmq.home.dir";
const string MESSAGE_COMPRESS_LEVEL = "rocketmq.message.compressLevel";
const string DEFAULT_SSL_PROPERTY_FILE = "/etc/rocketmq/tls.properties";
const string DEFAULT_CLIENT_KEY_PASSWD = null;
const string DEFAULT_CLIENT_KEY_FILE = "/etc/rocketmq/client.key";
const string DEFAULT_CLIENT_CERT_FILE = "/etc/rocketmq/client.pem";
const string DEFAULT_CA_CERT_FILE = "/etc/rocketmq/ca.pem";
const string WS_ADDR =
"please set nameserver domain by setDomainName, there is no default "
"nameserver domain";
const int POLL_NAMESERVER_INTEVAL = 1000 * 30;
const int HEARTBEAT_BROKER_INTERVAL = 1000 * 30;
const int PERSIST_CONSUMER_OFFSET_INTERVAL = 1000 * 5;
const int LINE_SEPARATOR = 1; // rocketmq::UtilAll::charToString((char) 1);
const int WORD_SEPARATOR = 2; // rocketmq::UtilAll::charToString((char) 2);
const int HTTP_TIMEOUT = 3000; // 3S
const int HTTP_CONFLICT = 409;
const int HTTP_OK = 200;
const int HTTP_NOTFOUND = 404;
const int CONNETERROR = -1;
const int MASTER_ID = 0;
template <typename Type>
inline void deleteAndZero(Type& pointer) {
delete pointer;
pointer = NULL;
}
#define EMPTY_STR_PTR(ptr) (ptr == NULL || ptr[0] == '\0')
#ifdef WIN32
#define SIZET_FMT "%lu"
#else
#define SIZET_FMT "%zu"
#endif
//<!************************************************************************
class UtilAll {
public:
static bool startsWith_retry(const string& topic);
static string getRetryTopic(const string& consumerGroup);
static void Trim(string& str);
static bool isBlank(const string& str);
static uint64 hexstr2ull(const char* str);
static int64 str2ll(const char* str);
static string bytes2string(const char* bytes, int len);
template <typename T>
static string to_string(const T& n) {
std::ostringstream stm;
stm << n;
return stm.str();
}
static bool to_bool(std::string const& s) { return atoi(s.c_str()); }
static bool SplitURL(const string& serverURL, string& addr, short& nPort);
static int Split(vector<string>& ret_, const string& strIn, const char sep);
static int Split(vector<string>& ret_, const string& strIn, const string& sep);
static bool StringToInt32(const std::string& str, int32_t& out);
static bool StringToInt64(const std::string& str, int64_t& val);
static string getLocalHostName();
static string getLocalAddress();
static string getHomeDirectory();
static string getProcessName();
static uint64_t currentTimeMillis();
static uint64_t currentTimeSeconds();
static bool deflate(std::string& input, std::string& out, int level);
static bool inflate(std::string& input, std::string& out);
// Renames file |from_path| to |to_path|. Both paths must be on the same
// volume, or the function will fail. Destination file will be created
// if it doesn't exist. Prefer this function over Move when dealing with
// temporary files. On Windows it preserves attributes of the target file.
// Returns true on success.
// Returns false on failure..
static bool ReplaceFile(const std::string& from_path, const std::string& to_path);
static std::map<std::string, std::string> ReadProperties(const std::string& path);
private:
static std::string s_localHostName;
static std::string s_localIpAddress;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "Validators.h"
#include <stdio.h>
#include <stdlib.h>
namespace rocketmq {
const string Validators::validPatternStr = "^[a-zA-Z0-9_-]+$";
const int Validators::CHARACTER_MAX_LENGTH = 255;
//<!***************************************************************************
bool Validators::regularExpressionMatcher(const string& origin, const string& patternStr) {
if (UtilAll::isBlank(origin)) {
return false;
}
if (UtilAll::isBlank(patternStr)) {
return true;
}
// Pattern pattern = Pattern.compile(patternStr);
// Matcher matcher = pattern.matcher(origin);
// return matcher.matches();
return true;
}
string Validators::getGroupWithRegularExpression(const string& origin, const string& patternStr) {
/*Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(origin);
while (matcher.find()) {
return matcher.group(0);
}*/
return "";
}
void Validators::checkTopic(const string& topic) {
if (UtilAll::isBlank(topic)) {
THROW_MQEXCEPTION(MQClientException, "the specified topic is blank", -1);
}
if ((int)topic.length() > CHARACTER_MAX_LENGTH) {
THROW_MQEXCEPTION(MQClientException, "the specified topic is longer than topic max length 255.", -1);
}
if (topic == DEFAULT_TOPIC) {
THROW_MQEXCEPTION(MQClientException, "the topic[" + topic + "] is conflict with default topic.", -1);
}
if (!regularExpressionMatcher(topic, validPatternStr)) {
string str;
str = "the specified topic[" + topic + "] contains illegal characters, allowing only" + validPatternStr;
THROW_MQEXCEPTION(MQClientException, str.c_str(), -1);
}
}
void Validators::checkGroup(const string& group) {
if (UtilAll::isBlank(group)) {
THROW_MQEXCEPTION(MQClientException, "the specified group is blank", -1);
}
if (!regularExpressionMatcher(group, validPatternStr)) {
string str;
str = "the specified group[" + group + "] contains illegal characters, allowing only" + validPatternStr;
THROW_MQEXCEPTION(MQClientException, str.c_str(), -1);
}
if ((int)group.length() > CHARACTER_MAX_LENGTH) {
THROW_MQEXCEPTION(MQClientException, "the specified group is longer than group max length 255.", -1);
}
}
void Validators::checkMessage(const MQMessage& msg, int maxMessageSize) {
checkTopic(msg.getTopic());
string body = msg.getBody();
//<!body;
if (body.empty()) {
THROW_MQEXCEPTION(MQClientException, "the message body is empty", -1);
}
if ((int)body.length() > maxMessageSize) {
char info[256];
sprintf(info, "the message body size over max value, MAX: %d", maxMessageSize);
THROW_MQEXCEPTION(MQClientException, info, -1);
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __VALIDATORST_H__
#define __VALIDATORST_H__
#include <string>
#include "MQClientException.h"
#include "MQMessage.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
class Validators {
public:
static bool regularExpressionMatcher(const string& origin, const string& patternStr);
static string getGroupWithRegularExpression(const string& origin, const string& patternStr);
static void checkTopic(const string& topic);
static void checkGroup(const string& group);
static void checkMessage(const MQMessage& msg, int maxMessageSize);
public:
static const string validPatternStr;
static const int CHARACTER_MAX_LENGTH;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "VirtualEnvUtil.h"
#include <stdio.h>
#include <stdlib.h>
#include "UtilAll.h"
namespace rocketmq {
const char* VirtualEnvUtil::VIRTUAL_APPGROUP_PREFIX = "%%PROJECT_%s%%";
//<!***************************************************************************
string VirtualEnvUtil::buildWithProjectGroup(const string& origin, const string& projectGroup) {
if (!UtilAll::isBlank(projectGroup)) {
char prefix[1024];
sprintf(prefix, VIRTUAL_APPGROUP_PREFIX, projectGroup.c_str());
if (origin.find(prefix) == string::npos) {
return origin + prefix;
} else {
return origin;
}
} else {
return origin;
}
}
string VirtualEnvUtil::clearProjectGroup(const string& origin, const string& projectGroup) {
char prefix[1024];
sprintf(prefix, VIRTUAL_APPGROUP_PREFIX, projectGroup.c_str());
auto pos = origin.find(prefix);
if (!UtilAll::isBlank(prefix) && pos != string::npos) {
return origin.substr(0, pos);
} else {
return origin;
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __VIRTUALENVUTIL_H__
#define __VIRTUALENVUTIL_H__
#include <string>
namespace rocketmq {
//<!***************************************************************************
class VirtualEnvUtil {
public:
static std::string buildWithProjectGroup(const std::string& origin, const std::string& projectGroup);
static std::string clearProjectGroup(const std::string& origin, const std::string& projectGroup);
public:
static const char* VIRTUAL_APPGROUP_PREFIX;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,96 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "big_endian.h"
#include <cstdlib>
#include <cstring>
namespace rocketmq {
BigEndianReader::BigEndianReader(const char* buf, size_t len) : ptr_(buf), end_(ptr_ + len) {}
bool BigEndianReader::Skip(size_t len) {
if (ptr_ + len > end_)
return false;
ptr_ += len;
return true;
}
bool BigEndianReader::ReadBytes(void* out, size_t len) {
if (ptr_ + len > end_)
return false;
memcpy(out, ptr_, len);
ptr_ += len;
return true;
}
template <typename T>
bool BigEndianReader::Read(T* value) {
if (ptr_ + sizeof(T) > end_)
return false;
ReadBigEndian<T>(ptr_, value);
ptr_ += sizeof(T);
return true;
}
bool BigEndianReader::ReadU8(uint8_t* value) {
return Read(value);
}
bool BigEndianReader::ReadU16(uint16_t* value) {
return Read(value);
}
bool BigEndianReader::ReadU32(uint32_t* value) {
return Read(value);
}
bool BigEndianReader::ReadU64(uint64_t* value) {
return Read(value);
}
BigEndianWriter::BigEndianWriter(char* buf, size_t len) : ptr_(buf), end_(ptr_ + len) {}
bool BigEndianWriter::Skip(size_t len) {
if (ptr_ + len > end_)
return false;
ptr_ += len;
return true;
}
bool BigEndianWriter::WriteBytes(const void* buf, size_t len) {
if (ptr_ + len > end_)
return false;
memcpy(ptr_, buf, len);
ptr_ += len;
return true;
}
template <typename T>
bool BigEndianWriter::Write(T value) {
if (ptr_ + sizeof(T) > end_)
return false;
WriteBigEndian<T>(ptr_, value);
ptr_ += sizeof(T);
return true;
}
bool BigEndianWriter::WriteU8(uint8_t value) {
return Write(value);
}
bool BigEndianWriter::WriteU16(uint16_t value) {
return Write(value);
}
bool BigEndianWriter::WriteU32(uint32_t value) {
return Write(value);
}
bool BigEndianWriter::WriteU64(uint64_t value) {
return Write(value);
}
} // namespace rocketmq

View File

@@ -0,0 +1,102 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BIG_ENDIAN_H_
#define BASE_BIG_ENDIAN_H_
#include <stddef.h>
#include <stdint.h>
namespace rocketmq {
// Read an integer (signed or unsigned) from |buf| in Big Endian order.
// Note: this loop is unrolled with -O1 and above.
// NOTE(szym): glibc dns-canon.c use ntohs(*(uint16_t*)ptr) which is
// potentially unaligned.
// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
template <typename T>
inline void ReadBigEndian(const char buf[], T* out) {
*out = buf[0];
for (size_t i = 1; i < sizeof(T); ++i) {
*out <<= 8;
// Must cast to uint8_t to avoid clobbering by sign extension.
*out |= static_cast<uint8_t>(buf[i]);
}
}
// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
// Note: this loop is unrolled with -O1 and above.
template <typename T>
inline void WriteBigEndian(char buf[], T val) {
for (size_t i = 0; i < sizeof(T); ++i) {
buf[sizeof(T) - i - 1] = static_cast<char>(val & 0xFF);
val >>= 8;
}
}
// Specializations to make clang happy about the (dead code) shifts above.
template <>
inline void ReadBigEndian<uint8_t>(const char buf[], uint8_t* out) {
*out = buf[0];
}
template <>
inline void WriteBigEndian<uint8_t>(char buf[], uint8_t val) {
buf[0] = static_cast<char>(val);
}
// Allows reading integers in network order (big endian) while iterating over
// an underlying buffer. All the reading functions advance the internal pointer.
class BigEndianReader {
public:
BigEndianReader(const char* buf, size_t len);
const char* ptr() const { return ptr_; }
int remaining() const { return end_ - ptr_; }
bool Skip(size_t len);
bool ReadBytes(void* out, size_t len);
bool ReadU8(uint8_t* value);
bool ReadU16(uint16_t* value);
bool ReadU32(uint32_t* value);
bool ReadU64(uint64_t* value);
private:
// Hidden to promote type safety.
template <typename T>
bool Read(T* v);
const char* ptr_;
const char* end_;
};
// Allows writing integers in network order (big endian) while iterating over
// an underlying buffer. All the writing functions advance the internal pointer.
class BigEndianWriter {
public:
BigEndianWriter(char* buf, size_t len);
char* ptr() const { return ptr_; }
int remaining() const { return end_ - ptr_; }
bool Skip(size_t len);
bool WriteBytes(const void* buf, size_t len);
bool WriteU8(uint8_t value);
bool WriteU16(uint16_t value);
bool WriteU32(uint32_t value);
bool WriteU64(uint64_t value);
private:
// Hidden to promote type safety.
template <typename T>
bool Write(T v);
char* ptr_;
char* end_;
};
} // namespace rocketmq
#endif // BASE_BIG_ENDIAN_H_

View File

@@ -0,0 +1,207 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "dataBlock.h"
#include <algorithm>
namespace rocketmq {
MemoryBlock::MemoryBlock() : size(0), data(NULL) {}
MemoryBlock::MemoryBlock(const int initialSize, const bool initialiseToZero) : size(0), data(NULL) {
if (initialSize > 0) {
size = initialSize;
data = static_cast<char*>(initialiseToZero ? std::calloc(initialSize, sizeof(char))
: std::malloc(initialSize * sizeof(char)));
}
}
MemoryBlock::MemoryBlock(const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size(sizeInBytes), data(NULL) {
if (size > 0) {
data = static_cast<char*>(std::malloc(size * sizeof(char)));
if (dataToInitialiseFrom != NULL)
memcpy(data, dataToInitialiseFrom, size);
}
}
MemoryBlock::MemoryBlock(const MemoryBlock& other) : size(other.size), data(NULL) {
if (size > 0) {
data = static_cast<char*>(std::malloc(size * sizeof(char)));
memcpy(data, other.data, size);
}
}
MemoryBlock::MemoryBlock(MemoryBlock&& other) : size(other.size), data(other.data) {
other.size = 0;
other.data = NULL;
}
MemoryBlock::~MemoryBlock() {
std::free(data);
}
MemoryBlock& MemoryBlock::operator=(const MemoryBlock& other) {
if (this != &other) {
setSize(other.size, false);
memcpy(data, other.data, size);
}
return *this;
}
MemoryBlock& MemoryBlock::operator=(MemoryBlock&& other) {
if (this != &other) {
std::free(data);
size = other.size;
data = other.data;
other.size = 0;
other.data = NULL;
}
return *this;
}
//==============================================================================
bool MemoryBlock::operator==(const MemoryBlock& other) const {
return matches(other.data, other.size);
}
bool MemoryBlock::operator!=(const MemoryBlock& other) const {
return !operator==(other);
}
bool MemoryBlock::matches(const void* dataToCompare, int dataSize) const {
return size == dataSize && memcmp(data, dataToCompare, size) == 0;
}
//==============================================================================
// this will resize the block to this size
void MemoryBlock::setSize(const int newSize, const bool initialiseToZero) {
if (size != newSize) {
if (newSize <= 0) {
reset();
} else {
if (data != NULL) {
data = static_cast<char*>(data == NULL ? std::malloc(newSize * sizeof(char))
: std::realloc(data, newSize * sizeof(char)));
if (initialiseToZero && (newSize > size))
memset(data + size, 0, newSize - size);
} else {
std::free(data);
data = static_cast<char*>(initialiseToZero ? std::calloc(newSize, sizeof(char))
: std::malloc(newSize * sizeof(char)));
}
size = newSize;
}
}
}
void MemoryBlock::reset() {
std::free(data);
data = NULL;
size = 0;
}
void MemoryBlock::ensureSize(const int minimumSize, const bool initialiseToZero) {
if (size < minimumSize)
setSize(minimumSize, initialiseToZero);
}
//==============================================================================
void MemoryBlock::fillWith(const int value) {
memset(data, (int)value, size);
}
void MemoryBlock::append(const void* const srcData, const int numBytes) {
if (numBytes > 0) {
const int oldSize = size;
setSize(size + numBytes);
memcpy(data + oldSize, srcData, numBytes);
}
}
void MemoryBlock::replaceWith(const void* const srcData, const int numBytes) {
if (numBytes > 0) {
setSize(numBytes);
memcpy(data, srcData, numBytes);
}
}
void MemoryBlock::insert(const void* const srcData, const int numBytes, int insertPosition) {
if (numBytes > 0) {
insertPosition = std::min(insertPosition, size);
const int trailingDataSize = size - insertPosition;
setSize(size + numBytes, false);
if (trailingDataSize > 0)
memmove(data + insertPosition + numBytes, data + insertPosition, trailingDataSize);
memcpy(data + insertPosition, srcData, numBytes);
}
}
void MemoryBlock::removeSection(const int startByte, const int numBytesToRemove) {
if (startByte + numBytesToRemove >= size) {
setSize(startByte);
} else if (numBytesToRemove > 0) {
memmove(data + startByte, data + startByte + numBytesToRemove, size - (startByte + numBytesToRemove));
setSize(size - numBytesToRemove);
}
}
void MemoryBlock::copyFrom(const void* const src, int offset, int num) {
const char* d = static_cast<const char*>(src);
if (offset < 0) {
d -= offset;
num += (size_t)-offset;
offset = 0;
}
if ((size_t)offset + num > (unsigned int)size)
num = size - (size_t)offset;
if (num > 0)
memcpy(data + offset, d, num);
}
void MemoryBlock::copyTo(void* const dst, int offset, int num) const {
char* d = static_cast<char*>(dst);
if (offset < 0) {
memset(d, 0, (size_t)-offset);
d -= offset;
num -= (size_t)-offset;
offset = 0;
}
if ((size_t)offset + num > (unsigned int)size) {
const int newNum = (size_t)size - (size_t)offset;
memset(d + newNum, 0, num - newNum);
num = newNum;
}
if (num > 0)
memcpy(d, data + offset, num);
}
} // namespace rocketmq

View File

@@ -0,0 +1,208 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __DATABLOCK_H__
#define __DATABLOCK_H__
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include "RocketMQClient.h"
namespace rocketmq {
class ROCKETMQCLIENT_API MemoryBlock {
public:
//==============================================================================
/** Create an uninitialised block with 0 size. */
MemoryBlock();
/** Creates a memory block with a given initial size.
@param initialSize the size of block to create
@param initialiseToZero whether to clear the memory or just leave it
uninitialised
*/
MemoryBlock(const int initialSize, bool initialiseToZero = false);
/** Creates a memory block using a copy of a block of data.
@param dataToInitialiseFrom some data to copy into this block
@param sizeInBytes how much space to use
*/
MemoryBlock(const void* dataToInitialiseFrom, size_t sizeInBytes);
/** Creates a copy of another memory block. */
MemoryBlock(const MemoryBlock&);
MemoryBlock(MemoryBlock&&);
/** Destructor. */
~MemoryBlock();
/** Copies another memory block onto this one.
This block will be resized and copied to exactly match the other one.
*/
MemoryBlock& operator=(const MemoryBlock&);
MemoryBlock& operator=(MemoryBlock&&);
//==============================================================================
/** Compares two memory blocks.
@returns true only if the two blocks are the same size and have identical
contents.
*/
bool operator==(const MemoryBlock& other) const;
/** Compares two memory blocks.
@returns true if the two blocks are different sizes or have different
contents.
*/
bool operator!=(const MemoryBlock& other) const;
//==============================================================================
/** Returns a void pointer to the data.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
char* getData() const { return data; }
/** Returns a byte from the memory block.
This returns a reference, so you can also use it to set a byte.
*/
template <typename Type>
char& operator[](const Type offset) const {
return data[offset];
}
/** Returns true if the data in this MemoryBlock matches the raw bytes
* passed-in. */
bool matches(const void* data, int dataSize) const;
//==============================================================================
/** Returns the block's current allocated size, in bytes. */
int getSize() const { return size; }
/** Resizes the memory block.
Any data that is present in both the old and new sizes will be retained.
When enlarging the block, the new space that is allocated at the end can
either be
cleared, or left uninitialised.
@param newSize the new desired size for the block
@param initialiseNewSpaceToZero if the block gets enlarged, this
determines
whether to clear the new section or
just leave it
uninitialised
@see ensureSize
*/
void setSize(const int newSize, bool initialiseNewSpaceToZero = false);
/** Increases the block's size only if it's smaller than a given size.
@param minimumSize if the block is already bigger than
this size, no action
will be taken; otherwise it will be
increased to this size
@param initialiseNewSpaceToZero if the block gets enlarged, this
determines
whether to clear the new section or
just leave it
uninitialised
@see setSize
*/
void ensureSize(const int minimumSize, bool initialiseNewSpaceToZero = false);
/** Frees all the blocks data, setting its size to 0. */
void reset();
//==============================================================================
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.
*/
void fillWith(int valueToUse);
/** Adds another block of data to the end of this one.
The data pointer must not be null. This block's size will be increased
accordingly.
*/
void append(const void* data, int numBytes);
/** Resizes this block to the given size and fills its contents from the
supplied buffer.
The data pointer must not be null.
*/
void replaceWith(const void* data, int numBytes);
/** Inserts some data into the block.
The dataToInsert pointer must not be null. This block's size will be
increased accordingly.
If the insert position lies outside the valid range of the block, it will
be clipped to
within the range before being used.
*/
void insert(const void* dataToInsert, int numBytesToInsert, int insertPosition);
/** Chops out a section of the block.
This will remove a section of the memory block and close the gap around
it,
shifting any subsequent data downwards and reducing the size of the block.
If the range specified goes beyond the size of the block, it will be
clipped.
*/
void removeSection(int startByte, int numBytesToRemove);
//==============================================================================
/** Copies data into this MemoryBlock from a memory address.
@param srcData the memory location of the data to copy into
this block
@param destinationOffset the offset in this block at which the data
being copied should begin
@param numBytes how much to copy in (if this goes beyond the
size of the memory block,
it will be clipped so not to do anything
nasty)
*/
void copyFrom(const void* srcData, int destinationOffset, int numBytes);
/** Copies data from this MemoryBlock to a memory address.
@param destData the memory location to write to
@param sourceOffset the offset within this block from which the copied
data will be read
@param numBytes how much to copy (if this extends beyond the
limits of the memory block,
zeros will be used for that portion of the data)
*/
void copyTo(void* destData, int sourceOffset, int numBytes) const;
private:
//==============================================================================
int size;
char* data;
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __NONCOPYABLE_H__
#define __NONCOPYABLE_H__
namespace rocketmq {
class noncopyable {
protected:
noncopyable() = default;
~noncopyable() = default;
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
};
} // namespace rocketmq
#endif //__NONCOPYABLE_H__

View File

@@ -0,0 +1,151 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include "Logging.h"
#include "url.h"
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
using boost::lambda::var;
namespace {
void check_deadline(deadline_timer* deadline, tcp::socket* socket, const boost::system::error_code& ec) {
// Check whether the deadline has passed. We compare the deadline against
// the current time since a new asynchronous operation may have moved the
// deadline before this actor had a chance to run.
if (deadline->expires_at() <= deadline_timer::traits_type::now()) {
// The deadline has passed. The socket is closed so that any outstanding
// asynchronous operations are cancelled. This allows the blocked
// connect(), read_line() or write_line() functions to return.
boost::system::error_code ignored_ec;
socket->close(ignored_ec);
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
deadline->expires_at(boost::posix_time::pos_infin);
}
// Put the actor back to sleep.
deadline->async_wait(boost::bind(&check_deadline, deadline, socket, boost::asio::placeholders::error));
}
} // namespace
namespace rocketmq {
bool SyncfetchNsAddr(const Url& url_s, std::string& body) {
bool ret = true;
try {
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query(url_s.host_, url_s.port_);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
boost::system::error_code ec = boost::asio::error::would_block;
deadline_timer deadline(io_service);
// TODO hardcode
boost::posix_time::seconds timeout(3);
deadline.expires_from_now(timeout);
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
boost::system::error_code deadline_ec;
check_deadline(&deadline, &socket, deadline_ec);
boost::asio::async_connect(socket, endpoint_iterator, boost::lambda::var(ec) = boost::lambda::_1);
do {
io_service.run_one();
} while (ec == boost::asio::error::would_block);
if (ec || !socket.is_open()) {
LOG_ERROR("socket connect failure, connect timeout or connect failure");
return false;
}
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << url_s.path_ << " HTTP/1.0\r\n";
request_stream << "Host: " << url_s.host_ << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
LOG_INFO("Invalid response %s\n", status_message.c_str());
return false;
}
if (status_code != 200) {
LOG_INFO("Response returned with status code %d ", status_code);
return false;
}
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
;
// Write whatever content we already have to output.
if (response.size() > 0) {
boost::asio::streambuf::const_buffers_type cbt = response.data();
body.clear();
body.insert(body.begin(), boost::asio::buffers_begin(cbt), boost::asio::buffers_end(cbt));
}
// Read until EOF, writing data to output as we go.
boost::system::error_code error;
while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error))
std::cout << &response;
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
} catch (std::exception& e) {
LOG_ERROR("Exception: %s", e.what());
ret = false;
}
return ret;
}
} // namespace rocketmq

View File

@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_
#define ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_
#include <string>
namespace rocketmq {
class Url;
extern bool SyncfetchNsAddr(const Url& url_s, std::string& body);
} // namespace rocketmq
#endif // ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_

View File

@@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "url.h"
#include <algorithm>
#include <cctype>
#include <functional>
#include <iterator>
#include <string>
namespace rocketmq {
Url::Url(const std::string& url_s) {
parse(url_s);
}
void Url::parse(const std::string& url_s) {
const std::string prot_end("://");
auto prot_i = std::search(url_s.begin(), url_s.end(), prot_end.begin(), prot_end.end());
protocol_.reserve(std::distance(url_s.begin(), prot_i));
std::transform(url_s.begin(), prot_i, std::back_inserter(protocol_),
std::ptr_fun<int, int>(tolower)); // protocol is icase
if (prot_i == url_s.end())
return;
std::advance(prot_i, prot_end.length());
auto path_i = find(prot_i, url_s.end(), ':');
std::string::const_iterator path_end_i;
if (path_i == url_s.end()) {
// not include port, use default port
port_ = "80";
path_i = std::find(prot_i, url_s.end(), '/');
path_end_i = path_i;
} else {
auto port_i = find(path_i + 1, url_s.end(), '/');
port_.insert(port_.begin(), path_i + 1, port_i);
path_end_i = path_i + port_.length() + 1;
}
host_.reserve(distance(prot_i, path_i));
std::transform(prot_i, path_i, std::back_inserter(host_), std::ptr_fun<int, int>(tolower)); // host is icase}
auto query_i = find(path_end_i, url_s.end(), '?');
path_.assign(path_end_i, query_i);
if (query_i != url_s.end())
++query_i;
query_.assign(query_i, url_s.end());
}
} // namespace rocketmq

View File

@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef ROCKETMQ_CLIENT4CPP_URL_HH_
#define ROCKETMQ_CLIENT4CPP_URL_HH_
#include <string>
namespace rocketmq {
class Url {
public:
Url(const std::string& url_s); // omitted copy, ==, accessors, ...
private:
void parse(const std::string& url_s);
public:
std::string protocol_;
std::string host_;
std::string port_;
std::string path_;
std::string query_;
};
} // namespace rocketmq
#endif // ROCKETMQ_CLIENT4CPP_URL_HH_

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __ALLOCATEMESSAGEQUEUESTRATEGY_H__
#define __ALLOCATEMESSAGEQUEUESTRATEGY_H__
#include "Logging.h"
#include "MQClientException.h"
#include "MQMessageQueue.h"
namespace rocketmq {
//<!***************************************************************************
class AllocateMQStrategy {
public:
virtual ~AllocateMQStrategy() {}
virtual void allocate(const std::string& currentCID,
std::vector<MQMessageQueue>& mqAll,
std::vector<std::string>& cidAll,
std::vector<MQMessageQueue>& outReuslt) = 0;
};
//<!************************************************************************
class AllocateMQAveragely : public AllocateMQStrategy {
public:
virtual ~AllocateMQAveragely() {}
virtual void allocate(const std::string& currentCID,
std::vector<MQMessageQueue>& mqAll,
std::vector<std::string>& cidAll,
std::vector<MQMessageQueue>& outReuslt) {
outReuslt.clear();
if (currentCID.empty()) {
THROW_MQEXCEPTION(MQClientException, "currentCID is empty", -1);
}
if (mqAll.empty()) {
THROW_MQEXCEPTION(MQClientException, "mqAll is empty", -1);
}
if (cidAll.empty()) {
THROW_MQEXCEPTION(MQClientException, "cidAll is empty", -1);
}
int index = -1;
int cidAllSize = cidAll.size();
for (int i = 0; i < cidAllSize; i++) {
if (cidAll[i] == currentCID) {
index = i;
break;
}
}
if (index == -1) {
LOG_ERROR("could not find clientId from Broker");
return;
}
int mqAllSize = mqAll.size();
int mod = mqAllSize % cidAllSize;
int averageSize =
mqAllSize <= cidAllSize ? 1 : (mod > 0 && index < mod ? mqAllSize / cidAllSize + 1 : mqAllSize / cidAllSize);
int startIndex = (mod > 0 && index < mod) ? index * averageSize : index * averageSize + mod;
int range = (std::min)(averageSize, mqAllSize - startIndex);
LOG_INFO(
"range is:%d, index is:%d, mqAllSize is:%d, averageSize is:%d, "
"startIndex is:%d",
range, index, mqAllSize, averageSize, startIndex);
//<!out;
if (range >= 0) // example: range is:-1, index is:1, mqAllSize is:1,
// averageSize is:1, startIndex is:2
{
for (int i = 0; i < range; i++) {
if ((startIndex + i) >= 0) {
outReuslt.push_back(mqAll.at((startIndex + i) % mqAllSize));
}
}
}
}
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,319 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#if !defined(WIN32) && !defined(__APPLE__)
#include <sys/prctl.h>
#endif
#include "ConsumeMsgService.h"
#include "DefaultMQPushConsumer.h"
#include "Logging.h"
#include "MessageAccessor.h"
#include "UtilAll.h"
namespace rocketmq {
//<!************************************************************************
ConsumeMessageConcurrentlyService::ConsumeMessageConcurrentlyService(MQConsumer* consumer,
int threadCount,
MQMessageListener* msgListener)
: m_pConsumer(consumer), m_pMessageListener(msgListener), m_ioServiceWork(m_ioService) {
#if !defined(WIN32) && !defined(__APPLE__)
string taskName = UtilAll::getProcessName();
prctl(PR_SET_NAME, "ConsumeTP", 0, 0, 0);
#endif
for (int i = 0; i != threadCount; ++i) {
m_threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &m_ioService));
}
#if !defined(WIN32) && !defined(__APPLE__)
prctl(PR_SET_NAME, taskName.c_str(), 0, 0, 0);
#endif
}
ConsumeMessageConcurrentlyService::~ConsumeMessageConcurrentlyService(void) {
m_pConsumer = NULL;
m_pMessageListener = NULL;
}
void ConsumeMessageConcurrentlyService::start() {}
void ConsumeMessageConcurrentlyService::shutdown() {
stopThreadPool();
}
void ConsumeMessageConcurrentlyService::stopThreadPool() {
m_ioService.stop();
m_threadpool.join_all();
}
MessageListenerType ConsumeMessageConcurrentlyService::getConsumeMsgSerivceListenerType() {
return m_pMessageListener->getMessageListenerType();
}
void ConsumeMessageConcurrentlyService::submitConsumeRequest(boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
if (request->isDropped()) {
LOG_INFO("Pull request for %s is dropped, which will be released in next re-balance.",
request->m_messageQueue.toString().c_str());
return;
}
if (!request->isDropped() && !m_ioService.stopped()) {
m_ioService.post(boost::bind(&ConsumeMessageConcurrentlyService::ConsumeRequest, this, request, msgs));
} else {
LOG_INFO("IOService stopped or Pull request for %s is dropped, will not post ConsumeRequest.",
request->m_messageQueue.toString().c_str());
}
}
void ConsumeMessageConcurrentlyService::submitConsumeRequestLater(boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs,
int millis) {
if (msgs.empty()) {
return;
}
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
if (request->isDropped()) {
LOG_INFO("Pull request is set as dropped with mq:%s, need release in next rebalance.",
(request->m_messageQueue).toString().c_str());
return;
}
if (!request->isDropped() && !m_ioService.stopped()) {
boost::asio::deadline_timer* t =
new boost::asio::deadline_timer(m_ioService, boost::posix_time::milliseconds(millis));
t->async_wait(
boost::bind(&(ConsumeMessageConcurrentlyService::static_submitConsumeRequest), this, t, request, msgs));
LOG_INFO("Submit Message to Consumer [%s] Later and Sleep [%d]ms.", (request->m_messageQueue).toString().c_str(),
millis);
} else {
LOG_INFO("IOService stopped or Pull request for %s is dropped, will not post delay ConsumeRequest.",
request->m_messageQueue.toString().c_str());
}
}
void ConsumeMessageConcurrentlyService::static_submitConsumeRequest(void* context,
boost::asio::deadline_timer* t,
boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
ConsumeMessageConcurrentlyService* pService = (ConsumeMessageConcurrentlyService*)context;
if (pService) {
pService->triggersubmitConsumeRequestLater(t, request, msgs);
}
}
void ConsumeMessageConcurrentlyService::triggersubmitConsumeRequestLater(boost::asio::deadline_timer* t,
boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
submitConsumeRequest(request, msgs);
deleteAndZero(t);
}
void ConsumeMessageConcurrentlyService::ConsumeRequest(boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
if (request->isDropped()) {
LOG_WARN("the pull request for %s Had been dropped before", request->m_messageQueue.toString().c_str());
request->clearAllMsgs(); // add clear operation to avoid bad state when
// dropped pullRequest returns normal
return;
}
if (msgs.empty()) {
LOG_WARN("the msg of pull result is NULL,its mq:%s", (request->m_messageQueue).toString().c_str());
return;
}
ConsumeMessageContext consumeMessageContext;
DefaultMQPushConsumerImpl* pConsumer = dynamic_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
if (pConsumer) {
if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) {
consumeMessageContext.setDefaultMQPushConsumer(pConsumer);
consumeMessageContext.setConsumerGroup(pConsumer->getGroupName());
consumeMessageContext.setMessageQueue(request->m_messageQueue);
consumeMessageContext.setMsgList(msgs);
consumeMessageContext.setSuccess(false);
consumeMessageContext.setNameSpace(pConsumer->getNameSpace());
pConsumer->executeConsumeMessageHookBefore(&consumeMessageContext);
}
}
ConsumeStatus status = CONSUME_SUCCESS;
if (m_pMessageListener != NULL) {
resetRetryTopic(msgs);
request->setLastConsumeTimestamp(UtilAll::currentTimeMillis());
LOG_DEBUG("=====Receive Messages,Topic[%s], MsgId[%s],Body[%s],RetryTimes[%d]", msgs[0].getTopic().c_str(),
msgs[0].getMsgId().c_str(), msgs[0].getBody().c_str(), msgs[0].getReconsumeTimes());
if (m_pConsumer->isUseNameSpaceMode()) {
MessageAccessor::withoutNameSpace(msgs, m_pConsumer->getNameSpace());
}
if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) {
// For open trace message, consume message one by one.
for (size_t i = 0; i < msgs.size(); ++i) {
LOG_DEBUG("=====Trace Receive Messages,Topic[%s], MsgId[%s],Body[%s],RetryTimes[%d]",
msgs[i].getTopic().c_str(), msgs[i].getMsgId().c_str(), msgs[i].getBody().c_str(),
msgs[i].getReconsumeTimes());
std::vector<MQMessageExt> msgInner;
msgInner.push_back(msgs[i]);
if (status != CONSUME_SUCCESS) {
// all the Messages behind should be set to failed.
status = RECONSUME_LATER;
consumeMessageContext.setMsgIndex(i);
consumeMessageContext.setStatus("RECONSUME_LATER");
consumeMessageContext.setSuccess(false);
pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext);
continue;
}
try {
status = m_pMessageListener->consumeMessage(msgInner);
} catch (...) {
status = RECONSUME_LATER;
LOG_ERROR("Consumer's code is buggy. Un-caught exception raised");
}
consumeMessageContext.setMsgIndex(i); // indicate message position,not support batch consumer
if (status == CONSUME_SUCCESS) {
consumeMessageContext.setStatus("CONSUME_SUCCESS");
consumeMessageContext.setSuccess(true);
} else {
status = RECONSUME_LATER;
consumeMessageContext.setStatus("RECONSUME_LATER");
consumeMessageContext.setSuccess(false);
}
pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext);
}
} else {
try {
status = m_pMessageListener->consumeMessage(msgs);
} catch (...) {
status = RECONSUME_LATER;
LOG_ERROR("Consumer's code is buggy. Un-caught exception raised");
}
}
}
int ackIndex = -1;
switch (status) {
case CONSUME_SUCCESS:
ackIndex = msgs.size();
break;
case RECONSUME_LATER:
ackIndex = -1;
break;
default:
break;
}
std::vector<MQMessageExt> localRetryMsgs;
switch (m_pConsumer->getMessageModel()) {
case BROADCASTING: {
// Note: broadcasting reconsume should do by application, as it has big
// affect to broker cluster
if (ackIndex != (int)msgs.size())
LOG_WARN("BROADCASTING, the message consume failed, drop it:%s", (request->m_messageQueue).toString().c_str());
break;
}
case CLUSTERING: {
// send back msg to broker;
for (size_t i = ackIndex + 1; i < msgs.size(); i++) {
LOG_DEBUG("consume fail, MQ is:%s, its msgId is:%s, index is:" SIZET_FMT ", reconsume times is:%d",
(request->m_messageQueue).toString().c_str(), msgs[i].getMsgId().c_str(), i,
msgs[i].getReconsumeTimes());
if (m_pConsumer->getConsumeType() == CONSUME_PASSIVELY) {
string brokerName = request->m_messageQueue.getBrokerName();
if (m_pConsumer->isUseNameSpaceMode()) {
MessageAccessor::withNameSpace(msgs[i], m_pConsumer->getNameSpace());
}
if (!m_pConsumer->sendMessageBack(msgs[i], 0, brokerName)) {
LOG_WARN("Send message back fail, MQ is:%s, its msgId is:%s, index is:%d, re-consume times is:%d",
(request->m_messageQueue).toString().c_str(), msgs[i].getMsgId().c_str(), i,
msgs[i].getReconsumeTimes());
msgs[i].setReconsumeTimes(msgs[i].getReconsumeTimes() + 1);
localRetryMsgs.push_back(msgs[i]);
}
}
}
break;
}
default:
break;
}
if (!localRetryMsgs.empty()) {
LOG_ERROR("Client side re-consume launched due to both message consuming and SDK send-back retry failure");
for (std::vector<MQMessageExt>::iterator itOrigin = msgs.begin(); itOrigin != msgs.end();) {
bool remove = false;
for (std::vector<MQMessageExt>::iterator itRetry = localRetryMsgs.begin(); itRetry != localRetryMsgs.end();
itRetry++) {
if (itRetry->getQueueOffset() == itOrigin->getQueueOffset()) {
remove = true;
break;
}
}
if (remove) {
itOrigin = msgs.erase(itOrigin);
} else {
itOrigin++;
}
}
}
// update offset
int64 offset = request->removeMessage(msgs);
if (offset >= 0) {
m_pConsumer->updateConsumeOffset(request->m_messageQueue, offset);
} else {
LOG_WARN("Note: Get local offset for mq:%s failed, may be it is updated before. skip..",
(request->m_messageQueue).toString().c_str());
}
if (!localRetryMsgs.empty()) {
// submitConsumeRequest(request, localTryMsgs);
LOG_INFO("Send [%d ]messages back to mq:%s failed, call reconsume again after 1s.", localRetryMsgs.size(),
(request->m_messageQueue).toString().c_str());
submitConsumeRequestLater(request, localRetryMsgs, 1000);
}
} // namespace rocketmq
void ConsumeMessageConcurrentlyService::resetRetryTopic(vector<MQMessageExt>& msgs) {
string groupTopic = UtilAll::getRetryTopic(m_pConsumer->getGroupName());
for (size_t i = 0; i < msgs.size(); i++) {
MQMessageExt& msg = msgs[i];
string retryTopic = msg.getProperty(MQMessage::PROPERTY_RETRY_TOPIC);
if (!retryTopic.empty() && groupTopic.compare(msg.getTopic()) == 0) {
msg.setTopic(retryTopic);
}
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "ConsumeMessageHookImpl.h"
#include <memory>
#include <string>
#include "ConsumeMessageContext.h"
#include "DefaultMQPushConsumerImpl.h"
#include "Logging.h"
#include "MQClientException.h"
#include "NameSpaceUtil.h"
#include "TraceContant.h"
#include "TraceContext.h"
#include "TraceTransferBean.h"
#include "TraceUtil.h"
#include "UtilAll.h"
namespace rocketmq {
class TraceMessageConsumeCallback : public SendCallback {
virtual void onSuccess(SendResult& sendResult) {
LOG_DEBUG("TraceMessageConsumeCallback, MsgId:[%s],OffsetMsgId[%s]", sendResult.getMsgId().c_str(),
sendResult.getOffsetMsgId().c_str());
}
virtual void onException(MQException& e) {}
};
static TraceMessageConsumeCallback* consumeTraceCallback = new TraceMessageConsumeCallback();
std::string ConsumeMessageHookImpl::getHookName() {
return "RocketMQConsumeMessageHookImpl";
}
void ConsumeMessageHookImpl::executeHookBefore(ConsumeMessageContext* context) {
if (context == NULL || context->getMsgList().empty()) {
return;
}
TraceContext* traceContext = new TraceContext();
context->setTraceContext(traceContext);
traceContext->setTraceType(SubBefore);
traceContext->setGroupName(NameSpaceUtil::withoutNameSpace(context->getConsumerGroup(), context->getNameSpace()));
std::vector<TraceBean> beans;
std::vector<MQMessageExt> msgs = context->getMsgList();
std::vector<MQMessageExt>::iterator it = msgs.begin();
for (; it != msgs.end(); ++it) {
TraceBean bean;
bean.setTopic((*it).getTopic());
bean.setMsgId((*it).getMsgId());
bean.setTags((*it).getTags());
bean.setKeys((*it).getKeys());
bean.setStoreHost((*it).getStoreHostString());
bean.setStoreTime((*it).getStoreTimestamp());
bean.setBodyLength((*it).getStoreSize());
bean.setRetryTimes((*it).getReconsumeTimes());
std::string regionId = (*it).getProperty(MQMessage::PROPERTY_MSG_REGION);
if (regionId.empty()) {
regionId = TraceContant::DEFAULT_REDION;
}
traceContext->setRegionId(regionId);
traceContext->setTraceBean(bean);
}
traceContext->setTimeStamp(UtilAll::currentTimeMillis());
std::string topic = TraceContant::TRACE_TOPIC + traceContext->getRegionId();
TraceTransferBean ben = TraceUtil::CovertTraceContextToTransferBean(traceContext);
MQMessage message(topic, ben.getTransData());
message.setKeys(ben.getTransKey());
// send trace message async.
context->getDefaultMQPushConsumer()->submitSendTraceRequest(message, consumeTraceCallback);
return;
}
void ConsumeMessageHookImpl::executeHookAfter(ConsumeMessageContext* context) {
if (context == NULL || context->getMsgList().empty()) {
return;
}
std::shared_ptr<TraceContext> subBeforeContext = context->getTraceContext();
TraceContext subAfterContext;
subAfterContext.setTraceType(SubAfter);
subAfterContext.setRegionId(subBeforeContext->getRegionId());
subAfterContext.setGroupName(subBeforeContext->getGroupName());
subAfterContext.setRequestId(subBeforeContext->getRequestId());
subAfterContext.setStatus(context->getSuccess());
int costTime = static_cast<int>(UtilAll::currentTimeMillis() - subBeforeContext->getTimeStamp());
subAfterContext.setCostTime(costTime);
subAfterContext.setTraceBeanIndex(context->getMsgIndex());
TraceBean bean = subBeforeContext->getTraceBeans()[subAfterContext.getTraceBeanIndex()];
subAfterContext.setTraceBean(bean);
std::string topic = TraceContant::TRACE_TOPIC + subAfterContext.getRegionId();
TraceTransferBean ben = TraceUtil::CovertTraceContextToTransferBean(&subAfterContext);
MQMessage message(topic, ben.getTransData());
message.setKeys(ben.getTransKey());
// send trace message async.
context->getDefaultMQPushConsumer()->submitSendTraceRequest(message, consumeTraceCallback);
return;
}
} // namespace rocketmq

View File

@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __ROCKETMQ_CONSUME_MESSAGE_RPC_HOOK_IMPL_H__
#define __ROCKETMQ_CONSUME_MESSAGE_RPC_HOOK_IMPL_H__
#include <string>
#include "ConsumeMessageContext.h"
#include "ConsumeMessageHook.h"
namespace rocketmq {
class ConsumeMessageHookImpl : public ConsumeMessageHook {
public:
virtual ~ConsumeMessageHookImpl() {}
virtual std::string getHookName();
virtual void executeHookBefore(ConsumeMessageContext* context);
virtual void executeHookAfter(ConsumeMessageContext* context);
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,266 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#if !defined(WIN32) && !defined(__APPLE__)
#include <sys/prctl.h>
#endif
#include <MessageAccessor.h>
#include "ConsumeMsgService.h"
#include "DefaultMQPushConsumer.h"
#include "Logging.h"
#include "Rebalance.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
ConsumeMessageOrderlyService::ConsumeMessageOrderlyService(MQConsumer* consumer,
int threadCount,
MQMessageListener* msgListener)
: m_pConsumer(consumer),
m_shutdownInprogress(false),
m_pMessageListener(msgListener),
m_MaxTimeConsumeContinuously(60 * 1000),
m_ioServiceWork(m_ioService),
m_async_service_thread(NULL) {
#if !defined(WIN32) && !defined(__APPLE__)
string taskName = UtilAll::getProcessName();
prctl(PR_SET_NAME, "oderlyConsumeTP", 0, 0, 0);
#endif
for (int i = 0; i != threadCount; ++i) {
m_threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &m_ioService));
}
#if !defined(WIN32) && !defined(__APPLE__)
prctl(PR_SET_NAME, taskName.c_str(), 0, 0, 0);
#endif
}
void ConsumeMessageOrderlyService::boost_asio_work() {
LOG_INFO("ConsumeMessageOrderlyService::boost asio async service runing");
boost::asio::io_service::work work(m_async_ioService); // avoid async io
// service stops after
// first timer timeout
// callback
boost::system::error_code ec;
boost::asio::deadline_timer t(m_async_ioService, boost::posix_time::milliseconds(PullRequest::RebalanceLockInterval));
t.async_wait(boost::bind(&ConsumeMessageOrderlyService::lockMQPeriodically, this, ec, &t));
m_async_ioService.run();
}
ConsumeMessageOrderlyService::~ConsumeMessageOrderlyService(void) {
m_pConsumer = NULL;
m_pMessageListener = NULL;
}
void ConsumeMessageOrderlyService::start() {
m_async_service_thread.reset(new boost::thread(boost::bind(&ConsumeMessageOrderlyService::boost_asio_work, this)));
}
void ConsumeMessageOrderlyService::shutdown() {
stopThreadPool();
unlockAllMQ();
}
void ConsumeMessageOrderlyService::lockMQPeriodically(boost::system::error_code& ec, boost::asio::deadline_timer* t) {
m_pConsumer->getRebalance()->lockAll();
boost::system::error_code e;
t->expires_at(t->expires_at() + boost::posix_time::milliseconds(PullRequest::RebalanceLockInterval), e);
t->async_wait(boost::bind(&ConsumeMessageOrderlyService::lockMQPeriodically, this, ec, t));
}
void ConsumeMessageOrderlyService::unlockAllMQ() {
m_pConsumer->getRebalance()->unlockAll(false);
}
bool ConsumeMessageOrderlyService::lockOneMQ(const MQMessageQueue& mq) {
return m_pConsumer->getRebalance()->lock(mq);
}
void ConsumeMessageOrderlyService::stopThreadPool() {
m_shutdownInprogress = true;
m_ioService.stop();
m_async_ioService.stop();
m_async_service_thread->interrupt();
m_async_service_thread->join();
m_threadpool.join_all();
}
MessageListenerType ConsumeMessageOrderlyService::getConsumeMsgSerivceListenerType() {
return m_pMessageListener->getMessageListenerType();
}
void ConsumeMessageOrderlyService::submitConsumeRequest(boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
m_ioService.post(boost::bind(&ConsumeMessageOrderlyService::ConsumeRequest, this, request));
}
void ConsumeMessageOrderlyService::static_submitConsumeRequestLater(void* context,
boost::weak_ptr<PullRequest> pullRequest,
bool tryLockMQ,
boost::asio::deadline_timer* t) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
LOG_INFO("submit consumeRequest later for mq:%s", request->m_messageQueue.toString().c_str());
vector<MQMessageExt> msgs;
ConsumeMessageOrderlyService* orderlyService = (ConsumeMessageOrderlyService*)context;
orderlyService->submitConsumeRequest(request, msgs);
if (tryLockMQ) {
orderlyService->lockOneMQ(request->m_messageQueue);
}
if (t)
deleteAndZero(t);
}
void ConsumeMessageOrderlyService::ConsumeRequest(boost::weak_ptr<PullRequest> pullRequest) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
bool bGetMutex = false;
boost::unique_lock<boost::timed_mutex> lock(request->getPullRequestCriticalSection(), boost::try_to_lock);
if (!lock.owns_lock()) {
if (!lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1))) {
LOG_ERROR("ConsumeRequest of:%s get timed_mutex timeout", request->m_messageQueue.toString().c_str());
return;
} else {
bGetMutex = true;
}
} else {
bGetMutex = true;
}
if (!bGetMutex) {
// LOG_INFO("pullrequest of mq:%s consume inprogress",
// request->m_messageQueue.toString().c_str());
return;
}
if (!request || request->isDropped()) {
LOG_WARN("the pull result is NULL or Had been dropped");
request->clearAllMsgs(); // add clear operation to avoid bad state when
// dropped pullRequest returns normal
return;
}
if (m_pMessageListener) {
if ((request->isLocked() && !request->isLockExpired()) || m_pConsumer->getMessageModel() == BROADCASTING) {
// DefaultMQPushConsumer* pConsumer = (DefaultMQPushConsumer*)m_pConsumer;
uint64_t beginTime = UtilAll::currentTimeMillis();
bool continueConsume = true;
while (continueConsume) {
if ((UtilAll::currentTimeMillis() - beginTime) > m_MaxTimeConsumeContinuously) {
LOG_INFO("Continuely consume %s more than 60s, consume it 1s later",
request->m_messageQueue.toString().c_str());
tryLockLaterAndReconsumeDelay(request, false, 1000);
break;
}
vector<MQMessageExt> msgs;
// request->takeMessages(msgs, pConsumer->getConsumeMessageBatchMaxSize());
request->takeMessages(msgs, 1);
if (!msgs.empty()) {
request->setLastConsumeTimestamp(UtilAll::currentTimeMillis());
if (m_pConsumer->isUseNameSpaceMode()) {
MessageAccessor::withoutNameSpace(msgs, m_pConsumer->getNameSpace());
}
ConsumeMessageContext consumeMessageContext;
DefaultMQPushConsumerImpl* pConsumer = dynamic_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
if (pConsumer) {
if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) {
consumeMessageContext.setDefaultMQPushConsumer(pConsumer);
consumeMessageContext.setConsumerGroup(pConsumer->getGroupName());
consumeMessageContext.setMessageQueue(request->m_messageQueue);
consumeMessageContext.setMsgList(msgs);
consumeMessageContext.setSuccess(false);
consumeMessageContext.setNameSpace(pConsumer->getNameSpace());
pConsumer->executeConsumeMessageHookBefore(&consumeMessageContext);
}
}
ConsumeStatus consumeStatus = m_pMessageListener->consumeMessage(msgs);
if (consumeStatus == RECONSUME_LATER) {
if (pConsumer) {
consumeMessageContext.setMsgIndex(0);
consumeMessageContext.setStatus("RECONSUME_LATER");
consumeMessageContext.setSuccess(false);
pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext);
}
if (msgs[0].getReconsumeTimes() <= 15) {
msgs[0].setReconsumeTimes(msgs[0].getReconsumeTimes() + 1);
request->makeMessageToCosumeAgain(msgs);
continueConsume = false;
tryLockLaterAndReconsumeDelay(request, false, 1000);
} else {
// need change to reconsumer delay level and print log.
LOG_INFO("Local Consume failed [%d] times, change [%s] delay to 5s.", msgs[0].getReconsumeTimes(),
msgs[0].getMsgId().c_str());
msgs[0].setReconsumeTimes(msgs[0].getReconsumeTimes() + 1);
continueConsume = false;
request->makeMessageToCosumeAgain(msgs);
tryLockLaterAndReconsumeDelay(request, false, 5000);
}
} else {
if (pConsumer) {
consumeMessageContext.setMsgIndex(0);
consumeMessageContext.setStatus("CONSUME_SUCCESS");
consumeMessageContext.setSuccess(true);
pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext);
}
m_pConsumer->updateConsumeOffset(request->m_messageQueue, request->commit());
}
} else {
continueConsume = false;
}
msgs.clear();
if (m_shutdownInprogress) {
LOG_INFO("shutdown inprogress, break the consuming");
return;
}
}
LOG_DEBUG("consume once exit of mq:%s", request->m_messageQueue.toString().c_str());
} else {
LOG_ERROR("message queue:%s was not locked", request->m_messageQueue.toString().c_str());
tryLockLaterAndReconsumeDelay(request, true, 1000);
}
}
}
void ConsumeMessageOrderlyService::tryLockLaterAndReconsumeDelay(boost::weak_ptr<PullRequest> pullRequest,
bool tryLockMQ,
int millisDelay) {
boost::shared_ptr<PullRequest> request = pullRequest.lock();
if (!request) {
LOG_WARN("Pull request has been released");
return;
}
int retryTimer = millisDelay;
if (millisDelay >= 30000 || millisDelay <= 1000) {
retryTimer = 1000;
}
boost::asio::deadline_timer* t =
new boost::asio::deadline_timer(m_async_ioService, boost::posix_time::milliseconds(retryTimer));
t->async_wait(
boost::bind(&ConsumeMessageOrderlyService::static_submitConsumeRequestLater, this, request, tryLockMQ, t));
}
} // namespace rocketmq

View File

@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef _CONSUMEMESSAGESERVICE_H_
#define _CONSUMEMESSAGESERVICE_H_
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread.hpp>
#include "DefaultMQPushConsumerImpl.h"
#include "Logging.h"
#include "MQConsumer.h"
#include "MQMessageListener.h"
#include "PullRequest.h"
namespace rocketmq {
// class MQConsumer;
//<!***************************************************************************
class ConsumeMsgService {
public:
ConsumeMsgService() {}
virtual ~ConsumeMsgService() {}
virtual void start() {}
virtual void shutdown() {}
virtual void stopThreadPool() {}
virtual void submitConsumeRequest(boost::weak_ptr<PullRequest> request, vector<MQMessageExt>& msgs) {}
virtual MessageListenerType getConsumeMsgSerivceListenerType() { return messageListenerDefaultly; }
};
class ConsumeMessageConcurrentlyService : public ConsumeMsgService {
public:
ConsumeMessageConcurrentlyService(MQConsumer*, int threadCount, MQMessageListener* msgListener);
virtual ~ConsumeMessageConcurrentlyService();
virtual void start();
virtual void shutdown();
virtual void submitConsumeRequest(boost::weak_ptr<PullRequest> request, vector<MQMessageExt>& msgs);
virtual MessageListenerType getConsumeMsgSerivceListenerType();
virtual void stopThreadPool();
void ConsumeRequest(boost::weak_ptr<PullRequest> request, vector<MQMessageExt>& msgs);
void submitConsumeRequestLater(boost::weak_ptr<PullRequest> request, vector<MQMessageExt>& msgs, int millis);
void triggersubmitConsumeRequestLater(boost::asio::deadline_timer* t,
boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs);
static void static_submitConsumeRequest(void* context,
boost::asio::deadline_timer* t,
boost::weak_ptr<PullRequest> pullRequest,
vector<MQMessageExt>& msgs);
private:
void resetRetryTopic(vector<MQMessageExt>& msgs);
private:
MQConsumer* m_pConsumer;
MQMessageListener* m_pMessageListener;
boost::asio::io_service m_ioService;
boost::thread_group m_threadpool;
boost::asio::io_service::work m_ioServiceWork;
};
class ConsumeMessageOrderlyService : public ConsumeMsgService {
public:
ConsumeMessageOrderlyService(MQConsumer*, int threadCount, MQMessageListener* msgListener);
virtual ~ConsumeMessageOrderlyService();
virtual void start();
virtual void shutdown();
virtual void submitConsumeRequest(boost::weak_ptr<PullRequest> request, vector<MQMessageExt>& msgs);
virtual void stopThreadPool();
virtual MessageListenerType getConsumeMsgSerivceListenerType();
void boost_asio_work();
// void tryLockLaterAndReconsume(boost::weak_ptr<PullRequest> request, bool tryLockMQ);
void tryLockLaterAndReconsumeDelay(boost::weak_ptr<PullRequest> request, bool tryLockMQ, int millisDelay);
static void static_submitConsumeRequestLater(void* context,
boost::weak_ptr<PullRequest> request,
bool tryLockMQ,
boost::asio::deadline_timer* t);
void ConsumeRequest(boost::weak_ptr<PullRequest> request);
void lockMQPeriodically(boost::system::error_code& ec, boost::asio::deadline_timer* t);
void unlockAllMQ();
bool lockOneMQ(const MQMessageQueue& mq);
private:
MQConsumer* m_pConsumer;
bool m_shutdownInprogress;
MQMessageListener* m_pMessageListener;
uint64_t m_MaxTimeConsumeContinuously;
boost::asio::io_service m_ioService;
boost::thread_group m_threadpool;
boost::asio::io_service::work m_ioServiceWork;
boost::asio::io_service m_async_ioService;
boost::scoped_ptr<boost::thread> m_async_service_thread;
};
//<!***************************************************************************
} // namespace rocketmq
#endif //<! _CONSUMEMESSAGESERVICE_H_

View File

@@ -0,0 +1,198 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "DefaultMQPullConsumer.h"
#include "DefaultMQPullConsumerImpl.h"
#include "MQVersion.h"
namespace rocketmq {
DefaultMQPullConsumer::DefaultMQPullConsumer(const std::string& groupName) {
impl = new DefaultMQPullConsumerImpl(groupName);
}
DefaultMQPullConsumer::~DefaultMQPullConsumer() {
delete impl;
}
void DefaultMQPullConsumer::start() {
impl->start();
}
void DefaultMQPullConsumer::shutdown() {
impl->shutdown();
}
std::string DefaultMQPullConsumer::version() {
std::string versions = impl->getClientVersionString();
/*versions.append(", PROTOCOL VERSION: ")
.append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion))
.append(", LANGUAGE: ")
.append(MQVersion::s_CurrentLanguage);*/
return versions;
}
// start mqclient set
const std::string& DefaultMQPullConsumer::getNamesrvAddr() const {
return impl->getNamesrvAddr();
}
void DefaultMQPullConsumer::setNamesrvAddr(const std::string& namesrvAddr) {
impl->setNamesrvAddr(namesrvAddr);
}
const std::string& DefaultMQPullConsumer::getNamesrvDomain() const {
return impl->getNamesrvDomain();
}
void DefaultMQPullConsumer::setNamesrvDomain(const std::string& namesrvDomain) {
impl->setNamesrvDomain(namesrvDomain);
}
void DefaultMQPullConsumer::setSessionCredentials(const std::string& accessKey,
const std::string& secretKey,
const std::string& accessChannel) {
impl->setSessionCredentials(accessKey, secretKey, accessChannel);
}
const SessionCredentials& DefaultMQPullConsumer::getSessionCredentials() const {
return impl->getSessionCredentials();
}
const std::string& DefaultMQPullConsumer::getInstanceName() const {
return impl->getInstanceName();
}
void DefaultMQPullConsumer::setInstanceName(const std::string& instanceName) {
impl->setInstanceName(instanceName);
}
const std::string& DefaultMQPullConsumer::getNameSpace() const {
return impl->getNameSpace();
}
void DefaultMQPullConsumer::setNameSpace(const std::string& nameSpace) {
impl->setNameSpace(nameSpace);
}
const std::string& DefaultMQPullConsumer::getGroupName() const {
return impl->getGroupName();
}
void DefaultMQPullConsumer::setGroupName(const std::string& groupName) {
impl->setGroupName(groupName);
}
void DefaultMQPullConsumer::setEnableSsl(bool enableSsl) {
impl->setEnableSsl(enableSsl);
}
bool DefaultMQPullConsumer::getEnableSsl() const {
return impl->getEnableSsl();
}
void DefaultMQPullConsumer::setSslPropertyFile(const std::string& sslPropertyFile) {
impl->setSslPropertyFile(sslPropertyFile);
}
const std::string& DefaultMQPullConsumer::getSslPropertyFile() const {
return impl->getSslPropertyFile();
}
void DefaultMQPullConsumer::setLogLevel(elogLevel inputLevel) {
impl->setLogLevel(inputLevel);
}
elogLevel DefaultMQPullConsumer::getLogLevel() {
return impl->getLogLevel();
}
void DefaultMQPullConsumer::setLogFileSizeAndNum(int fileNum, long perFileSize) {
impl->setLogFileSizeAndNum(fileNum, perFileSize);
}
// void DefaultMQPullConsumer::setUnitName(std::string unitName) {
// impl->setUnitName(unitName);
// }
// const std::string& DefaultMQPullConsumer::getUnitName() const {
// return impl->getUnitName();
// }
void DefaultMQPullConsumer::fetchSubscribeMessageQueues(const std::string& topic, std::vector<MQMessageQueue>& mqs) {
impl->fetchSubscribeMessageQueues(topic, mqs);
}
void DefaultMQPullConsumer::persistConsumerOffset() {
impl->persistConsumerOffset();
}
void DefaultMQPullConsumer::persistConsumerOffsetByResetOffset() {
impl->persistConsumerOffsetByResetOffset();
}
void DefaultMQPullConsumer::updateTopicSubscribeInfo(const std::string& topic, std::vector<MQMessageQueue>& info) {
impl->updateTopicSubscribeInfo(topic, info);
}
ConsumeFromWhere DefaultMQPullConsumer::getConsumeFromWhere() {
return impl->getConsumeFromWhere();
}
void DefaultMQPullConsumer::getSubscriptions(std::vector<SubscriptionData>& subData) {
impl->getSubscriptions(subData);
}
void DefaultMQPullConsumer::updateConsumeOffset(const MQMessageQueue& mq, int64 offset) {
impl->updateConsumeOffset(mq, offset);
}
void DefaultMQPullConsumer::removeConsumeOffset(const MQMessageQueue& mq) {
impl->removeConsumeOffset(mq);
}
void DefaultMQPullConsumer::registerMessageQueueListener(const std::string& topic, MQueueListener* pListener) {
impl->registerMessageQueueListener(topic, pListener);
}
PullResult DefaultMQPullConsumer::pull(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums) {
return impl->pull(mq, subExpression, offset, maxNums);
}
void DefaultMQPullConsumer::pull(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) {
impl->pull(mq, subExpression, offset, maxNums, pPullCallback);
}
PullResult DefaultMQPullConsumer::pullBlockIfNotFound(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums) {
return impl->pullBlockIfNotFound(mq, subExpression, offset, maxNums);
}
void DefaultMQPullConsumer::pullBlockIfNotFound(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) {
impl->pullBlockIfNotFound(mq, subExpression, offset, maxNums, pPullCallback);
}
int64 DefaultMQPullConsumer::fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore) {
return impl->fetchConsumeOffset(mq, fromStore);
}
void DefaultMQPullConsumer::fetchMessageQueuesInBalance(const std::string& topic, std::vector<MQMessageQueue> mqs) {
impl->fetchMessageQueuesInBalance(topic, mqs);
}
void DefaultMQPullConsumer::persistConsumerOffset4PullConsumer(const MQMessageQueue& mq) {
// impl->persistConsumerOffsetByResetOffset(mq);
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,421 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "DefaultMQPullConsumerImpl.h"
#include "AsyncArg.h"
#include "CommunicationMode.h"
#include "FilterAPI.h"
#include "Logging.h"
#include "MQClientFactory.h"
#include "MessageAccessor.h"
#include "NameSpaceUtil.h"
#include "OffsetStore.h"
#include "PullAPIWrapper.h"
#include "PullSysFlag.h"
#include "Rebalance.h"
#include "Validators.h"
namespace rocketmq {
//<!***************************************************************************
DefaultMQPullConsumerImpl::DefaultMQPullConsumerImpl(const string& groupname)
: m_pMessageQueueListener(NULL),
m_pOffsetStore(NULL),
m_pRebalance(NULL),
m_pPullAPIWrapper(NULL)
{
//<!set default group name;
string gname = groupname.empty() ? DEFAULT_CONSUMER_GROUP : groupname;
setGroupName(gname);
setMessageModel(CLUSTERING);
}
DefaultMQPullConsumerImpl::~DefaultMQPullConsumerImpl() {
m_pMessageQueueListener = NULL;
deleteAndZero(m_pRebalance);
deleteAndZero(m_pOffsetStore);
deleteAndZero(m_pPullAPIWrapper);
}
// MQConsumer
//<!************************************************************************
void DefaultMQPullConsumerImpl::start() {
#ifndef WIN32
/* Ignore the SIGPIPE */
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction(SIGPIPE, &sa, 0);
#endif
LOG_INFO("###Current Pull Consumer@%s", getClientVersionString().c_str());
dealWithNameSpace();
showClientConfigs();
switch (m_serviceState) {
case CREATE_JUST: {
m_serviceState = START_FAILED;
DefaultMQClient::start();
LOG_INFO("DefaultMQPullConsumerImpl:%s start", m_GroupName.c_str());
//<!create rebalance;
m_pRebalance = new RebalancePull(this, getFactory());
string groupname = getGroupName();
m_pPullAPIWrapper = new PullAPIWrapper(getFactory(), groupname);
//<!data;
checkConfig();
copySubscription();
//<! registe;
bool registerOK = getFactory()->registerConsumer(this);
if (!registerOK) {
m_serviceState = CREATE_JUST;
THROW_MQEXCEPTION(
MQClientException,
"The cousumer group[" + getGroupName() + "] has been created before, specify another name please.", -1);
}
//<!msg model;
switch (getMessageModel()) {
case BROADCASTING:
m_pOffsetStore = new LocalFileOffsetStore(groupname, getFactory());
break;
case CLUSTERING:
m_pOffsetStore = new RemoteBrokerOffsetStore(groupname, getFactory());
break;
}
bool bStartFailed = false;
string errorMsg;
try {
m_pOffsetStore->load();
} catch (MQClientException& e) {
bStartFailed = true;
errorMsg = std::string(e.what());
}
getFactory()->start();
m_serviceState = RUNNING;
if (bStartFailed) {
shutdown();
THROW_MQEXCEPTION(MQClientException, errorMsg, -1);
}
break;
}
case RUNNING:
case START_FAILED:
case SHUTDOWN_ALREADY:
break;
default:
break;
}
}
void DefaultMQPullConsumerImpl::shutdown() {
switch (m_serviceState) {
case RUNNING: {
LOG_INFO("DefaultMQPullConsumerImpl:%s shutdown", m_GroupName.c_str());
persistConsumerOffset();
getFactory()->unregisterConsumer(this);
getFactory()->shutdown();
m_serviceState = SHUTDOWN_ALREADY;
break;
}
case SHUTDOWN_ALREADY:
case CREATE_JUST:
break;
default:
break;
}
}
bool DefaultMQPullConsumerImpl::sendMessageBack(MQMessageExt& msg, int delayLevel, string& brokerName) {
return true;
}
void DefaultMQPullConsumerImpl::fetchSubscribeMessageQueues(const string& topic, vector<MQMessageQueue>& mqs) {
mqs.clear();
try {
const string localTopic = NameSpaceUtil::withNameSpace(topic, getNameSpace());
getFactory()->fetchSubscribeMessageQueues(localTopic, mqs, getSessionCredentials());
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
}
}
void DefaultMQPullConsumerImpl::updateTopicSubscribeInfo(const string& topic, vector<MQMessageQueue>& info) {}
void DefaultMQPullConsumerImpl::registerMessageQueueListener(const string& topic, MQueueListener* pListener) {
m_registerTopics.insert(topic);
if (pListener) {
m_pMessageQueueListener = pListener;
}
}
PullResult DefaultMQPullConsumerImpl::pull(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums) {
return pullSyncImpl(mq, subExpression, offset, maxNums, false);
}
void DefaultMQPullConsumerImpl::pull(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) {
pullAsyncImpl(mq, subExpression, offset, maxNums, false, pPullCallback);
}
PullResult DefaultMQPullConsumerImpl::pullBlockIfNotFound(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums) {
return pullSyncImpl(mq, subExpression, offset, maxNums, true);
}
void DefaultMQPullConsumerImpl::pullBlockIfNotFound(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) {
pullAsyncImpl(mq, subExpression, offset, maxNums, true, pPullCallback);
}
PullResult DefaultMQPullConsumerImpl::pullSyncImpl(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums,
bool block) {
if (offset < 0)
THROW_MQEXCEPTION(MQClientException, "offset < 0", -1);
if (maxNums <= 0)
THROW_MQEXCEPTION(MQClientException, "maxNums <= 0", -1);
//<!auto subscript,all sub;
subscriptionAutomatically(mq.getTopic());
int sysFlag = PullSysFlag::buildSysFlag(false, block, true, false);
//<!this sub;
unique_ptr<SubscriptionData> pSData(FilterAPI::buildSubscriptionData(mq.getTopic(), subExpression));
int timeoutMillis = block ? 1000 * 30 : 1000 * 10;
try {
unique_ptr<PullResult> pullResult(m_pPullAPIWrapper->pullKernelImpl(mq, // 1
pSData->getSubString(), // 2
0L, // 3
offset, // 4
maxNums, // 5
sysFlag, // 6
0, // 7
1000 * 20, // 8
timeoutMillis, // 9
ComMode_SYNC, // 10
NULL, //<!callback;
getSessionCredentials(), NULL));
PullResult pr = m_pPullAPIWrapper->processPullResult(mq, pullResult.get(), pSData.get());
if (m_useNameSpaceMode) {
MessageAccessor::withoutNameSpace(pr.msgFoundList, m_nameSpace);
}
return pr;
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
}
return PullResult(BROKER_TIMEOUT);
}
void DefaultMQPullConsumerImpl::pullAsyncImpl(const MQMessageQueue& mq,
const string& subExpression,
int64 offset,
int maxNums,
bool block,
PullCallback* pPullCallback) {
if (offset < 0)
THROW_MQEXCEPTION(MQClientException, "offset < 0", -1);
if (maxNums <= 0)
THROW_MQEXCEPTION(MQClientException, "maxNums <= 0", -1);
if (!pPullCallback)
THROW_MQEXCEPTION(MQClientException, "pPullCallback is null", -1);
//<!auto subscript,all sub;
subscriptionAutomatically(mq.getTopic());
int sysFlag = PullSysFlag::buildSysFlag(false, block, true, false);
//<!this sub;
unique_ptr<SubscriptionData> pSData(FilterAPI::buildSubscriptionData(mq.getTopic(), subExpression));
int timeoutMillis = block ? 1000 * 30 : 1000 * 10;
//<!<21><EFBFBD><ECB2BD><EFBFBD><EFBFBD>;
AsyncArg arg;
arg.mq = mq;
arg.subData = *pSData;
arg.pPullWrapper = m_pPullAPIWrapper;
try {
// not support name space
unique_ptr<PullResult> pullResult(m_pPullAPIWrapper->pullKernelImpl(mq, // 1
pSData->getSubString(), // 2
0L, // 3
offset, // 4
maxNums, // 5
sysFlag, // 6
0, // 7
1000 * 20, // 8
timeoutMillis, // 9
ComMode_ASYNC, // 10
pPullCallback, getSessionCredentials(), &arg));
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
}
}
void DefaultMQPullConsumerImpl::subscriptionAutomatically(const string& topic) {
SubscriptionData* pSdata = m_pRebalance->getSubscriptionData(topic);
if (pSdata == NULL) {
unique_ptr<SubscriptionData> subscriptionData(FilterAPI::buildSubscriptionData(topic, SUB_ALL));
m_pRebalance->setSubscriptionData(topic, subscriptionData.release());
}
}
void DefaultMQPullConsumerImpl::updateConsumeOffset(const MQMessageQueue& mq, int64 offset) {
m_pOffsetStore->updateOffset(mq, offset);
}
void DefaultMQPullConsumerImpl::removeConsumeOffset(const MQMessageQueue& mq) {
m_pOffsetStore->removeOffset(mq);
}
int64 DefaultMQPullConsumerImpl::fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore) {
return m_pOffsetStore->readOffset(mq, fromStore ? READ_FROM_STORE : MEMORY_FIRST_THEN_STORE, getSessionCredentials());
}
void DefaultMQPullConsumerImpl::persistConsumerOffset() {
/*As do not execute rebalance for pullConsumer now, requestTable is always
empty
map<MQMessageQueue, PullRequest*> requestTable =
m_pRebalance->getPullRequestTable();
map<MQMessageQueue, PullRequest*>::iterator it = requestTable.begin();
vector<MQMessageQueue> mqs;
for (; it != requestTable.end(); ++it)
{
if (it->second)
{
mqs.push_back(it->first);
}
}
m_pOffsetStore->persistAll(mqs);*/
}
void DefaultMQPullConsumerImpl::persistConsumerOffsetByResetOffset() {}
void DefaultMQPullConsumerImpl::persistConsumerOffset4PullConsumer(const MQMessageQueue& mq) {
if (isServiceStateOk()) {
m_pOffsetStore->persist(mq, getSessionCredentials());
}
}
void DefaultMQPullConsumerImpl::fetchMessageQueuesInBalance(const string& topic, vector<MQMessageQueue> mqs) {}
void DefaultMQPullConsumerImpl::checkConfig() {
string groupname = getGroupName();
// check consumerGroup
Validators::checkGroup(groupname);
// consumerGroup
if (!groupname.compare(DEFAULT_CONSUMER_GROUP)) {
THROW_MQEXCEPTION(MQClientException, "consumerGroup can not equal DEFAULT_CONSUMER", -1);
}
if (getMessageModel() != BROADCASTING && getMessageModel() != CLUSTERING) {
THROW_MQEXCEPTION(MQClientException, "messageModel is valid ", -1);
}
}
void DefaultMQPullConsumerImpl::doRebalance() {}
void DefaultMQPullConsumerImpl::copySubscription() {
set<string>::iterator it = m_registerTopics.begin();
for (; it != m_registerTopics.end(); ++it) {
unique_ptr<SubscriptionData> subscriptionData(FilterAPI::buildSubscriptionData((*it), SUB_ALL));
m_pRebalance->setSubscriptionData((*it), subscriptionData.release());
}
}
ConsumeType DefaultMQPullConsumerImpl::getConsumeType() {
return CONSUME_ACTIVELY;
}
ConsumeFromWhere DefaultMQPullConsumerImpl::getConsumeFromWhere() {
return CONSUME_FROM_LAST_OFFSET;
}
void DefaultMQPullConsumerImpl::getSubscriptions(vector<SubscriptionData>& result) {
set<string>::iterator it = m_registerTopics.begin();
for (; it != m_registerTopics.end(); ++it) {
SubscriptionData ms(*it, SUB_ALL);
result.push_back(ms);
}
}
bool DefaultMQPullConsumerImpl::producePullMsgTask(boost::weak_ptr<PullRequest> pullRequest) {
return true;
}
Rebalance* DefaultMQPullConsumerImpl::getRebalance() const {
return NULL;
}
// we should deal with name space before producer start.
bool DefaultMQPullConsumerImpl::dealWithNameSpace() {
string ns = getNameSpace();
if (ns.empty()) {
string nsAddr = getNamesrvAddr();
if (!NameSpaceUtil::checkNameSpaceExistInNameServer(nsAddr)) {
return true;
}
ns = NameSpaceUtil::getNameSpaceFromNsURL(nsAddr);
// reset namespace
setNameSpace(ns);
}
// reset group name
if (!NameSpaceUtil::hasNameSpace(getGroupName(), ns)) {
string fullGID = NameSpaceUtil::withNameSpace(getGroupName(), ns);
setGroupName(fullGID);
}
set<string> tmpTopics;
for (auto iter = m_registerTopics.begin(); iter != m_registerTopics.end(); iter++) {
string topic = *iter;
if (!NameSpaceUtil::hasNameSpace(topic, ns)) {
LOG_INFO("Update Subscribe Topic[%s] with NameSpace:%s", topic.c_str(), ns.c_str());
topic = NameSpaceUtil::withNameSpace(topic, ns);
// let other mode to known, the name space model opened.
m_useNameSpaceMode = true;
}
tmpTopics.insert(topic);
}
m_registerTopics.swap(tmpTopics);
return true;
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __DEFAULTMQPULLCONSUMERIMPL_H__
#define __DEFAULTMQPULLCONSUMERIMPL_H__
#include <set>
#include <string>
#include "MQConsumer.h"
#include "MQMessageQueue.h"
#include "MQueueListener.h"
#include "RocketMQClient.h"
namespace rocketmq {
class Rebalance;
class SubscriptionData;
class OffsetStore;
class PullAPIWrapper;
class ConsumerRunningInfo;
//<!***************************************************************************
class DefaultMQPullConsumerImpl : public MQConsumer {
public:
DefaultMQPullConsumerImpl(const std::string& groupname);
virtual ~DefaultMQPullConsumerImpl();
//<!begin mqadmin;
virtual void start();
virtual void shutdown();
//<!end mqadmin;
//<!begin MQConsumer
virtual bool sendMessageBack(MQMessageExt& msg, int delayLevel, std::string& brokerName);
virtual void fetchSubscribeMessageQueues(const std::string& topic, std::vector<MQMessageQueue>& mqs);
virtual void doRebalance();
virtual void persistConsumerOffset();
virtual void persistConsumerOffsetByResetOffset();
virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector<MQMessageQueue>& info);
virtual ConsumeType getConsumeType();
virtual ConsumeFromWhere getConsumeFromWhere();
virtual void getSubscriptions(std::vector<SubscriptionData>&);
virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset);
virtual void removeConsumeOffset(const MQMessageQueue& mq);
virtual bool producePullMsgTask(boost::weak_ptr<PullRequest> pullRequest);
virtual Rebalance* getRebalance() const;
//<!end MQConsumer;
void registerMessageQueueListener(const std::string& topic, MQueueListener* pListener);
/**
* Pull message from specified queue, if no msg in queue, return directly
*
* @param mq
* specify the pulled queue
* @param subExpression
* set filter expression for pulled msg, broker will filter msg actively
* Now only OR operation is supported, eg: "tag1 || tag2 || tag3"
* if subExpression is setted to "null" or "*", all msg will be subscribed
* @param offset
* specify the started pull offset
* @param maxNums
* specify max msg num by per pull
* @return
* PullResult
*/
virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums);
virtual void pull(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback);
/**
* pull msg from specified queue, if no msg, broker will suspend the pull request 20s
*
* @param mq
* specify the pulled queue
* @param subExpression
* set filter expression for pulled msg, broker will filter msg actively
* Now only OR operation is supported, eg: "tag1 || tag2 || tag3"
* if subExpression is setted to "null" or "*", all msg will be subscribed
* @param offset
* specify the started pull offset
* @param maxNums
* specify max msg num by per pull
* @return
* accroding to PullResult
*/
PullResult pullBlockIfNotFound(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums);
void pullBlockIfNotFound(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback);
virtual ConsumerRunningInfo* getConsumerRunningInfo() { return NULL; }
int64 fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore);
void fetchMessageQueuesInBalance(const std::string& topic, std::vector<MQMessageQueue> mqs);
// temp persist consumer offset interface, only valid with
// RemoteBrokerOffsetStore, updateConsumeOffset should be called before.
void persistConsumerOffset4PullConsumer(const MQMessageQueue& mq);
private:
void checkConfig();
void copySubscription();
bool dealWithNameSpace();
PullResult pullSyncImpl(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
bool block);
void pullAsyncImpl(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
bool block,
PullCallback* pPullCallback);
void subscriptionAutomatically(const std::string& topic);
private:
std::set<std::string> m_registerTopics;
MQueueListener* m_pMessageQueueListener;
OffsetStore* m_pOffsetStore;
Rebalance* m_pRebalance;
PullAPIWrapper* m_pPullAPIWrapper;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,228 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "DefaultMQPushConsumer.h"
#include <MQVersion.h>
#include "DefaultMQPushConsumerImpl.h"
namespace rocketmq {
DefaultMQPushConsumer::DefaultMQPushConsumer(const std::string& groupName) {
impl = new DefaultMQPushConsumerImpl(groupName);
}
DefaultMQPushConsumer::~DefaultMQPushConsumer() {
delete impl;
}
void DefaultMQPushConsumer::start() {
impl->start();
}
void DefaultMQPushConsumer::shutdown() {
impl->shutdown();
}
std::string DefaultMQPushConsumer::version() {
std::string versions = impl->getClientVersionString();
/*versions.append(", PROTOCOL VERSION: ")
.append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion))
.append(", LANGUAGE: ")
.append(MQVersion::s_CurrentLanguage);*/
return versions;
}
// ConsumeType DefaultMQPushConsumer::getConsumeType() {
// return impl->getConsumeType();
//}
ConsumeFromWhere DefaultMQPushConsumer::getConsumeFromWhere() {
return impl->getConsumeFromWhere();
}
void DefaultMQPushConsumer::setConsumeFromWhere(ConsumeFromWhere consumeFromWhere) {
impl->setConsumeFromWhere(consumeFromWhere);
}
void DefaultMQPushConsumer::registerMessageListener(MQMessageListener* pMessageListener) {
impl->registerMessageListener(pMessageListener);
}
MessageListenerType DefaultMQPushConsumer::getMessageListenerType() {
return impl->getMessageListenerType();
}
void DefaultMQPushConsumer::subscribe(const std::string& topic, const std::string& subExpression) {
impl->subscribe(topic, subExpression);
}
void DefaultMQPushConsumer::setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize) {
impl->setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
}
int DefaultMQPushConsumer::getConsumeMessageBatchMaxSize() const {
return impl->getConsumeMessageBatchMaxSize();
}
/*
set consuming thread count, default value is cpu cores
*/
void DefaultMQPushConsumer::setConsumeThreadCount(int threadCount) {
impl->setConsumeThreadCount(threadCount);
}
int DefaultMQPushConsumer::getConsumeThreadCount() const {
return impl->getConsumeThreadCount();
}
void DefaultMQPushConsumer::setMaxReconsumeTimes(int maxReconsumeTimes) {
impl->setMaxReconsumeTimes(maxReconsumeTimes);
}
int DefaultMQPushConsumer::getMaxReconsumeTimes() const {
return impl->getMaxReconsumeTimes();
}
/*
set pullMsg thread count, default value is cpu cores
*/
void DefaultMQPushConsumer::setPullMsgThreadPoolCount(int threadCount) {
impl->setPullMsgThreadPoolCount(threadCount);
}
int DefaultMQPushConsumer::getPullMsgThreadPoolCount() const {
return impl->getPullMsgThreadPoolCount();
}
/*
set max cache msg size perQueue in memory if consumer could not consume msgs
immediately
default maxCacheMsgSize perQueue is 1000, set range is:1~65535
*/
void DefaultMQPushConsumer::setMaxCacheMsgSizePerQueue(int maxCacheSize) {
impl->setMaxCacheMsgSizePerQueue(maxCacheSize);
}
int DefaultMQPushConsumer::getMaxCacheMsgSizePerQueue() const {
return impl->getMaxCacheMsgSizePerQueue();
}
MessageModel DefaultMQPushConsumer::getMessageModel() const {
return impl->getMessageModel();
}
void DefaultMQPushConsumer::setMessageModel(MessageModel messageModel) {
impl->setMessageModel(messageModel);
}
const std::string& DefaultMQPushConsumer::getNamesrvAddr() const {
return impl->getNamesrvAddr();
}
void DefaultMQPushConsumer::setNamesrvAddr(const std::string& namesrvAddr) {
impl->setNamesrvAddr(namesrvAddr);
}
const std::string& DefaultMQPushConsumer::getNamesrvDomain() const {
return impl->getNamesrvDomain();
}
void DefaultMQPushConsumer::setNamesrvDomain(const std::string& namesrvDomain) {
impl->setNamesrvDomain(namesrvDomain);
}
void DefaultMQPushConsumer::setSessionCredentials(const std::string& accessKey,
const std::string& secretKey,
const std::string& accessChannel) {
impl->setSessionCredentials(accessKey, secretKey, accessChannel);
}
const SessionCredentials& DefaultMQPushConsumer::getSessionCredentials() const {
return impl->getSessionCredentials();
}
const std::string& DefaultMQPushConsumer::getInstanceName() const {
return impl->getInstanceName();
}
void DefaultMQPushConsumer::setInstanceName(const std::string& instanceName) {
impl->setInstanceName(instanceName);
}
const std::string& DefaultMQPushConsumer::getNameSpace() const {
return impl->getNameSpace();
}
void DefaultMQPushConsumer::setNameSpace(const std::string& nameSpace) {
impl->setNameSpace(nameSpace);
}
const std::string& DefaultMQPushConsumer::getGroupName() const {
return impl->getGroupName();
}
void DefaultMQPushConsumer::setGroupName(const std::string& groupName) {
impl->setGroupName(groupName);
}
void DefaultMQPushConsumer::setEnableSsl(bool enableSsl) {
impl->setEnableSsl(enableSsl);
}
bool DefaultMQPushConsumer::getEnableSsl() const {
return impl->getEnableSsl();
}
void DefaultMQPushConsumer::setSslPropertyFile(const std::string& sslPropertyFile) {
impl->setSslPropertyFile(sslPropertyFile);
}
const std::string& DefaultMQPushConsumer::getSslPropertyFile() const {
return impl->getSslPropertyFile();
}
void DefaultMQPushConsumer::setLogLevel(elogLevel inputLevel) {
impl->setLogLevel(inputLevel);
}
elogLevel DefaultMQPushConsumer::getLogLevel() {
return impl->getLogLevel();
}
void DefaultMQPushConsumer::setLogFileSizeAndNum(int fileNum, long perFileSize) {
impl->setLogFileSizeAndNum(fileNum, perFileSize);
}
void DefaultMQPushConsumer::setUnitName(std::string unitName) {
impl->setUnitName(unitName);
}
const std::string& DefaultMQPushConsumer::getUnitName() const {
return impl->getUnitName();
}
void DefaultMQPushConsumer::setTcpTransportPullThreadNum(int num) {
impl->setTcpTransportPullThreadNum(num);
}
int DefaultMQPushConsumer::getTcpTransportPullThreadNum() const {
return impl->getTcpTransportPullThreadNum();
}
void DefaultMQPushConsumer::setTcpTransportConnectTimeout(uint64_t timeout) {
impl->setTcpTransportConnectTimeout(timeout);
}
uint64_t DefaultMQPushConsumer::getTcpTransportConnectTimeout() const {
return impl->getTcpTransportConnectTimeout();
}
void DefaultMQPushConsumer::setTcpTransportTryLockTimeout(uint64_t timeout) {
impl->setTcpTransportTryLockTimeout(timeout);
}
uint64_t DefaultMQPushConsumer::getTcpTransportTryLockTimeout() const {
return impl->getTcpTransportTryLockTimeout();
}
void DefaultMQPushConsumer::setAsyncPull(bool asyncFlag) {
impl->setAsyncPull(asyncFlag);
}
void DefaultMQPushConsumer::setMessageTrace(bool messageTrace) {
impl->setMessageTrace(messageTrace);
}
bool DefaultMQPushConsumer::getMessageTrace() const {
return impl->getMessageTrace();
}
} // namespace rocketmq

View File

@@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __DEFAULTMQPUSHCONSUMERIMPL_H__
#define __DEFAULTMQPUSHCONSUMERIMPL_H__
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread.hpp>
#include <string>
#include "AsyncCallback.h"
#include "ConsumeMessageContext.h"
#include "ConsumeMessageHook.h"
#include "DefaultMQProducerImpl.h"
#include "MQConsumer.h"
#include "MQMessageListener.h"
#include "MQMessageQueue.h"
namespace rocketmq {
class Rebalance;
class SubscriptionData;
class OffsetStore;
class PullAPIWrapper;
class PullRequest;
class ConsumeMsgService;
class TaskQueue;
class TaskThread;
class AsyncPullCallback;
class ConsumerRunningInfo;
//<!***************************************************************************
class DefaultMQPushConsumerImpl : public MQConsumer {
public:
DefaultMQPushConsumerImpl();
DefaultMQPushConsumerImpl(const std::string& groupname);
void boost_asio_work();
virtual ~DefaultMQPushConsumerImpl();
//<!begin mqadmin;
virtual void start();
virtual void shutdown();
//<!end mqadmin;
//<!begin MQConsumer
virtual bool sendMessageBack(MQMessageExt& msg, int delayLevel, std::string& brokerName);
virtual void fetchSubscribeMessageQueues(const std::string& topic, std::vector<MQMessageQueue>& mqs);
virtual void doRebalance();
virtual void persistConsumerOffset();
virtual void persistConsumerOffsetByResetOffset();
virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector<MQMessageQueue>& info);
virtual ConsumeType getConsumeType();
virtual ConsumeFromWhere getConsumeFromWhere();
void setConsumeFromWhere(ConsumeFromWhere consumeFromWhere);
virtual void getSubscriptions(std::vector<SubscriptionData>&);
virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset);
virtual void removeConsumeOffset(const MQMessageQueue& mq);
virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums) {
return PullResult();
}
virtual void pull(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) {}
virtual ConsumerRunningInfo* getConsumerRunningInfo();
//<!end MQConsumer;
void registerMessageListener(MQMessageListener* pMessageListener);
MessageListenerType getMessageListenerType();
void subscribe(const std::string& topic, const std::string& subExpression);
OffsetStore* getOffsetStore() const;
virtual Rebalance* getRebalance() const;
ConsumeMsgService* getConsumerMsgService() const;
virtual bool producePullMsgTask(boost::weak_ptr<PullRequest>);
virtual bool producePullMsgTaskLater(boost::weak_ptr<PullRequest>, int millis);
static void static_triggerNextPullRequest(void* context,
boost::asio::deadline_timer* t,
boost::weak_ptr<PullRequest>);
void triggerNextPullRequest(boost::asio::deadline_timer* t, boost::weak_ptr<PullRequest>);
void runPullMsgQueue(TaskQueue* pTaskQueue);
void pullMessage(boost::weak_ptr<PullRequest> pullrequest);
void pullMessageAsync(boost::weak_ptr<PullRequest> pullrequest);
void setAsyncPull(bool asyncFlag);
AsyncPullCallback* getAsyncPullCallBack(boost::weak_ptr<PullRequest>, MQMessageQueue msgQueue);
void shutdownAsyncPullCallBack();
/*
for orderly consume, set the pull num of message size by each pullMsg,
default value is 1;
*/
void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize);
int getConsumeMessageBatchMaxSize() const;
/*
set consuming thread count, default value is cpu cores
*/
void setConsumeThreadCount(int threadCount);
int getConsumeThreadCount() const;
void setMaxReconsumeTimes(int maxReconsumeTimes);
int getMaxReconsumeTimes() const;
/*
set pullMsg thread count, default value is cpu cores
*/
void setPullMsgThreadPoolCount(int threadCount);
int getPullMsgThreadPoolCount() const;
/*
set max cache msg size perQueue in memory if consumer could not consume msgs
immediately
default maxCacheMsgSize perQueue is 1000, set range is:1~65535
*/
void setMaxCacheMsgSizePerQueue(int maxCacheSize);
int getMaxCacheMsgSizePerQueue() const;
void submitSendTraceRequest(MQMessage& msg, SendCallback* pSendCallback);
bool hasConsumeMessageHook();
void registerConsumeMessageHook(std::shared_ptr<ConsumeMessageHook>& hook);
void setDefaultMqProducerImpl(DefaultMQProducerImpl* DefaultMqProducerImpl);
void executeConsumeMessageHookBefore(ConsumeMessageContext* context);
void executeConsumeMessageHookAfter(ConsumeMessageContext* context);
private:
void checkConfig();
void copySubscription();
void updateTopicSubscribeInfoWhenSubscriptionChanged();
bool dealWithNameSpace();
void logConfigs();
bool dealWithMessageTrace();
void createMessageTraceInnerProducer();
void shutdownMessageTraceInnerProducer();
private:
uint64_t m_startTime;
ConsumeFromWhere m_consumeFromWhere;
std::map<std::string, std::string> m_subTopics;
int m_consumeThreadCount;
OffsetStore* m_pOffsetStore;
Rebalance* m_pRebalance;
PullAPIWrapper* m_pPullAPIWrapper;
ConsumeMsgService* m_consumerService;
MQMessageListener* m_pMessageListener;
int m_consumeMessageBatchMaxSize;
int m_maxMsgCacheSize;
int m_maxReconsumeTimes = -1;
boost::asio::io_service m_async_ioService;
boost::scoped_ptr<boost::thread> m_async_service_thread;
typedef std::map<MQMessageQueue, AsyncPullCallback*> PullMAP;
PullMAP m_PullCallback;
bool m_asyncPull;
int m_asyncPullTimeout;
int m_pullMsgThreadPoolNum;
private:
TaskQueue* m_pullmsgQueue;
std::unique_ptr<boost::thread> m_pullmsgThread;
// used for trace
std::vector<std::shared_ptr<ConsumeMessageHook> > m_consumeMessageHookList;
std::shared_ptr<DefaultMQProducerImpl> m_DefaultMQProducerImpl;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __FINDBROKERRESULT_H__
#define __FINDBROKERRESULT_H__
namespace rocketmq {
//<!************************************************************************
struct FindBrokerResult {
FindBrokerResult(const std::string& sbrokerAddr, bool bslave) : brokerAddr(sbrokerAddr), slave(bslave) {}
public:
std::string brokerAddr;
bool slave;
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,343 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "OffsetStore.h"
#include "Logging.h"
#include "MQClientFactory.h"
#include "MessageQueue.h"
#include <fstream>
#include <sstream>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/filesystem.hpp>
#include <boost/serialization/map.hpp>
namespace rocketmq {
//<!***************************************************************************
OffsetStore::OffsetStore(const string& groupName, MQClientFactory* pfactory)
: m_groupName(groupName), m_pClientFactory(pfactory) {}
OffsetStore::~OffsetStore() {
m_pClientFactory = NULL;
m_offsetTable.clear();
}
//<!***************************************************************************
LocalFileOffsetStore::LocalFileOffsetStore(const string& groupName, MQClientFactory* pfactory)
: OffsetStore(groupName, pfactory) {
MQConsumer* pConsumer = pfactory->selectConsumer(groupName);
if (pConsumer) {
LOG_INFO("new LocalFileOffsetStore");
string directoryName = UtilAll::getLocalAddress() + "@" + pConsumer->getInstanceName();
m_storePath = ".rocketmq_offsets/" + directoryName + "/" + groupName;
string homeDir(UtilAll::getHomeDirectory());
m_storeFile = homeDir + "/" + m_storePath + "/offsets.Json";
string storePath(homeDir);
storePath.append("/").append(m_storePath);
boost::filesystem::path dir(storePath);
boost::system::error_code ec;
if (!boost::filesystem::exists(dir, ec)) {
if (!boost::filesystem::create_directories(dir, ec)) {
LOG_ERROR("create offset store dir:%s error", storePath.c_str());
string errorMsg("create offset store dir fail: ");
errorMsg.append(storePath);
THROW_MQEXCEPTION(MQClientException, errorMsg, -1);
}
}
}
}
LocalFileOffsetStore::~LocalFileOffsetStore() {}
void LocalFileOffsetStore::load() {
std::ifstream ifs(m_storeFile.c_str(), std::ios::in);
if (ifs.good()) {
if (ifs.is_open()) {
if (ifs.peek() != std::ifstream::traits_type::eof()) {
map<string, int64> m_offsetTable_tmp;
boost::system::error_code e;
try {
boost::archive::text_iarchive ia(ifs);
ia >> m_offsetTable_tmp;
} catch (...) {
LOG_ERROR(
"load offset store file failed, please check whether file: %s is "
"cleared by operator, if so, delete this offsets.Json file and "
"then restart consumer",
m_storeFile.c_str());
ifs.close();
string errorMsg("load offset store file: ");
errorMsg.append(m_storeFile)
.append(
" failed, please check whether offsets.Json is cleared by "
"operator, if so, delete this offsets.Json file and then "
"restart consumer");
THROW_MQEXCEPTION(MQClientException, errorMsg, -1);
}
ifs.close();
for (map<string, int64>::iterator it = m_offsetTable_tmp.begin(); it != m_offsetTable_tmp.end(); ++it) {
// LOG_INFO("it->first:%s, it->second:%lld", it->first.c_str(),
// it->second);
Json::Reader reader;
Json::Value object;
reader.parse(it->first.c_str(), object);
MQMessageQueue mq(object["topic"].asString(), object["brokerName"].asString(), object["queueId"].asInt());
updateOffset(mq, it->second);
}
m_offsetTable_tmp.clear();
} else {
LOG_ERROR(
"open offset store file failed, please check whether file: %s is "
"cleared by operator, if so, delete this offsets.Json file and "
"then restart consumer",
m_storeFile.c_str());
THROW_MQEXCEPTION(MQClientException,
"open offset store file failed, please check whether "
"offsets.Json is cleared by operator, if so, delete "
"this offsets.Json file and then restart consumer",
-1);
}
} else {
LOG_ERROR(
"open offset store file failed, please check whether file:%s is "
"deleted by operator and then restart consumer",
m_storeFile.c_str());
THROW_MQEXCEPTION(MQClientException,
"open offset store file failed, please check "
"directory:%s is deleted by operator or offset.Json "
"file is cleared by operator, and then restart "
"consumer",
-1);
}
} else {
LOG_WARN(
"offsets.Json file not exist, maybe this is the first time "
"consumation");
}
}
void LocalFileOffsetStore::updateOffset(const MQMessageQueue& mq, int64 offset) {
boost::lock_guard<boost::mutex> lock(m_lock);
m_offsetTable[mq] = offset;
}
int64 LocalFileOffsetStore::readOffset(const MQMessageQueue& mq,
ReadOffsetType type,
const SessionCredentials& session_credentials) {
switch (type) {
case MEMORY_FIRST_THEN_STORE:
case READ_FROM_MEMORY: {
boost::lock_guard<boost::mutex> lock(m_lock);
MQ2OFFSET::iterator it = m_offsetTable.find(mq);
if (it != m_offsetTable.end()) {
return it->second;
} else if (READ_FROM_MEMORY == type) {
return -1;
}
}
case READ_FROM_STORE: {
try {
load();
} catch (MQException& e) {
LOG_ERROR("catch exception when load local file");
return -1;
}
boost::lock_guard<boost::mutex> lock(m_lock);
MQ2OFFSET::iterator it = m_offsetTable.find(mq);
if (it != m_offsetTable.end()) {
return it->second;
}
}
default:
break;
}
LOG_ERROR("can not readOffset from offsetStore.json, maybe first time consumation");
return -1;
}
void LocalFileOffsetStore::persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials) {}
void LocalFileOffsetStore::persistAll(const std::vector<MQMessageQueue>& mqs) {
boost::lock_guard<boost::mutex> lock(m_lock);
map<string, int64> m_offsetTable_tmp;
vector<MQMessageQueue>::const_iterator it = mqs.begin();
for (; it != mqs.end(); ++it) {
MessageQueue mq_tmp((*it).getTopic(), (*it).getBrokerName(), (*it).getQueueId());
string mqKey = mq_tmp.toJson().toStyledString();
m_offsetTable_tmp[mqKey] = m_offsetTable[*it];
}
std::ofstream s;
string storefile_bak(m_storeFile);
storefile_bak.append(".bak");
s.open(storefile_bak.c_str(), std::ios::out);
if (s.is_open()) {
try {
boost::archive::text_oarchive oa(s);
// Boost is nervous that archiving non-const class instances which might
// cause a problem with object tracking if different tracked objects use
// the same address.
oa << const_cast<const map<string, int64>&>(m_offsetTable_tmp);
} catch (...) {
LOG_ERROR("persist offset store file:%s failed", m_storeFile.c_str());
s.close();
THROW_MQEXCEPTION(MQClientException, "persistAll:open offset store file failed", -1);
}
s.close();
if (!UtilAll::ReplaceFile(storefile_bak, m_storeFile))
LOG_ERROR("could not rename bak file:%s", strerror(errno));
m_offsetTable_tmp.clear();
} else {
LOG_ERROR("open offset store file:%s failed", m_storeFile.c_str());
m_offsetTable_tmp.clear();
THROW_MQEXCEPTION(MQClientException, "persistAll:open offset store file failed", -1);
}
}
void LocalFileOffsetStore::removeOffset(const MQMessageQueue& mq) {}
//<!***************************************************************************
RemoteBrokerOffsetStore::RemoteBrokerOffsetStore(const string& groupName, MQClientFactory* pfactory)
: OffsetStore(groupName, pfactory) {}
RemoteBrokerOffsetStore::~RemoteBrokerOffsetStore() {}
void RemoteBrokerOffsetStore::load() {}
void RemoteBrokerOffsetStore::updateOffset(const MQMessageQueue& mq, int64 offset) {
boost::lock_guard<boost::mutex> lock(m_lock);
m_offsetTable[mq] = offset;
}
int64 RemoteBrokerOffsetStore::readOffset(const MQMessageQueue& mq,
ReadOffsetType type,
const SessionCredentials& session_credentials) {
switch (type) {
case MEMORY_FIRST_THEN_STORE:
case READ_FROM_MEMORY: {
boost::lock_guard<boost::mutex> lock(m_lock);
MQ2OFFSET::iterator it = m_offsetTable.find(mq);
if (it != m_offsetTable.end()) {
return it->second;
} else if (READ_FROM_MEMORY == type) {
return -1;
}
}
case READ_FROM_STORE: {
try {
int64 brokerOffset = fetchConsumeOffsetFromBroker(mq, session_credentials);
//<!update;
updateOffset(mq, brokerOffset);
return brokerOffset;
} catch (MQBrokerException& e) {
LOG_ERROR("%s", e.what());
return -1;
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
return -2;
}
}
default:
break;
}
return -1;
}
void RemoteBrokerOffsetStore::persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials) {
MQ2OFFSET offsetTable;
{
boost::lock_guard<boost::mutex> lock(m_lock);
offsetTable = m_offsetTable;
}
MQ2OFFSET::iterator it = offsetTable.find(mq);
if (it != offsetTable.end()) {
try {
updateConsumeOffsetToBroker(mq, it->second, session_credentials);
} catch (MQException& e) {
LOG_ERROR("updateConsumeOffsetToBroker %s ,offset:[%lld] error", mq.toString().c_str(), it->second);
}
}
}
void RemoteBrokerOffsetStore::persistAll(const std::vector<MQMessageQueue>& mq) {}
void RemoteBrokerOffsetStore::removeOffset(const MQMessageQueue& mq) {
boost::lock_guard<boost::mutex> lock(m_lock);
if (m_offsetTable.find(mq) != m_offsetTable.end())
m_offsetTable.erase(mq);
}
void RemoteBrokerOffsetStore::updateConsumeOffsetToBroker(const MQMessageQueue& mq,
int64 offset,
const SessionCredentials& session_credentials) {
unique_ptr<FindBrokerResult> pFindBrokerResult(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName()));
if (pFindBrokerResult == NULL) {
m_pClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials);
pFindBrokerResult.reset(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName()));
}
if (pFindBrokerResult != NULL) {
UpdateConsumerOffsetRequestHeader* pRequestHeader = new UpdateConsumerOffsetRequestHeader();
pRequestHeader->topic = mq.getTopic();
pRequestHeader->consumerGroup = m_groupName;
pRequestHeader->queueId = mq.getQueueId();
pRequestHeader->commitOffset = offset;
try {
LOG_INFO("oneway updateConsumeOffsetToBroker of mq:%s, its offset is:%lld", mq.toString().c_str(), offset);
return m_pClientFactory->getMQClientAPIImpl()->updateConsumerOffsetOneway(
pFindBrokerResult->brokerAddr, pRequestHeader, 1000 * 5, session_credentials);
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
}
}
LOG_WARN("The broker not exist");
}
int64 RemoteBrokerOffsetStore::fetchConsumeOffsetFromBroker(const MQMessageQueue& mq,
const SessionCredentials& session_credentials) {
unique_ptr<FindBrokerResult> pFindBrokerResult(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName()));
if (pFindBrokerResult == NULL) {
m_pClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials);
pFindBrokerResult.reset(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName()));
}
if (pFindBrokerResult != NULL) {
QueryConsumerOffsetRequestHeader* pRequestHeader = new QueryConsumerOffsetRequestHeader();
pRequestHeader->topic = mq.getTopic();
pRequestHeader->consumerGroup = m_groupName;
pRequestHeader->queueId = mq.getQueueId();
return m_pClientFactory->getMQClientAPIImpl()->queryConsumerOffset(pFindBrokerResult->brokerAddr, pRequestHeader,
1000 * 5, session_credentials);
} else {
LOG_ERROR("The broker not exist when fetchConsumeOffsetFromBroker");
THROW_MQEXCEPTION(MQClientException, "The broker not exist", -1);
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __OFFSETSTORE_H__
#define __OFFSETSTORE_H__
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <map>
#include "MQMessageQueue.h"
#include "SessionCredentials.h"
namespace rocketmq {
class MQClientFactory;
//<!***************************************************************************
enum ReadOffsetType {
// read offset from memory
READ_FROM_MEMORY,
// read offset from remoting
READ_FROM_STORE,
// read offset from memory firstly, then from remoting
MEMORY_FIRST_THEN_STORE,
};
//<!***************************************************************************
class OffsetStore {
public:
OffsetStore(const std::string& groupName, MQClientFactory*);
virtual ~OffsetStore();
virtual void load() = 0;
virtual void updateOffset(const MQMessageQueue& mq, int64 offset) = 0;
virtual int64 readOffset(const MQMessageQueue& mq,
ReadOffsetType type,
const SessionCredentials& session_credentials) = 0;
virtual void persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials) = 0;
virtual void persistAll(const std::vector<MQMessageQueue>& mq) = 0;
virtual void removeOffset(const MQMessageQueue& mq) = 0;
protected:
std::string m_groupName;
typedef std::map<MQMessageQueue, int64> MQ2OFFSET;
MQ2OFFSET m_offsetTable;
MQClientFactory* m_pClientFactory;
boost::mutex m_lock;
};
//<!***************************************************************************
class LocalFileOffsetStore : public OffsetStore {
public:
LocalFileOffsetStore(const std::string& groupName, MQClientFactory*);
virtual ~LocalFileOffsetStore();
virtual void load();
virtual void updateOffset(const MQMessageQueue& mq, int64 offset);
virtual int64 readOffset(const MQMessageQueue& mq,
ReadOffsetType type,
const SessionCredentials& session_credentials);
virtual void persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
virtual void persistAll(const std::vector<MQMessageQueue>& mq);
virtual void removeOffset(const MQMessageQueue& mq);
private:
std::string m_storePath;
std::string m_storeFile;
};
//<!***************************************************************************
class RemoteBrokerOffsetStore : public OffsetStore {
public:
RemoteBrokerOffsetStore(const std::string& groupName, MQClientFactory*);
virtual ~RemoteBrokerOffsetStore();
virtual void load();
virtual void updateOffset(const MQMessageQueue& mq, int64 offset);
virtual int64 readOffset(const MQMessageQueue& mq,
ReadOffsetType type,
const SessionCredentials& session_credentials);
virtual void persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
virtual void persistAll(const std::vector<MQMessageQueue>& mq);
virtual void removeOffset(const MQMessageQueue& mq);
private:
void updateConsumeOffsetToBroker(const MQMessageQueue& mq,
int64 offset,
const SessionCredentials& session_credentials);
int64 fetchConsumeOffsetFromBroker(const MQMessageQueue& mq, const SessionCredentials& session_credentials);
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,133 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PullAPIWrapper.h"
#include "CommunicationMode.h"
#include "MQClientFactory.h"
#include "PullResultExt.h"
#include "PullSysFlag.h"
namespace rocketmq {
//<!************************************************************************
PullAPIWrapper::PullAPIWrapper(MQClientFactory* mQClientFactory, const string& consumerGroup) {
m_MQClientFactory = mQClientFactory;
m_consumerGroup = consumerGroup;
}
PullAPIWrapper::~PullAPIWrapper() {
m_MQClientFactory = NULL;
m_pullFromWhichNodeTable.clear();
}
void PullAPIWrapper::updatePullFromWhichNode(const MQMessageQueue& mq, int brokerId) {
boost::lock_guard<boost::mutex> lock(m_lock);
m_pullFromWhichNodeTable[mq] = brokerId;
}
int PullAPIWrapper::recalculatePullFromWhichNode(const MQMessageQueue& mq) {
boost::lock_guard<boost::mutex> lock(m_lock);
if (m_pullFromWhichNodeTable.find(mq) != m_pullFromWhichNodeTable.end()) {
return m_pullFromWhichNodeTable[mq];
}
return MASTER_ID;
}
PullResult PullAPIWrapper::processPullResult(const MQMessageQueue& mq,
PullResult* pullResult,
SubscriptionData* subscriptionData) {
PullResultExt* pResultExt = static_cast<PullResultExt*>(pullResult);
if (pResultExt == NULL) {
string errMsg("The pullResult NULL of");
errMsg.append(mq.toString());
THROW_MQEXCEPTION(MQClientException, errMsg, -1);
}
//<!update;
updatePullFromWhichNode(mq, pResultExt->suggestWhichBrokerId);
vector<MQMessageExt> msgFilterList;
if (pResultExt->pullStatus == FOUND) {
//<!decode all msg list;
vector<MQMessageExt> msgAllList;
MQDecoder::decodes(&pResultExt->msgMemBlock, msgAllList);
//<!filter msg list again;
if (subscriptionData != NULL && !subscriptionData->getTagsSet().empty()) {
msgFilterList.reserve(msgAllList.size());
vector<MQMessageExt>::iterator it = msgAllList.begin();
for (; it != msgAllList.end(); ++it) {
string msgTag = (*it).getTags();
if (subscriptionData->containTag(msgTag)) {
msgFilterList.push_back(*it);
}
}
} else {
msgFilterList.swap(msgAllList);
}
}
return PullResult(pResultExt->pullStatus, pResultExt->nextBeginOffset, pResultExt->minOffset, pResultExt->maxOffset,
msgFilterList);
}
PullResult* PullAPIWrapper::pullKernelImpl(const MQMessageQueue& mq, // 1
string subExpression, // 2
int64 subVersion, // 3
int64 offset, // 4
int maxNums, // 5
int sysFlag, // 6
int64 commitOffset, // 7
int brokerSuspendMaxTimeMillis, // 8
int timeoutMillis, // 9
int communicationMode, // 10
PullCallback* pullCallback,
const SessionCredentials& session_credentials,
void* pArg /*= NULL*/) {
unique_ptr<FindBrokerResult> pFindBrokerResult(
m_MQClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), recalculatePullFromWhichNode(mq), false));
//<!goto nameserver;
if (pFindBrokerResult == NULL) {
m_MQClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials);
pFindBrokerResult.reset(
m_MQClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), recalculatePullFromWhichNode(mq), false));
}
if (pFindBrokerResult != NULL) {
int sysFlagInner = sysFlag;
if (pFindBrokerResult->slave) {
sysFlagInner = PullSysFlag::clearCommitOffsetFlag(sysFlagInner);
}
PullMessageRequestHeader* pRequestHeader = new PullMessageRequestHeader();
pRequestHeader->consumerGroup = m_consumerGroup;
pRequestHeader->topic = mq.getTopic();
pRequestHeader->queueId = mq.getQueueId();
pRequestHeader->queueOffset = offset;
pRequestHeader->maxMsgNums = maxNums;
pRequestHeader->sysFlag = sysFlagInner;
pRequestHeader->commitOffset = commitOffset;
pRequestHeader->suspendTimeoutMillis = brokerSuspendMaxTimeMillis;
pRequestHeader->subscription = subExpression;
pRequestHeader->subVersion = subVersion;
return m_MQClientFactory->getMQClientAPIImpl()->pullMessage(pFindBrokerResult->brokerAddr, pRequestHeader,
timeoutMillis, communicationMode, pullCallback, pArg,
session_credentials);
}
THROW_MQEXCEPTION(MQClientException, "The broker not exist", -1);
}
} // namespace rocketmq

View File

@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef _PULLAPIWRAPPER_H_
#define _PULLAPIWRAPPER_H_
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include "AsyncCallback.h"
#include "MQMessageQueue.h"
#include "SessionCredentials.h"
#include "SubscriptionData.h"
namespace rocketmq {
class MQClientFactory;
//<!***************************************************************************
class PullAPIWrapper {
public:
PullAPIWrapper(MQClientFactory* mQClientFactory, const string& consumerGroup);
~PullAPIWrapper();
PullResult processPullResult(const MQMessageQueue& mq, PullResult* pullResult, SubscriptionData* subscriptionData);
PullResult* pullKernelImpl(const MQMessageQueue& mq, // 1
string subExpression, // 2
int64 subVersion, // 3
int64 offset, // 4
int maxNums, // 5
int sysFlag, // 6
int64 commitOffset, // 7
int brokerSuspendMaxTimeMillis, // 8
int timeoutMillis, // 9
int communicationMode, // 10
PullCallback* pullCallback,
const SessionCredentials& session_credentials,
void* pArg = NULL);
private:
void updatePullFromWhichNode(const MQMessageQueue& mq, int brokerId);
int recalculatePullFromWhichNode(const MQMessageQueue& mq);
private:
MQClientFactory* m_MQClientFactory;
string m_consumerGroup;
boost::mutex m_lock;
map<MQMessageQueue, int /* brokerId */> m_pullFromWhichNodeTable;
};
//<!***************************************************************************
} // namespace rocketmq
#endif //<! _PULLAPIWRAPPER_H_

View File

@@ -0,0 +1,278 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PullRequest.h"
#include "Logging.h"
namespace rocketmq {
//<!***************************************************************************
const uint64 PullRequest::RebalanceLockInterval = 20 * 1000;
const uint64 PullRequest::RebalanceLockMaxLiveTime = 30 * 1000;
/**
* If the process queue has not been pulled for more than MAX_PULL_IDLE_TIME, we need to mark it as dropped
* default 120s
*/
const uint64 PullRequest::MAX_PULL_IDLE_TIME = 120 * 1000;
PullRequest::PullRequest(const string& groupname)
: m_groupname(groupname), m_nextOffset(0), m_queueOffsetMax(0), m_bDropped(false), m_bLocked(false) {
m_lastLockTimestamp = UtilAll::currentTimeMillis();
m_lastPullTimestamp = UtilAll::currentTimeMillis();
m_lastConsumeTimestamp = UtilAll::currentTimeMillis();
}
PullRequest::~PullRequest() {
m_msgTreeMapTemp.clear();
m_msgTreeMap.clear();
}
PullRequest& PullRequest::operator=(const PullRequest& other) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
if (this != &other) {
m_groupname = other.m_groupname;
m_nextOffset = other.m_nextOffset;
m_bDropped.store(other.m_bDropped.load());
m_queueOffsetMax = other.m_queueOffsetMax;
m_messageQueue = other.m_messageQueue;
m_msgTreeMap = other.m_msgTreeMap;
m_msgTreeMapTemp = other.m_msgTreeMapTemp;
m_lastPullTimestamp = other.m_lastPullTimestamp;
m_lastConsumeTimestamp = other.m_lastConsumeTimestamp;
}
return *this;
}
void PullRequest::putMessage(vector<MQMessageExt>& msgs) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
vector<MQMessageExt>::iterator it = msgs.begin();
for (; it != msgs.end(); it++) {
m_msgTreeMap[it->getQueueOffset()] = *it;
m_queueOffsetMax = (std::max)(m_queueOffsetMax, it->getQueueOffset());
}
LOG_DEBUG("PullRequest: putMessage m_queueOffsetMax:%lld ", m_queueOffsetMax);
}
void PullRequest::getMessage(vector<MQMessageExt>& msgs) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
map<int64, MQMessageExt>::iterator it = m_msgTreeMap.begin();
for (; it != m_msgTreeMap.end(); it++) {
msgs.push_back(it->second);
}
}
int64 PullRequest::getCacheMinOffset() {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
if (m_msgTreeMap.empty()) {
return 0;
} else {
map<int64, MQMessageExt>::iterator it = m_msgTreeMap.begin();
MQMessageExt msg = it->second;
return msg.getQueueOffset();
}
}
int64 PullRequest::getCacheMaxOffset() {
return m_queueOffsetMax;
}
int PullRequest::getCacheMsgCount() {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
return m_msgTreeMap.size();
}
void PullRequest::getMessageByQueueOffset(vector<MQMessageExt>& msgs, int64 minQueueOffset, int64 maxQueueOffset) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
int64 it = minQueueOffset;
for (; it <= maxQueueOffset; it++) {
msgs.push_back(m_msgTreeMap[it]);
}
}
int64 PullRequest::removeMessage(vector<MQMessageExt>& msgs) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
int64 result = -1;
LOG_DEBUG("m_queueOffsetMax is:%lld", m_queueOffsetMax);
if (!m_msgTreeMap.empty()) {
result = m_queueOffsetMax + 1;
LOG_DEBUG(" offset result is:%lld, m_queueOffsetMax is:%lld, msgs size:" SIZET_FMT "", result, m_queueOffsetMax,
msgs.size());
vector<MQMessageExt>::iterator it = msgs.begin();
for (; it != msgs.end(); it++) {
LOG_DEBUG("remove these msg from m_msgTreeMap, its offset:%lld", it->getQueueOffset());
m_msgTreeMap.erase(it->getQueueOffset());
}
if (!m_msgTreeMap.empty()) {
map<int64, MQMessageExt>::iterator it = m_msgTreeMap.begin();
result = it->first;
LOG_INFO("cache msg size:" SIZET_FMT " of pullRequest:%s, return offset result is:%lld", m_msgTreeMap.size(),
m_messageQueue.toString().c_str(), result);
}
}
return result;
}
void PullRequest::clearAllMsgs() {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
if (isDropped()) {
LOG_DEBUG("clear m_msgTreeMap as PullRequest had been dropped.");
m_msgTreeMap.clear();
m_msgTreeMapTemp.clear();
}
}
void PullRequest::updateQueueMaxOffset(int64 queueOffset) {
// following 2 cases which may set queueOffset smaller than m_queueOffsetMax:
// 1. resetOffset cmd
// 2. during rebalance, if configured with CONSUMER_FROM_FIRST_OFFSET, when
// readOffset called by computePullFromWhere was failed, m_nextOffset will be
// setted to 0
m_queueOffsetMax = queueOffset;
}
void PullRequest::setDropped(bool dropped) {
int temp = (dropped == true ? 1 : 0);
m_bDropped.store(temp);
/*
m_queueOffsetMax = 0;
m_nextOffset = 0;
//the reason why not clear m_queueOffsetMax and m_nextOffset is due to
ConsumeMsgService and drop mq are concurrent running.
consider following situation:
1>. ConsumeMsgService running
2>. dorebalance, drop mq, reset m_nextOffset and m_queueOffsetMax
3>. ConsumeMsgService calls removeMessages, if no other msgs in
m_msgTreeMap, m_queueOffsetMax(0)+1 will return;
4>. updateOffset with 1, which is more smaller than correct offset.
*/
}
bool PullRequest::isDropped() const {
return m_bDropped.load() == 1;
}
int64 PullRequest::getNextOffset() {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
return m_nextOffset;
}
void PullRequest::setLocked(bool Locked) {
int temp = (Locked == true ? 1 : 0);
m_bLocked.store(temp);
}
bool PullRequest::isLocked() const {
return m_bLocked.load() == 1;
}
bool PullRequest::isLockExpired() const {
return (UtilAll::currentTimeMillis() - m_lastLockTimestamp) > RebalanceLockMaxLiveTime;
}
void PullRequest::setLastLockTimestamp(int64 time) {
m_lastLockTimestamp = time;
}
int64 PullRequest::getLastLockTimestamp() const {
return m_lastLockTimestamp;
}
void PullRequest::setLastPullTimestamp(uint64 time) {
m_lastPullTimestamp = time;
}
uint64 PullRequest::getLastPullTimestamp() const {
return m_lastPullTimestamp;
}
bool PullRequest::isPullRequestExpired() const {
uint64 interval = m_lastPullTimestamp + MAX_PULL_IDLE_TIME;
if (interval <= UtilAll::currentTimeMillis()) {
LOG_WARN("PullRequest for [%s] has been expired %lld ms,m_lastPullTimestamp = %lld ms",
m_messageQueue.toString().c_str(), UtilAll::currentTimeMillis() - interval, m_lastPullTimestamp);
return true;
}
return false;
}
void PullRequest::setLastConsumeTimestamp(uint64 time) {
m_lastConsumeTimestamp = time;
}
uint64 PullRequest::getLastConsumeTimestamp() const {
return m_lastConsumeTimestamp;
}
void PullRequest::setTryUnlockTimes(int time) {
m_lastLockTimestamp = time;
}
int PullRequest::getTryUnlockTimes() const {
return m_lastLockTimestamp;
}
void PullRequest::setNextOffset(int64 nextoffset) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
m_nextOffset = nextoffset;
}
string PullRequest::getGroupName() const {
return m_groupname;
}
boost::timed_mutex& PullRequest::getPullRequestCriticalSection() {
return m_consumeLock;
}
void PullRequest::takeMessages(vector<MQMessageExt>& msgs, int batchSize) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
for (int i = 0; i != batchSize; i++) {
map<int64, MQMessageExt>::iterator it = m_msgTreeMap.begin();
if (it != m_msgTreeMap.end()) {
msgs.push_back(it->second);
m_msgTreeMapTemp[it->first] = it->second;
m_msgTreeMap.erase(it);
}
}
}
void PullRequest::makeMessageToCosumeAgain(vector<MQMessageExt>& msgs) {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
for (unsigned int it = 0; it != msgs.size(); ++it) {
m_msgTreeMap[msgs[it].getQueueOffset()] = msgs[it];
m_msgTreeMapTemp.erase(msgs[it].getQueueOffset());
}
}
int64 PullRequest::commit() {
boost::lock_guard<boost::mutex> lock(m_pullRequestLock);
if (!m_msgTreeMapTemp.empty()) {
int64 offset = (--m_msgTreeMapTemp.end())->first;
m_msgTreeMapTemp.clear();
return offset + 1;
} else {
return -1;
}
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,101 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __PULLREQUEST_H__
#define __PULLREQUEST_H__
#include <boost/atomic.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include "MQMessageExt.h"
#include "MQMessageQueue.h"
#include "UtilAll.h"
namespace rocketmq {
//<!***************************************************************************
class PullRequest {
public:
PullRequest(const string& groupname);
virtual ~PullRequest();
void putMessage(vector<MQMessageExt>& msgs);
void getMessage(vector<MQMessageExt>& msgs);
int64 getCacheMinOffset();
int64 getCacheMaxOffset();
int getCacheMsgCount();
void getMessageByQueueOffset(vector<MQMessageExt>& msgs, int64 minQueueOffset, int64 maxQueueOffset);
int64 removeMessage(vector<MQMessageExt>& msgs);
void clearAllMsgs();
PullRequest& operator=(const PullRequest& other);
void setDropped(bool dropped);
bool isDropped() const;
int64 getNextOffset();
void setNextOffset(int64 nextoffset);
string getGroupName() const;
void updateQueueMaxOffset(int64 queueOffset);
void setLocked(bool Locked);
bool isLocked() const;
bool isLockExpired() const;
void setLastLockTimestamp(int64 time);
int64 getLastLockTimestamp() const;
void setLastPullTimestamp(uint64 time);
uint64 getLastPullTimestamp() const;
bool isPullRequestExpired() const;
void setLastConsumeTimestamp(uint64 time);
uint64 getLastConsumeTimestamp() const;
void setTryUnlockTimes(int time);
int getTryUnlockTimes() const;
void takeMessages(vector<MQMessageExt>& msgs, int batchSize);
int64 commit();
void makeMessageToCosumeAgain(vector<MQMessageExt>& msgs);
boost::timed_mutex& getPullRequestCriticalSection();
bool removePullMsgEvent(bool force = false);
bool addPullMsgEvent();
/**
* Check if there is an in-flight pull request.
*/
bool hasInFlightPullRequest() const;
public:
MQMessageQueue m_messageQueue;
static const uint64 RebalanceLockInterval; // ms
static const uint64 RebalanceLockMaxLiveTime; // ms
static const uint64 MAX_PULL_IDLE_TIME; // ms
private:
string m_groupname;
int64 m_nextOffset;
int64 m_queueOffsetMax;
boost::atomic<bool> m_bDropped;
boost::atomic<bool> m_bLocked;
map<int64, MQMessageExt> m_msgTreeMap;
map<int64, MQMessageExt> m_msgTreeMapTemp;
boost::mutex m_pullRequestLock;
uint64 m_lastLockTimestamp; // ms
// uint64 m_tryUnlockTimes;
uint64 m_lastPullTimestamp;
uint64 m_lastConsumeTimestamp;
boost::timed_mutex m_consumeLock;
};
//<!************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PullResult.h"
#include "UtilAll.h"
namespace rocketmq {
//<!************************************************************************
PullResult::PullResult() : pullStatus(NO_MATCHED_MSG), nextBeginOffset(0), minOffset(0), maxOffset(0) {}
PullResult::PullResult(PullStatus status) : pullStatus(status), nextBeginOffset(0), minOffset(0), maxOffset(0) {}
PullResult::PullResult(PullStatus pullStatus, int64 nextBeginOffset, int64 minOffset, int64 maxOffset)
: pullStatus(pullStatus), nextBeginOffset(nextBeginOffset), minOffset(minOffset), maxOffset(maxOffset) {}
PullResult::PullResult(PullStatus pullStatus,
int64 nextBeginOffset,
int64 minOffset,
int64 maxOffset,
const vector<MQMessageExt>& src)
: pullStatus(pullStatus), nextBeginOffset(nextBeginOffset), minOffset(minOffset), maxOffset(maxOffset) {
msgFoundList.reserve(src.size());
for (size_t i = 0; i < src.size(); i++) {
msgFoundList.push_back(src[i]);
}
}
PullResult::~PullResult() {
msgFoundList.clear();
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "PullResult.h"
#include "UtilAll.h"
#include "dataBlock.h"
namespace rocketmq {
/**
* use internal only
*/
//<!***************************************************************************
class PullResultExt : public PullResult {
public:
PullResultExt(PullStatus pullStatus,
int64 nextBeginOffset,
int64 minOffset,
int64 maxOffset,
int suggestWhichBrokerId,
const MemoryBlock& messageBinary)
: PullResult(pullStatus, nextBeginOffset, minOffset, maxOffset),
suggestWhichBrokerId(suggestWhichBrokerId),
msgMemBlock(messageBinary) {}
PullResultExt(PullStatus pullStatus,
int64 nextBeginOffset,
int64 minOffset,
int64 maxOffset,
int suggestWhichBrokerId,
MemoryBlock&& messageBinary)
: PullResult(pullStatus, nextBeginOffset, minOffset, maxOffset),
suggestWhichBrokerId(suggestWhichBrokerId),
msgMemBlock(std::forward<MemoryBlock>(messageBinary)) {}
PullResultExt(PullStatus pullStatus,
int64 nextBeginOffset,
int64 minOffset,
int64 maxOffset,
int suggestWhichBrokerId)
: PullResult(pullStatus, nextBeginOffset, minOffset, maxOffset), suggestWhichBrokerId(suggestWhichBrokerId) {}
virtual ~PullResultExt() {}
public:
int suggestWhichBrokerId;
MemoryBlock msgMemBlock;
};
} // namespace rocketmq

View File

@@ -0,0 +1,658 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "Rebalance.h"
#include "DefaultMQPushConsumerImpl.h"
#include "LockBatchBody.h"
#include "Logging.h"
#include "MQClientAPIImpl.h"
#include "MQClientFactory.h"
#include "OffsetStore.h"
namespace rocketmq {
//<!************************************************************************
Rebalance::Rebalance(MQConsumer* consumer, MQClientFactory* pfactory)
: m_pConsumer(consumer), m_pClientFactory(pfactory) {
m_pAllocateMQStrategy = new AllocateMQAveragely();
}
Rebalance::~Rebalance() {
{
map<string, SubscriptionData*>::iterator it = m_subscriptionData.begin();
for (; it != m_subscriptionData.end(); ++it) {
deleteAndZero(it->second);
}
m_subscriptionData.clear();
}
{
/*
MQ2PULLREQ::iterator it = m_requestQueueTable.begin();
for (; it != m_requestQueueTable.end(); ++it) {
delete it->second;
it->second = NULL;
}
m_requestQueueTable.clear();*/
}
m_topicSubscribeInfoTable.clear();
m_pConsumer = NULL;
m_pClientFactory = NULL;
deleteAndZero(m_pAllocateMQStrategy);
}
void Rebalance::doRebalance() {
LOG_DEBUG("start doRebalance");
try {
map<string, SubscriptionData*>::iterator it = m_subscriptionData.begin();
for (; it != m_subscriptionData.end(); ++it) {
string topic = (it->first);
LOG_DEBUG("current topic is:%s", topic.c_str());
//<!topic -> mqs
vector<MQMessageQueue> mqAll;
if (!getTopicSubscribeInfo(topic, mqAll)) {
continue;
}
if (mqAll.empty()) {
if (!UtilAll::startsWith_retry(topic)) {
std::string msg("#doRebalance. mqAll for topic:");
msg.append(topic);
msg.append(" is empty");
LOG_ERROR("Queues to allocate are empty. Msg: %s", msg.c_str());
// to check, return error or throw exception
THROW_MQEXCEPTION(MQClientException, msg, -1);
}
}
//<!msg model;
switch (m_pConsumer->getMessageModel()) {
case BROADCASTING: {
bool changed = updateRequestTableInRebalance(topic, mqAll);
if (changed) {
messageQueueChanged(topic, mqAll, mqAll);
}
break;
}
case CLUSTERING: {
vector<string> cidAll;
m_pClientFactory->findConsumerIds(topic, m_pConsumer->getGroupName(), cidAll,
m_pConsumer->getSessionCredentials());
if (cidAll.empty()) {
LOG_ERROR("[ERROR] Get empty consumer IDs. Consumer Group: %s, Topic: %s",
m_pConsumer->getGroupName().c_str(), topic.c_str());
// Should skip this round of re-balance immediately if consumer ID set is empty.
THROW_MQEXCEPTION(MQClientException, "doRebalance the cidAll is empty", -1);
}
// log
for (int i = 0; i < (int)cidAll.size(); ++i) {
LOG_DEBUG("client id:%s of topic:%s", cidAll[i].c_str(), topic.c_str());
}
//<! sort;
sort(mqAll.begin(), mqAll.end());
sort(cidAll.begin(), cidAll.end());
//<! allocate;
vector<MQMessageQueue> allocateResult;
try {
m_pAllocateMQStrategy->allocate(m_pConsumer->getMQClientId(), mqAll, cidAll, allocateResult);
} catch (MQException& e) {
std::string errMsg("Allocate message queue for ConsumerGroup[");
errMsg.append(m_pConsumer->getGroupName());
errMsg.append("],Topic[");
errMsg.append(topic);
errMsg.append("] failed. ");
LOG_ERROR("%s", errMsg.c_str());
THROW_MQEXCEPTION(MQClientException, errMsg, -1);
}
// log
for (int i = 0; i < (int)allocateResult.size(); ++i) {
LOG_DEBUG("allocate mq:%s", allocateResult[i].toString().c_str());
}
//<!update local;
bool changed = updateRequestTableInRebalance(topic, allocateResult);
if (changed) {
std::stringstream ss;
ss << "Allocation result for [Consumer Group: " << m_pConsumer->getGroupName() << ", Topic: " << topic
<< ", Current Consumer ID: " << m_pConsumer->getMQClientId() << "] is changed.\n"
<< "Total Queue :#" << mqAll.size() << ", Total Consumer :#" << cidAll.size()
<< ", Allocated Queues are: \n";
for (vector<MQMessageQueue>::size_type i = 0; i < allocateResult.size(); ++i) {
ss << allocateResult[i].toString() << "\n";
}
// Log allocation result.
LOG_INFO("%s", ss.str().c_str());
messageQueueChanged(topic, mqAll, allocateResult);
break;
}
}
default:
break;
}
}
} catch (MQException& e) {
LOG_ERROR("%s", e.what());
}
}
void Rebalance::persistConsumerOffset() {
DefaultMQPushConsumerImpl* pConsumer = static_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
OffsetStore* pOffsetStore = pConsumer->getOffsetStore();
vector<MQMessageQueue> mqs;
{
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
MQ2PULLREQ::iterator it = m_requestQueueTable.begin();
for (; it != m_requestQueueTable.end(); ++it) {
if (it->second && (!it->second->isDropped())) {
mqs.push_back(it->first);
}
}
}
if (pConsumer->getMessageModel() == BROADCASTING) {
pOffsetStore->persistAll(mqs);
} else {
vector<MQMessageQueue>::iterator it2 = mqs.begin();
for (; it2 != mqs.end(); ++it2) {
pOffsetStore->persist(*it2, m_pConsumer->getSessionCredentials());
}
}
}
void Rebalance::persistConsumerOffsetByResetOffset() {
DefaultMQPushConsumerImpl* pConsumer = static_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
OffsetStore* pOffsetStore = pConsumer->getOffsetStore();
vector<MQMessageQueue> mqs;
{
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
MQ2PULLREQ::iterator it = m_requestQueueTable.begin();
for (; it != m_requestQueueTable.end(); ++it) {
if (it->second) { // even if it was dropped, also need update offset when
// rcv resetOffset cmd
mqs.push_back(it->first);
}
}
}
vector<MQMessageQueue>::iterator it2 = mqs.begin();
for (; it2 != mqs.end(); ++it2) {
pOffsetStore->persist(*it2, m_pConsumer->getSessionCredentials());
}
}
SubscriptionData* Rebalance::getSubscriptionData(const string& topic) {
if (m_subscriptionData.find(topic) != m_subscriptionData.end()) {
return m_subscriptionData[topic];
}
return NULL;
}
map<string, SubscriptionData*>& Rebalance::getSubscriptionInner() {
return m_subscriptionData;
}
void Rebalance::setSubscriptionData(const string& topic, SubscriptionData* pdata) {
if (pdata != NULL && m_subscriptionData.find(topic) == m_subscriptionData.end())
m_subscriptionData[topic] = pdata;
}
void Rebalance::setTopicSubscribeInfo(const string& topic, vector<MQMessageQueue>& mqs) {
if (m_subscriptionData.find(topic) != m_subscriptionData.end()) {
{
boost::lock_guard<boost::mutex> lock(m_topicSubscribeInfoTableMutex);
if (m_topicSubscribeInfoTable.find(topic) != m_topicSubscribeInfoTable.end())
m_topicSubscribeInfoTable.erase(topic);
m_topicSubscribeInfoTable[topic] = mqs;
}
// log
vector<MQMessageQueue>::iterator it = mqs.begin();
for (; it != mqs.end(); ++it) {
LOG_DEBUG("topic [%s] has :%s", topic.c_str(), (*it).toString().c_str());
}
}
}
bool Rebalance::getTopicSubscribeInfo(const string& topic, vector<MQMessageQueue>& mqs) {
boost::lock_guard<boost::mutex> lock(m_topicSubscribeInfoTableMutex);
if (m_topicSubscribeInfoTable.find(topic) != m_topicSubscribeInfoTable.end()) {
mqs = m_topicSubscribeInfoTable[topic];
return true;
}
return false;
}
void Rebalance::addPullRequest(MQMessageQueue mq, boost::shared_ptr<PullRequest> pPullRequest) {
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
m_requestQueueTable[mq] = pPullRequest;
}
void Rebalance::removePullRequest(MQMessageQueue mq) {
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) {
m_requestQueueTable.erase(mq);
}
}
bool Rebalance::isPullRequestExist(MQMessageQueue mq) {
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) {
return true;
}
return false;
}
boost::weak_ptr<PullRequest> Rebalance::getPullRequest(MQMessageQueue mq) {
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) {
return m_requestQueueTable[mq];
}
return boost::weak_ptr<PullRequest>();
}
map<MQMessageQueue, boost::shared_ptr<PullRequest>> Rebalance::getPullRequestTable() {
boost::lock_guard<boost::mutex> lock(m_requestTableMutex);
return m_requestQueueTable;
}
void Rebalance::unlockAll(bool oneWay) {
map<string, vector<MQMessageQueue>*> brokerMqs;
MQ2PULLREQ requestQueueTable = getPullRequestTable();
for (MQ2PULLREQ::iterator it = requestQueueTable.begin(); it != requestQueueTable.end(); ++it) {
if (!(it->second->isDropped())) {
if (brokerMqs.find(it->first.getBrokerName()) == brokerMqs.end()) {
vector<MQMessageQueue>* mqs = new vector<MQMessageQueue>;
brokerMqs[it->first.getBrokerName()] = mqs;
} else {
brokerMqs[it->first.getBrokerName()]->push_back(it->first);
}
}
}
LOG_INFO("unLockAll " SIZET_FMT " broker mqs", brokerMqs.size());
for (map<string, vector<MQMessageQueue>*>::iterator itb = brokerMqs.begin(); itb != brokerMqs.end(); ++itb) {
unique_ptr<FindBrokerResult> pFindBrokerResult(
m_pClientFactory->findBrokerAddressInSubscribe(itb->first, MASTER_ID, true));
if (!pFindBrokerResult) {
LOG_ERROR("unlockAll findBrokerAddressInSubscribe ret null for broker:%s", itb->first.data());
continue;
}
unique_ptr<UnlockBatchRequestBody> unlockBatchRequest(new UnlockBatchRequestBody());
vector<MQMessageQueue> mqs(*(itb->second));
unlockBatchRequest->setClientId(m_pConsumer->getMQClientId());
unlockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName());
unlockBatchRequest->setMqSet(mqs);
try {
m_pClientFactory->getMQClientAPIImpl()->unlockBatchMQ(pFindBrokerResult->brokerAddr, unlockBatchRequest.get(),
1000, m_pConsumer->getSessionCredentials());
for (unsigned int i = 0; i != mqs.size(); ++i) {
boost::weak_ptr<PullRequest> pullreq = getPullRequest(mqs[i]);
if (!pullreq.expired()) {
LOG_INFO("unlockBatchMQ success of mq:%s", mqs[i].toString().c_str());
pullreq.lock()->setLocked(false);
} else {
LOG_ERROR("unlockBatchMQ fails of mq:%s", mqs[i].toString().c_str());
}
}
} catch (MQException& e) {
LOG_ERROR("unlockBatchMQ fails");
}
deleteAndZero(itb->second);
}
brokerMqs.clear();
}
void Rebalance::unlock(MQMessageQueue mq) {
unique_ptr<FindBrokerResult> pFindBrokerResult(
m_pClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), MASTER_ID, true));
if (!pFindBrokerResult) {
LOG_ERROR("unlock findBrokerAddressInSubscribe ret null for broker:%s", mq.getBrokerName().data());
return;
}
unique_ptr<UnlockBatchRequestBody> unlockBatchRequest(new UnlockBatchRequestBody());
vector<MQMessageQueue> mqs;
mqs.push_back(mq);
unlockBatchRequest->setClientId(m_pConsumer->getMQClientId());
unlockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName());
unlockBatchRequest->setMqSet(mqs);
try {
m_pClientFactory->getMQClientAPIImpl()->unlockBatchMQ(pFindBrokerResult->brokerAddr, unlockBatchRequest.get(), 1000,
m_pConsumer->getSessionCredentials());
for (unsigned int i = 0; i != mqs.size(); ++i) {
boost::weak_ptr<PullRequest> pullreq = getPullRequest(mqs[i]);
if (!pullreq.expired()) {
LOG_INFO("unlock success of mq:%s", mqs[i].toString().c_str());
pullreq.lock()->setLocked(false);
} else {
LOG_ERROR("unlock fails of mq:%s", mqs[i].toString().c_str());
}
}
} catch (MQException& e) {
LOG_ERROR("unlock fails of mq:%s", mq.toString().c_str());
}
}
void Rebalance::lockAll() {
map<string, vector<MQMessageQueue>*> brokerMqs;
MQ2PULLREQ requestQueueTable = getPullRequestTable();
for (MQ2PULLREQ::iterator it = requestQueueTable.begin(); it != requestQueueTable.end(); ++it) {
if (!(it->second->isDropped())) {
string brokerKey = it->first.getBrokerName() + it->first.getTopic();
if (brokerMqs.find(brokerKey) == brokerMqs.end()) {
vector<MQMessageQueue>* mqs = new vector<MQMessageQueue>;
brokerMqs[brokerKey] = mqs;
brokerMqs[brokerKey]->push_back(it->first);
} else {
brokerMqs[brokerKey]->push_back(it->first);
}
}
}
LOG_INFO("LockAll " SIZET_FMT " broker mqs", brokerMqs.size());
for (map<string, vector<MQMessageQueue>*>::iterator itb = brokerMqs.begin(); itb != brokerMqs.end(); ++itb) {
string brokerName = (*(itb->second))[0].getBrokerName();
unique_ptr<FindBrokerResult> pFindBrokerResult(
m_pClientFactory->findBrokerAddressInSubscribe(brokerName, MASTER_ID, true));
if (!pFindBrokerResult) {
LOG_ERROR("lockAll findBrokerAddressInSubscribe ret null for broker:%s", brokerName.data());
continue;
}
unique_ptr<LockBatchRequestBody> lockBatchRequest(new LockBatchRequestBody());
lockBatchRequest->setClientId(m_pConsumer->getMQClientId());
lockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName());
lockBatchRequest->setMqSet(*(itb->second));
LOG_INFO("try to lock:" SIZET_FMT " mqs of broker:%s", itb->second->size(), itb->first.c_str());
try {
vector<MQMessageQueue> messageQueues;
m_pClientFactory->getMQClientAPIImpl()->lockBatchMQ(pFindBrokerResult->brokerAddr, lockBatchRequest.get(),
messageQueues, 1000, m_pConsumer->getSessionCredentials());
for (unsigned int i = 0; i != messageQueues.size(); ++i) {
boost::weak_ptr<PullRequest> pullreq = getPullRequest(messageQueues[i]);
if (!pullreq.expired()) {
LOG_INFO("lockBatchMQ success of mq:%s", messageQueues[i].toString().c_str());
pullreq.lock()->setLocked(true);
pullreq.lock()->setLastLockTimestamp(UtilAll::currentTimeMillis());
} else {
LOG_ERROR("lockBatchMQ fails of mq:%s", messageQueues[i].toString().c_str());
}
}
messageQueues.clear();
} catch (MQException& e) {
LOG_ERROR("lockBatchMQ fails");
}
deleteAndZero(itb->second);
}
brokerMqs.clear();
}
bool Rebalance::lock(MQMessageQueue mq) {
unique_ptr<FindBrokerResult> pFindBrokerResult(
m_pClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), MASTER_ID, true));
if (!pFindBrokerResult) {
LOG_ERROR("lock findBrokerAddressInSubscribe ret null for broker:%s", mq.getBrokerName().data());
return false;
}
unique_ptr<LockBatchRequestBody> lockBatchRequest(new LockBatchRequestBody());
lockBatchRequest->setClientId(m_pConsumer->getMQClientId());
lockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName());
vector<MQMessageQueue> in_mqSet;
in_mqSet.push_back(mq);
lockBatchRequest->setMqSet(in_mqSet);
bool lockResult = false;
try {
vector<MQMessageQueue> messageQueues;
LOG_DEBUG("try to lock mq:%s", mq.toString().c_str());
m_pClientFactory->getMQClientAPIImpl()->lockBatchMQ(pFindBrokerResult->brokerAddr, lockBatchRequest.get(),
messageQueues, 1000, m_pConsumer->getSessionCredentials());
if (messageQueues.size() == 0) {
LOG_ERROR("lock mq on broker:%s failed", pFindBrokerResult->brokerAddr.c_str());
return false;
}
for (unsigned int i = 0; i != messageQueues.size(); ++i) {
boost::weak_ptr<PullRequest> pullreq = getPullRequest(messageQueues[i]);
if (!pullreq.expired()) {
LOG_INFO("lock success of mq:%s", messageQueues[i].toString().c_str());
pullreq.lock()->setLocked(true);
pullreq.lock()->setLastLockTimestamp(UtilAll::currentTimeMillis());
lockResult = true;
} else {
LOG_ERROR("lock fails of mq:%s", messageQueues[i].toString().c_str());
}
}
messageQueues.clear();
return lockResult;
} catch (MQException& e) {
LOG_ERROR("lock fails of mq:%s", mq.toString().c_str());
return false;
}
}
//<!************************************************************************
RebalancePull::RebalancePull(MQConsumer* consumer, MQClientFactory* pfactory) : Rebalance(consumer, pfactory) {}
bool RebalancePull::updateRequestTableInRebalance(const string& topic, vector<MQMessageQueue>& mqsSelf) {
return false;
}
int64 RebalancePull::computePullFromWhere(const MQMessageQueue& mq) {
return 0;
}
void RebalancePull::messageQueueChanged(const string& topic,
vector<MQMessageQueue>& mqAll,
vector<MQMessageQueue>& mqDivided) {}
void RebalancePull::removeUnnecessaryMessageQueue(const MQMessageQueue& mq) {}
//<!***************************************************************************
RebalancePush::RebalancePush(MQConsumer* consumer, MQClientFactory* pfactory) : Rebalance(consumer, pfactory) {}
bool RebalancePush::updateRequestTableInRebalance(const string& topic, vector<MQMessageQueue>& mqsSelf) {
LOG_DEBUG("updateRequestTableInRebalance for Topic[%s] Enter", topic.c_str());
// 1. Clear no in charge of
// 1. set dropped
// 2. clear local message
// 3. clear offset
// 4. remove request table
// 5. set flag for route changed
// 2. Check and clear dropped/invalid pullrequest(timeout and so on)
// 3. Add new mq in charge of
// 1. new pullrequest
// 2. init next pull offset
// 3. int offset
// 4. add request table
// 5. set flag for route changed
// 4. Start long pull for request
if (mqsSelf.empty()) {
LOG_WARN("allocated queue is empty for topic:%s", topic.c_str());
}
bool changed = false;
//<!remove none responsive mq
MQ2PULLREQ requestQueueTable(getPullRequestTable());
MQ2PULLREQ::iterator itDel = requestQueueTable.begin();
for (; itDel != requestQueueTable.end(); ++itDel) {
MQMessageQueue mqtemp = itDel->first;
if (mqtemp.getTopic().compare(topic) == 0) {
if (mqsSelf.empty() || (std::find(mqsSelf.begin(), mqsSelf.end(), mqtemp) == mqsSelf.end())) {
// if not response , set to dropped
LOG_INFO("Drop mq:%s,because not responsive", mqtemp.toString().c_str());
itDel->second->setDropped(true);
// remove offset table to avoid offset backup
removeUnnecessaryMessageQueue(mqtemp);
itDel->second->clearAllMsgs();
removePullRequest(mqtemp);
changed = true;
} else if (itDel->second->isPullRequestExpired()) {
// if pull expired , set to dropped, eg: if add pull task error, the pull request will be expired.
LOG_INFO("Drop mq:%s according Pull timeout.", mqtemp.toString().c_str());
itDel->second->setDropped(true);
removeUnnecessaryMessageQueue(mqtemp);
itDel->second->clearAllMsgs();
removePullRequest(mqtemp);
changed = true;
}
}
}
//<!add check new mq added.
vector<boost::shared_ptr<PullRequest>> pullRequestsToAdd;
vector<MQMessageQueue>::iterator itAdd = mqsSelf.begin();
for (; itAdd != mqsSelf.end(); ++itAdd) {
if (isPullRequestExist(*itAdd)) {
// have check the expired pull request, re-add it.
continue;
}
boost::shared_ptr<PullRequest> pullRequest = boost::make_shared<PullRequest>(m_pConsumer->getGroupName());
pullRequest->m_messageQueue = *itAdd;
int64 nextOffset = computePullFromWhere(*itAdd);
if (nextOffset >= 0) {
pullRequest->setNextOffset(nextOffset);
changed = true;
addPullRequest(*itAdd, pullRequest);
pullRequestsToAdd.push_back(pullRequest);
LOG_INFO("Add mq:%s, request initial offset:%ld", (*itAdd).toString().c_str(), nextOffset);
} else {
LOG_WARN(
"Failed to add pull request for %s due to failure of querying consume offset, request initial offset:%ld",
(*itAdd).toString().c_str(), nextOffset);
}
}
for (vector<boost::shared_ptr<PullRequest>>::iterator itAdded = pullRequestsToAdd.begin();
itAdded != pullRequestsToAdd.end(); ++itAdded) {
LOG_INFO("Start to pull %s, offset:%ld, GroupName %s", (*itAdded)->m_messageQueue.toString().c_str(),
(*itAdded)->getNextOffset(), (*itAdded)->getGroupName().c_str());
if (!m_pConsumer->producePullMsgTask(*itAdded)) {
LOG_WARN(
"Failed to producer pull message task for %s, Remove it from Request table and wait for next #Rebalance.",
(*itAdded)->m_messageQueue.toString().c_str());
// remove from request table, and wait for next rebalance.
(*itAdded)->setDropped(true);
removePullRequest((*itAdded)->m_messageQueue);
}
}
LOG_DEBUG("updateRequestTableInRebalance Topic[%s] exit", topic.c_str());
return changed;
}
int64 RebalancePush::computePullFromWhere(const MQMessageQueue& mq) {
int64 result = -1;
DefaultMQPushConsumerImpl* pConsumer = dynamic_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
if (!pConsumer) {
LOG_ERROR("Cast consumer pointer to DefaultMQPushConsumer pointer failed when computePullFromWhere %s",
mq.toString().c_str());
return result;
}
ConsumeFromWhere consumeFromWhere = pConsumer->getConsumeFromWhere();
OffsetStore* pOffsetStore = pConsumer->getOffsetStore();
switch (consumeFromWhere) {
case CONSUME_FROM_LAST_OFFSET: {
int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials());
if (lastOffset >= 0) {
LOG_INFO("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset);
result = lastOffset;
} else if (-1 == lastOffset) {
LOG_WARN("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is -1", mq.toString().c_str());
if (UtilAll::startsWith_retry(mq.getTopic())) {
LOG_INFO("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is 0", mq.toString().c_str());
result = 0;
} else {
try {
result = pConsumer->maxOffset(mq);
LOG_INFO("CONSUME_FROM_LAST_OFFSET, maxOffset of mq:%s is:%lld", mq.toString().c_str(), result);
} catch (MQException& e) {
LOG_ERROR("CONSUME_FROM_LAST_OFFSET error, lastOffset of mq:%s is -1", mq.toString().c_str());
result = -1;
}
}
} else {
LOG_ERROR("CONSUME_FROM_LAST_OFFSET error, lastOffset of mq:%s is -1", mq.toString().c_str());
result = -1;
}
break;
}
case CONSUME_FROM_FIRST_OFFSET: {
int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials());
if (lastOffset >= 0) {
LOG_INFO("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset);
result = lastOffset;
} else if (-1 == lastOffset) {
LOG_INFO("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s, return 0", mq.toString().c_str());
result = 0;
} else {
LOG_ERROR("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s, return -1", mq.toString().c_str());
result = -1;
}
break;
}
case CONSUME_FROM_TIMESTAMP: {
int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials());
if (lastOffset >= 0) {
LOG_INFO("CONSUME_FROM_TIMESTAMP, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset);
result = lastOffset;
} else if (-1 == lastOffset) {
if (UtilAll::startsWith_retry(mq.getTopic())) {
try {
result = pConsumer->maxOffset(mq);
LOG_INFO("CONSUME_FROM_TIMESTAMP, maxOffset of mq:%s is:%lld", mq.toString().c_str(), result);
} catch (MQException& e) {
LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s is -1", mq.toString().c_str());
result = -1;
}
} else {
try {
} catch (MQException& e) {
LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s, return 0", mq.toString().c_str());
result = -1;
}
}
} else {
LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s, return -1", mq.toString().c_str());
result = -1;
}
break;
}
default:
break;
}
return result;
}
void RebalancePush::messageQueueChanged(const string& topic,
vector<MQMessageQueue>& mqAll,
vector<MQMessageQueue>& mqDivided) {}
void RebalancePush::removeUnnecessaryMessageQueue(const MQMessageQueue& mq) {
// DefaultMQPushConsumer *pConsumer = static_cast<DefaultMQPushConsumer *>(m_pConsumer);
DefaultMQPushConsumerImpl* pConsumer = dynamic_cast<DefaultMQPushConsumerImpl*>(m_pConsumer);
if (!pConsumer) {
LOG_ERROR("Cast MQConsumer* to DefaultMQPushConsumer* failed when remove %s", mq.toString().c_str());
return;
}
OffsetStore* pOffsetStore = pConsumer->getOffsetStore();
pOffsetStore->persist(mq, m_pConsumer->getSessionCredentials());
pOffsetStore->removeOffset(mq);
if (pConsumer->getMessageListenerType() == messageListenerOrderly) {
unlock(mq);
}
}
//<!************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __REBALANCEIMPL_H__
#define __REBALANCEIMPL_H__
#include "AllocateMQStrategy.h"
#include "ConsumeType.h"
#include "MQConsumer.h"
#include "MQMessageQueue.h"
#include "PullRequest.h"
#include "SubscriptionData.h"
#include <boost/smart_ptr.hpp>
#include <boost/thread/mutex.hpp>
namespace rocketmq {
class MQClientFactory;
//<!************************************************************************
class Rebalance {
public:
Rebalance(MQConsumer*, MQClientFactory*);
virtual ~Rebalance();
virtual void messageQueueChanged(const string& topic,
vector<MQMessageQueue>& mqAll,
vector<MQMessageQueue>& mqDivided) = 0;
virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq) = 0;
virtual int64 computePullFromWhere(const MQMessageQueue& mq) = 0;
virtual bool updateRequestTableInRebalance(const string& topic, vector<MQMessageQueue>& mqsSelf) = 0;
public:
void doRebalance();
void persistConsumerOffset();
void persistConsumerOffsetByResetOffset();
//<!m_subscriptionInner;
SubscriptionData* getSubscriptionData(const string& topic);
void setSubscriptionData(const string& topic, SubscriptionData* pdata);
map<string, SubscriptionData*>& getSubscriptionInner();
//<!m_topicSubscribeInfoTable;
void setTopicSubscribeInfo(const string& topic, vector<MQMessageQueue>& mqs);
bool getTopicSubscribeInfo(const string& topic, vector<MQMessageQueue>& mqs);
void addPullRequest(MQMessageQueue mq, boost::shared_ptr<PullRequest> pPullRequest);
void removePullRequest(MQMessageQueue mq);
bool isPullRequestExist(MQMessageQueue mq);
boost::weak_ptr<PullRequest> getPullRequest(MQMessageQueue mq);
map<MQMessageQueue, boost::shared_ptr<PullRequest>> getPullRequestTable();
void lockAll();
bool lock(MQMessageQueue mq);
void unlockAll(bool oneWay = false);
void unlock(MQMessageQueue mq);
protected:
map<string, SubscriptionData*> m_subscriptionData;
boost::mutex m_topicSubscribeInfoTableMutex;
map<string, vector<MQMessageQueue>> m_topicSubscribeInfoTable;
typedef map<MQMessageQueue, boost::shared_ptr<PullRequest>> MQ2PULLREQ;
MQ2PULLREQ m_requestQueueTable;
boost::mutex m_requestTableMutex;
AllocateMQStrategy* m_pAllocateMQStrategy;
MQConsumer* m_pConsumer;
MQClientFactory* m_pClientFactory;
};
//<!************************************************************************
class RebalancePull : public Rebalance {
public:
RebalancePull(MQConsumer*, MQClientFactory*);
virtual ~RebalancePull(){};
virtual void messageQueueChanged(const string& topic,
vector<MQMessageQueue>& mqAll,
vector<MQMessageQueue>& mqDivided);
virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq);
virtual int64 computePullFromWhere(const MQMessageQueue& mq);
virtual bool updateRequestTableInRebalance(const string& topic, vector<MQMessageQueue>& mqsSelf);
};
//<!***************************************************************************
class RebalancePush : public Rebalance {
public:
RebalancePush(MQConsumer*, MQClientFactory*);
virtual ~RebalancePush(){};
virtual void messageQueueChanged(const string& topic,
vector<MQMessageQueue>& mqAll,
vector<MQMessageQueue>& mqDivided);
virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq);
virtual int64 computePullFromWhere(const MQMessageQueue& mq);
virtual bool updateRequestTableInRebalance(const string& topic, vector<MQMessageQueue>& mqsSelf);
};
//<!************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,130 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "SubscriptionData.h"
#include <algorithm>
#include <sstream>
#include <vector>
#include "Logging.h"
#include "UtilAll.h"
namespace rocketmq {
//<!************************************************************************
SubscriptionData::SubscriptionData() {
m_subVersion = UtilAll::currentTimeMillis();
}
SubscriptionData::SubscriptionData(const string& topic, const string& subString)
: m_topic(topic), m_subString(subString) {
m_subVersion = UtilAll::currentTimeMillis();
}
SubscriptionData::SubscriptionData(const SubscriptionData& other) {
m_subString = other.m_subString;
m_subVersion = other.m_subVersion;
m_tagSet = other.m_tagSet;
m_topic = other.m_topic;
m_codeSet = other.m_codeSet;
}
const string& SubscriptionData::getTopic() const {
return m_topic;
}
const string& SubscriptionData::getSubString() const {
return m_subString;
}
void SubscriptionData::setSubString(const string& sub) {
m_subString = sub;
}
int64 SubscriptionData::getSubVersion() const {
return m_subVersion;
}
void SubscriptionData::putTagsSet(const string& tag) {
m_tagSet.push_back(tag);
}
bool SubscriptionData::containTag(const string& tag) {
return std::find(m_tagSet.begin(), m_tagSet.end(), tag) != m_tagSet.end();
}
vector<string>& SubscriptionData::getTagsSet() {
return m_tagSet;
}
bool SubscriptionData::operator==(const SubscriptionData& other) const {
if (!m_subString.compare(other.m_subString)) {
return false;
}
if (m_subVersion != other.m_subVersion) {
return false;
}
if (m_tagSet.size() != other.m_tagSet.size()) {
return false;
}
if (!m_topic.compare(other.m_topic)) {
return false;
}
return true;
}
bool SubscriptionData::operator<(const SubscriptionData& other) const {
int ret = m_topic.compare(other.m_topic);
if (ret < 0) {
return true;
} else if (ret == 0) {
ret = m_subString.compare(other.m_subString);
if (ret < 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
void SubscriptionData::putCodeSet(const string& tag) {
int value = atoi(tag.c_str());
m_codeSet.push_back(value);
}
Json::Value SubscriptionData::toJson() const {
Json::Value outJson;
outJson["subString"] = m_subString;
outJson["subVersion"] = UtilAll::to_string(m_subVersion);
outJson["topic"] = m_topic;
{
vector<string>::const_iterator it = m_tagSet.begin();
for (; it != m_tagSet.end(); it++) {
outJson["tagsSet"].append(*it);
}
}
{
vector<int>::const_iterator it = m_codeSet.begin();
for (; it != m_codeSet.end(); it++) {
outJson["codeSet"].append(*it);
}
}
return outJson;
}
//<!***************************************************************************
} // namespace rocketmq

View File

@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __SUBSCRIPTIONDATA_H__
#define __SUBSCRIPTIONDATA_H__
#include <string>
#include "UtilAll.h"
#include "json/json.h"
namespace rocketmq {
//<!************************************************************************
class SubscriptionData {
public:
SubscriptionData();
virtual ~SubscriptionData() {
m_tagSet.clear();
m_codeSet.clear();
}
SubscriptionData(const string& topic, const string& subString);
SubscriptionData(const SubscriptionData& other);
const string& getTopic() const;
const string& getSubString() const;
void setSubString(const string& sub);
int64 getSubVersion() const;
void putTagsSet(const string& tag);
bool containTag(const string& tag);
vector<string>& getTagsSet();
void putCodeSet(const string& tag);
bool operator==(const SubscriptionData& other) const;
bool operator<(const SubscriptionData& other) const;
Json::Value toJson() const;
private:
string m_topic;
string m_subString;
int64 m_subVersion;
vector<string> m_tagSet;
vector<int> m_codeSet;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 <stdio.h>
#include "windows.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 <vector>
#include "CBatchMessage.h"
#include "CCommon.h"
#include "CMessage.h"
#include "MQMessage.h"
using std::vector;
#ifdef __cplusplus
extern "C" {
#endif
using namespace rocketmq;
CBatchMessage* CreateBatchMessage() {
vector<MQMessage>* msgs = new vector<MQMessage>();
return (CBatchMessage*)msgs;
}
int AddMessage(CBatchMessage* batchMsg, CMessage* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
if (batchMsg == NULL) {
return NULL_POINTER;
}
MQMessage* message = (MQMessage*)msg;
((vector<MQMessage>*)batchMsg)->push_back(*message);
return OK;
}
int DestroyBatchMessage(CBatchMessage* batchMsg) {
if (batchMsg == NULL) {
return NULL_POINTER;
}
delete (vector<MQMessage>*)batchMsg;
return OK;
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CErrorMessage.h"
#include "CCommon.h"
#include "MQClientErrorContainer.h"
#ifdef __cplusplus
extern "C" {
#endif
using namespace rocketmq;
const char* GetLatestErrorMessage() {
return MQClientErrorContainer::getErr().c_str();
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,129 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CMessage.h"
#include "CCommon.h"
#include "MQMessage.h"
#ifdef __cplusplus
extern "C" {
#endif
using namespace rocketmq;
CMessage* CreateMessage(const char* topic) {
MQMessage* mqMessage = new MQMessage();
if (topic != NULL) {
mqMessage->setTopic(topic);
}
return (CMessage*)mqMessage;
}
int DestroyMessage(CMessage* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
delete (MQMessage*)msg;
return OK;
}
int SetMessageTopic(CMessage* msg, const char* topic) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setTopic(topic);
return OK;
}
int SetMessageTags(CMessage* msg, const char* tags) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setTags(tags);
return OK;
}
int SetMessageKeys(CMessage* msg, const char* keys) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setKeys(keys);
return OK;
}
int SetMessageBody(CMessage* msg, const char* body) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setBody(body);
return OK;
}
int SetByteMessageBody(CMessage* msg, const char* body, int len) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setBody(body, len);
return OK;
}
int SetMessageProperty(CMessage* msg, const char* key, const char* value) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setProperty(key, value);
return OK;
}
int SetDelayTimeLevel(CMessage* msg, int level) {
if (msg == NULL) {
return NULL_POINTER;
}
((MQMessage*)msg)->setDelayTimeLevel(level);
return OK;
}
const char* GetOriginMessageTopic(CMessage* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessage*)msg)->getTopic().c_str();
}
const char* GetOriginMessageTags(CMessage* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessage*)msg)->getTags().c_str();
}
const char* GetOriginMessageKeys(CMessage* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessage*)msg)->getKeys().c_str();
}
const char* GetOriginMessageBody(CMessage* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessage*)msg)->getBody().c_str();
}
const char* GetOriginMessageProperty(CMessage* msg, const char* key) {
if (msg == NULL) {
return NULL;
}
return ((MQMessage*)msg)->getProperty(key).c_str();
}
int GetOriginDelayTimeLevel(CMessage* msg) {
if (msg == NULL) {
return -1;
}
return ((MQMessage*)msg)->getDelayTimeLevel();
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,127 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CMessageExt.h"
#include "CCommon.h"
#include "MQMessageExt.h"
#ifdef __cplusplus
extern "C" {
#endif
using namespace rocketmq;
const char* GetMessageTopic(CMessageExt* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getTopic().c_str();
}
const char* GetMessageTags(CMessageExt* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getTags().c_str();
}
const char* GetMessageKeys(CMessageExt* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getKeys().c_str();
}
const char* GetMessageBody(CMessageExt* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getBody().c_str();
}
const char* GetMessageProperty(CMessageExt* msg, const char* key) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getProperty(key).c_str();
}
const char* GetMessageId(CMessageExt* msg) {
if (msg == NULL) {
return NULL;
}
return ((MQMessageExt*)msg)->getMsgId().c_str();
}
int GetMessageDelayTimeLevel(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getDelayTimeLevel();
}
int GetMessageQueueId(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getQueueId();
}
int GetMessageReconsumeTimes(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getReconsumeTimes();
}
int GetMessageStoreSize(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getStoreSize();
}
long long GetMessageBornTimestamp(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getBornTimestamp();
}
long long GetMessageStoreTimestamp(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getStoreTimestamp();
}
long long GetMessageQueueOffset(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getQueueOffset();
}
long long GetMessageCommitLogOffset(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getCommitLogOffset();
}
long long GetMessagePreparedTransactionOffset(CMessageExt* msg) {
if (msg == NULL) {
return NULL_POINTER;
}
return ((MQMessageExt*)msg)->getPreparedTransactionOffset();
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,820 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CProducer.h"
#include <string.h>
#include <functional>
#include <typeindex>
#include <typeinfo>
#include "AsyncCallback.h"
#include "CBatchMessage.h"
#include "CCommon.h"
#include "CMQException.h"
#include "CMessage.h"
#include "CSendResult.h"
#include "DefaultMQProducer.h"
#include "MQClient.h"
#include "MQClientErrorContainer.h"
#include "TransactionListener.h"
#include "TransactionMQProducer.h"
#include "TransactionSendResult.h"
#include "UtilAll.h"
#ifdef __cplusplus
extern "C" {
#endif
using namespace rocketmq;
using namespace std;
class MyLocalTransactionExecuterInner {
public:
MyLocalTransactionExecuterInner(CLocalTransactionExecutorCallback executor, CMessage* msg, void* userData)
: m_ExcutorCallback(executor), message(msg), data(userData) {}
~MyLocalTransactionExecuterInner() {}
CLocalTransactionExecutorCallback m_ExcutorCallback;
CMessage* message;
void* data;
};
class LocalTransactionListenerInner : public TransactionListener {
public:
LocalTransactionListenerInner() {}
LocalTransactionListenerInner(CProducer* producer, CLocalTransactionCheckerCallback pCallback, void* data) {
m_CheckerCallback = pCallback;
m_producer = producer;
m_data = data;
}
~LocalTransactionListenerInner() {}
LocalTransactionState executeLocalTransaction(const MQMessage& message, void* arg) {
if (m_CheckerCallback == NULL) {
return LocalTransactionState::UNKNOWN;
}
(void)(message);
MyLocalTransactionExecuterInner* executerInner = (MyLocalTransactionExecuterInner*)arg;
CTransactionStatus status =
executerInner->m_ExcutorCallback(m_producer, executerInner->message, executerInner->data);
switch (status) {
case E_COMMIT_TRANSACTION:
return LocalTransactionState::COMMIT_MESSAGE;
case E_ROLLBACK_TRANSACTION:
return LocalTransactionState::ROLLBACK_MESSAGE;
default:
return LocalTransactionState::UNKNOWN;
}
}
LocalTransactionState checkLocalTransaction(const MQMessageExt& msg) {
if (m_CheckerCallback == NULL) {
return LocalTransactionState::UNKNOWN;
}
CMessageExt* msgExt = (CMessageExt*)(&msg);
// CMessage *msg = (CMessage *) (&message);
CTransactionStatus status = m_CheckerCallback(m_producer, msgExt, m_data);
switch (status) {
case E_COMMIT_TRANSACTION:
return LocalTransactionState::COMMIT_MESSAGE;
case E_ROLLBACK_TRANSACTION:
return LocalTransactionState::ROLLBACK_MESSAGE;
default:
return LocalTransactionState::UNKNOWN;
}
}
private:
CLocalTransactionCheckerCallback m_CheckerCallback;
CProducer* m_producer;
void* m_data;
};
class SelectMessageQueueInner : public MessageQueueSelector {
public:
MQMessageQueue select(const std::vector<MQMessageQueue>& mqs, const MQMessage& msg, void* arg) {
int index = 0;
std::string shardingKey = rocketmq::UtilAll::to_string((char*)arg);
index = std::hash<std::string>{}(shardingKey) % mqs.size();
return mqs[index % mqs.size()];
}
};
class SelectMessageQueue : public MessageQueueSelector {
public:
SelectMessageQueue(QueueSelectorCallback callback) { m_pCallback = callback; }
MQMessageQueue select(const std::vector<MQMessageQueue>& mqs, const MQMessage& msg, void* arg) {
CMessage* message = (CMessage*)&msg;
// Get the index of sending MQMessageQueue through callback function.
int index = m_pCallback(mqs.size(), message, arg);
return mqs[index];
}
private:
QueueSelectorCallback m_pCallback;
};
class COnSendCallback : public AutoDeleteSendCallBack {
public:
COnSendCallback(COnSendSuccessCallback cSendSuccessCallback,
COnSendExceptionCallback cSendExceptionCallback,
void* message,
void* userData) {
m_cSendSuccessCallback = cSendSuccessCallback;
m_cSendExceptionCallback = cSendExceptionCallback;
m_message = message;
m_userData = userData;
}
virtual ~COnSendCallback() {}
virtual void onSuccess(SendResult& sendResult) {
CSendResult result;
result.sendStatus = CSendStatus((int)sendResult.getSendStatus());
result.offset = sendResult.getQueueOffset();
strncpy(result.msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result.msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
m_cSendSuccessCallback(result, (CMessage*)m_message, m_userData);
}
virtual void onException(MQException& e) {
CMQException exception;
exception.error = e.GetError();
exception.line = e.GetLine();
strncpy(exception.msg, e.what(), MAX_EXEPTION_MSG_LENGTH - 1);
strncpy(exception.file, e.GetFile(), MAX_EXEPTION_FILE_LENGTH - 1);
m_cSendExceptionCallback(exception, (CMessage*)m_message, m_userData);
}
private:
COnSendSuccessCallback m_cSendSuccessCallback;
COnSendExceptionCallback m_cSendExceptionCallback;
void* m_message;
void* m_userData;
};
class CSendCallback : public AutoDeleteSendCallBack {
public:
CSendCallback(CSendSuccessCallback cSendSuccessCallback, CSendExceptionCallback cSendExceptionCallback) {
m_cSendSuccessCallback = cSendSuccessCallback;
m_cSendExceptionCallback = cSendExceptionCallback;
}
virtual ~CSendCallback() {}
virtual void onSuccess(SendResult& sendResult) {
CSendResult result;
result.sendStatus = CSendStatus((int)sendResult.getSendStatus());
result.offset = sendResult.getQueueOffset();
strncpy(result.msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result.msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
m_cSendSuccessCallback(result);
}
virtual void onException(MQException& e) {
CMQException exception;
exception.error = e.GetError();
exception.line = e.GetLine();
strncpy(exception.msg, e.what(), MAX_EXEPTION_MSG_LENGTH - 1);
strncpy(exception.file, e.GetFile(), MAX_EXEPTION_FILE_LENGTH - 1);
m_cSendExceptionCallback(exception);
}
private:
CSendSuccessCallback m_cSendSuccessCallback;
CSendExceptionCallback m_cSendExceptionCallback;
};
#ifndef CAPI_C_PRODUCER_TYPE_COMMON
#define CAPI_C_PRODUCER_TYPE_COMMON 0
#endif
#ifndef CAPI_C_PRODUCER_TYPE_ORDERLY
#define CAPI_C_PRODUCER_TYPE_ORDERLY 1
#endif
#ifndef CAPI_C_PRODUCER_TYPE_TRANSACTION
#define CAPI_C_PRODUCER_TYPE_TRANSACTION 2
#endif
typedef struct __DefaultProducer__ {
DefaultMQProducer* innerProducer;
TransactionMQProducer* innerTransactionProducer;
LocalTransactionListenerInner* listenerInner;
int producerType;
char* version;
} DefaultProducer;
CProducer* CreateProducer(const char* groupId) {
if (groupId == NULL) {
return NULL;
}
DefaultProducer* defaultMQProducer = new DefaultProducer();
defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_COMMON;
defaultMQProducer->innerProducer = new DefaultMQProducer(groupId);
defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH];
strncpy(defaultMQProducer->version, defaultMQProducer->innerProducer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1);
defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0;
defaultMQProducer->innerTransactionProducer = NULL;
defaultMQProducer->listenerInner = NULL;
return (CProducer*)defaultMQProducer;
}
CProducer* CreateOrderlyProducer(const char* groupId) {
if (groupId == NULL) {
return NULL;
}
DefaultProducer* defaultMQProducer = new DefaultProducer();
defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_ORDERLY;
defaultMQProducer->innerProducer = new DefaultMQProducer(groupId);
defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH];
strncpy(defaultMQProducer->version, defaultMQProducer->innerProducer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1);
defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0;
defaultMQProducer->innerTransactionProducer = NULL;
defaultMQProducer->listenerInner = NULL;
return (CProducer*)defaultMQProducer;
}
CProducer* CreateTransactionProducer(const char* groupId, CLocalTransactionCheckerCallback callback, void* userData) {
if (groupId == NULL) {
return NULL;
}
DefaultProducer* defaultMQProducer = new DefaultProducer();
defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_TRANSACTION;
defaultMQProducer->innerProducer = NULL;
defaultMQProducer->innerTransactionProducer = new TransactionMQProducer(groupId);
defaultMQProducer->listenerInner =
new LocalTransactionListenerInner((CProducer*)defaultMQProducer, callback, userData);
defaultMQProducer->innerTransactionProducer->setTransactionListener(defaultMQProducer->listenerInner);
defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH];
strncpy(defaultMQProducer->version, defaultMQProducer->innerTransactionProducer->version().c_str(),
MAX_SDK_VERSION_LENGTH - 1);
defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0;
return (CProducer*)defaultMQProducer;
}
int DestroyProducer(CProducer* pProducer) {
if (pProducer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)pProducer;
if (defaultMQProducer->version != NULL) {
delete defaultMQProducer->version;
defaultMQProducer->version = NULL;
}
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
if (defaultMQProducer->innerTransactionProducer != NULL) {
delete defaultMQProducer->innerTransactionProducer;
defaultMQProducer->innerTransactionProducer = NULL;
}
} else {
if (defaultMQProducer->innerProducer != NULL) {
delete defaultMQProducer->innerProducer;
defaultMQProducer->innerProducer = NULL;
}
}
delete reinterpret_cast<DefaultProducer*>(pProducer);
return OK;
}
int StartProducer(CProducer* producer) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->start();
} else {
defaultMQProducer->innerProducer->start();
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int ShutdownProducer(CProducer* producer) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->shutdown();
} else {
defaultMQProducer->innerProducer->shutdown();
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
const char* ShowProducerVersion(CProducer* producer) {
if (producer == NULL) {
return DEFAULT_SDK_VERSION;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
return defaultMQProducer->version;
}
int SetProducerNameServerAddress(CProducer* producer, const char* namesrv) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setNamesrvAddr(namesrv);
} else {
defaultMQProducer->innerProducer->setNamesrvAddr(namesrv);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerNameServerDomain(CProducer* producer, const char* domain) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setNamesrvDomain(domain);
} else {
defaultMQProducer->innerProducer->setNamesrvDomain(domain);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SendMessageSync(CProducer* producer, CMessage* msg, CSendResult* result) {
// CSendResult sendResult;
if (producer == NULL || msg == NULL || result == NULL) {
return NULL_POINTER;
}
try {
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
SendResult sendResult = defaultMQProducer->innerProducer->send(*message);
switch (sendResult.getSendStatus()) {
case SEND_OK:
result->sendStatus = E_SEND_OK;
break;
case SEND_FLUSH_DISK_TIMEOUT:
result->sendStatus = E_SEND_FLUSH_DISK_TIMEOUT;
break;
case SEND_FLUSH_SLAVE_TIMEOUT:
result->sendStatus = E_SEND_FLUSH_SLAVE_TIMEOUT;
break;
case SEND_SLAVE_NOT_AVAILABLE:
result->sendStatus = E_SEND_SLAVE_NOT_AVAILABLE;
break;
default:
result->sendStatus = E_SEND_OK;
break;
}
result->offset = sendResult.getQueueOffset();
strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_SYNC_FAILED;
}
return OK;
}
int SendBatchMessage(CProducer* producer, CBatchMessage* batcMsg, CSendResult* result) {
// CSendResult sendResult;
if (producer == NULL || batcMsg == NULL || result == NULL) {
return NULL_POINTER;
}
try {
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
vector<MQMessage>* message = (vector<MQMessage>*)batcMsg;
SendResult sendResult = defaultMQProducer->innerProducer->send(*message);
switch (sendResult.getSendStatus()) {
case SEND_OK:
result->sendStatus = E_SEND_OK;
break;
case SEND_FLUSH_DISK_TIMEOUT:
result->sendStatus = E_SEND_FLUSH_DISK_TIMEOUT;
break;
case SEND_FLUSH_SLAVE_TIMEOUT:
result->sendStatus = E_SEND_FLUSH_SLAVE_TIMEOUT;
break;
case SEND_SLAVE_NOT_AVAILABLE:
result->sendStatus = E_SEND_SLAVE_NOT_AVAILABLE;
break;
default:
result->sendStatus = E_SEND_OK;
break;
}
result->offset = sendResult.getQueueOffset();
strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
} catch (exception& e) {
return PRODUCER_SEND_SYNC_FAILED;
}
return OK;
}
int SendMessageAsync(CProducer* producer,
CMessage* msg,
CSendSuccessCallback cSendSuccessCallback,
CSendExceptionCallback cSendExceptionCallback) {
if (producer == NULL || msg == NULL || cSendSuccessCallback == NULL || cSendExceptionCallback == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
CSendCallback* cSendCallback = new CSendCallback(cSendSuccessCallback, cSendExceptionCallback);
try {
defaultMQProducer->innerProducer->send(*message, cSendCallback);
} catch (exception& e) {
if (cSendCallback != NULL) {
if (std::type_index(typeid(e)) == std::type_index(typeid(MQException))) {
MQException& mqe = (MQException&)e;
cSendCallback->onException(mqe);
}
delete cSendCallback;
cSendCallback = NULL;
}
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ASYNC_FAILED;
}
return OK;
}
int SendAsync(CProducer* producer,
CMessage* msg,
COnSendSuccessCallback onSuccess,
COnSendExceptionCallback onException,
void* usrData) {
if (producer == NULL || msg == NULL || onSuccess == NULL || onException == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
COnSendCallback* cSendCallback = new COnSendCallback(onSuccess, onException, (void*)msg, usrData);
try {
defaultMQProducer->innerProducer->send(*message, cSendCallback);
} catch (exception& e) {
if (cSendCallback != NULL) {
if (std::type_index(typeid(e)) == std::type_index(typeid(MQException))) {
MQException& mqe = (MQException&)e;
cSendCallback->onException(mqe);
}
delete cSendCallback;
cSendCallback = NULL;
}
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ASYNC_FAILED;
}
return OK;
}
int SendMessageOneway(CProducer* producer, CMessage* msg) {
if (producer == NULL || msg == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
try {
defaultMQProducer->innerProducer->sendOneway(*message);
} catch (exception& e) {
return PRODUCER_SEND_ONEWAY_FAILED;
}
return OK;
}
int SendMessageOnewayOrderly(CProducer* producer, CMessage* msg, QueueSelectorCallback selector, void* arg) {
if (producer == NULL || msg == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
try {
SelectMessageQueue selectMessageQueue(selector);
defaultMQProducer->innerProducer->sendOneway(*message, &selectMessageQueue, arg);
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ONEWAY_FAILED;
}
return OK;
}
int SendMessageOrderlyAsync(CProducer* producer,
CMessage* msg,
QueueSelectorCallback callback,
void* arg,
CSendSuccessCallback cSendSuccessCallback,
CSendExceptionCallback cSendExceptionCallback) {
if (producer == NULL || msg == NULL || callback == NULL || cSendSuccessCallback == NULL ||
cSendExceptionCallback == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
CSendCallback* cSendCallback = new CSendCallback(cSendSuccessCallback, cSendExceptionCallback);
try {
// Constructing SelectMessageQueue objects through function pointer callback
SelectMessageQueue selectMessageQueue(callback);
defaultMQProducer->innerProducer->send(*message, &selectMessageQueue, arg, cSendCallback);
} catch (exception& e) {
printf("%s\n", e.what());
// std::count<<e.what( )<<std::endl;
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ORDERLYASYNC_FAILED;
}
return OK;
}
int SendMessageOrderly(CProducer* producer,
CMessage* msg,
QueueSelectorCallback callback,
void* arg,
int autoRetryTimes,
CSendResult* result) {
if (producer == NULL || msg == NULL || callback == NULL || arg == NULL || result == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
try {
// Constructing SelectMessageQueue objects through function pointer callback
SelectMessageQueue selectMessageQueue(callback);
SendResult sendResult = defaultMQProducer->innerProducer->send(*message, &selectMessageQueue, arg, autoRetryTimes);
// Convert SendStatus to CSendStatus
result->sendStatus = CSendStatus((int)sendResult.getSendStatus());
result->offset = sendResult.getQueueOffset();
strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ORDERLY_FAILED;
}
return OK;
}
int SendMessageOrderlyByShardingKey(CProducer* producer, CMessage* msg, const char* shardingKey, CSendResult* result) {
if (producer == NULL || msg == NULL || shardingKey == NULL || result == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
string sKey(shardingKey);
message->setProperty("__SHARDINGKEY", sKey);
try {
// Constructing SelectMessageQueue objects through function pointer callback
int retryTimes = 3;
SelectMessageQueueInner selectMessageQueue;
SendResult sendResult =
defaultMQProducer->innerProducer->send(*message, &selectMessageQueue, (void*)shardingKey, retryTimes);
// Convert SendStatus to CSendStatus
result->sendStatus = CSendStatus((int)sendResult.getSendStatus());
result->offset = sendResult.getQueueOffset();
strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_ORDERLY_FAILED;
}
return OK;
}
int SendMessageTransaction(CProducer* producer,
CMessage* msg,
CLocalTransactionExecutorCallback callback,
void* userData,
CSendResult* result) {
if (producer == NULL || msg == NULL || callback == NULL || result == NULL) {
return NULL_POINTER;
}
try {
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
MQMessage* message = (MQMessage*)msg;
MyLocalTransactionExecuterInner executerInner(callback, msg, userData);
// defaultMQProducer->listenerInner->setM_m_ExcutorCallback(callback);
SendResult sendResult =
defaultMQProducer->innerTransactionProducer->sendMessageInTransaction(*message, &executerInner);
result->sendStatus = CSendStatus((int)sendResult.getSendStatus());
result->offset = sendResult.getQueueOffset();
strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1);
result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0;
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_SEND_TRANSACTION_FAILED;
}
return OK;
}
int SetProducerGroupName(CProducer* producer, const char* groupName) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setGroupName(groupName);
} else {
defaultMQProducer->innerProducer->setGroupName(groupName);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerInstanceName(CProducer* producer, const char* instanceName) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setInstanceName(instanceName);
} else {
defaultMQProducer->innerProducer->setInstanceName(instanceName);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerSessionCredentials(CProducer* producer,
const char* accessKey,
const char* secretKey,
const char* onsChannel) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setSessionCredentials(accessKey, secretKey, onsChannel);
} else {
defaultMQProducer->innerProducer->setSessionCredentials(accessKey, secretKey, onsChannel);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerLogPath(CProducer* producer, const char* logPath) {
if (producer == NULL) {
return NULL_POINTER;
}
return OK;
}
int SetProducerLogFileNumAndSize(CProducer* producer, int fileNum, long fileSize) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setLogFileSizeAndNum(fileNum, fileSize);
} else {
defaultMQProducer->innerProducer->setLogFileSizeAndNum(fileNum, fileSize);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerLogLevel(CProducer* producer, CLogLevel level) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setLogLevel((elogLevel)level);
} else {
defaultMQProducer->innerProducer->setLogLevel((elogLevel)level);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerSendMsgTimeout(CProducer* producer, int timeout) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setSendMsgTimeout(timeout);
} else {
defaultMQProducer->innerProducer->setSendMsgTimeout(timeout);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerCompressMsgBodyOverHowmuch(CProducer* producer, int howmuch) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setCompressMsgBodyOverHowmuch(howmuch);
} else {
defaultMQProducer->innerProducer->setCompressMsgBodyOverHowmuch(howmuch);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerCompressLevel(CProducer* producer, int level) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setCompressLevel(level);
} else {
defaultMQProducer->innerProducer->setCompressLevel(level);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerMaxMessageSize(CProducer* producer, int size) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setMaxMessageSize(size);
} else {
defaultMQProducer->innerProducer->setMaxMessageSize(size);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
int SetProducerMessageTrace(CProducer* producer, CTraceModel openTrace) {
if (producer == NULL) {
return NULL_POINTER;
}
DefaultProducer* defaultMQProducer = (DefaultProducer*)producer;
bool messageTrace = openTrace == OPEN ? true : false;
try {
if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) {
defaultMQProducer->innerTransactionProducer->setMessageTrace(messageTrace);
} else {
defaultMQProducer->innerProducer->setMessageTrace(messageTrace);
}
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PRODUCER_START_FAILED;
}
return OK;
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,259 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CPullConsumer.h"
#include "CCommon.h"
#include "CMessageExt.h"
#include "DefaultMQPullConsumer.h"
#include "MQClientErrorContainer.h"
using namespace rocketmq;
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
char VERSION_FOR_PULL_CONSUMER[MAX_SDK_VERSION_LENGTH];
CPullConsumer* CreatePullConsumer(const char* groupId) {
if (groupId == NULL) {
return NULL;
}
DefaultMQPullConsumer* defaultMQPullConsumer = new DefaultMQPullConsumer(groupId);
strncpy(VERSION_FOR_PULL_CONSUMER, defaultMQPullConsumer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1);
VERSION_FOR_PULL_CONSUMER[MAX_SDK_VERSION_LENGTH - 1] = 0;
return (CPullConsumer*)defaultMQPullConsumer;
}
int DestroyPullConsumer(CPullConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
delete reinterpret_cast<DefaultMQPullConsumer*>(consumer);
return OK;
}
int StartPullConsumer(CPullConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
try {
((DefaultMQPullConsumer*)consumer)->start();
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PULLCONSUMER_START_FAILED;
}
return OK;
}
int ShutdownPullConsumer(CPullConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->shutdown();
return OK;
}
const char* ShowPullConsumerVersion(CPullConsumer* consumer) {
if (consumer == NULL) {
return NULL;
}
return VERSION_FOR_PULL_CONSUMER;
}
int SetPullConsumerGroupID(CPullConsumer* consumer, const char* groupId) {
if (consumer == NULL || groupId == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setGroupName(groupId);
return OK;
}
const char* GetPullConsumerGroupID(CPullConsumer* consumer) {
if (consumer == NULL) {
return NULL;
}
return ((DefaultMQPullConsumer*)consumer)->getGroupName().c_str();
}
int SetPullConsumerNameServerAddress(CPullConsumer* consumer, const char* namesrv) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setNamesrvAddr(namesrv);
return OK;
}
int SetPullConsumerNameServerDomain(CPullConsumer* consumer, const char* domain) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setNamesrvDomain(domain);
return OK;
}
int SetPullConsumerSessionCredentials(CPullConsumer* consumer,
const char* accessKey,
const char* secretKey,
const char* channel) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setSessionCredentials(accessKey, secretKey, channel);
return OK;
}
int SetPullConsumerLogPath(CPullConsumer* consumer, const char* logPath) {
if (consumer == NULL) {
return NULL_POINTER;
}
// Todo, This api should be implemented by core api.
//((DefaultMQPullConsumer *) consumer)->setInstanceName(instanceName);
return OK;
}
int SetPullConsumerLogFileNumAndSize(CPullConsumer* consumer, int fileNum, long fileSize) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setLogFileSizeAndNum(fileNum, fileSize);
return OK;
}
int SetPullConsumerLogLevel(CPullConsumer* consumer, CLogLevel level) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPullConsumer*)consumer)->setLogLevel((elogLevel)level);
return OK;
}
int FetchSubscriptionMessageQueues(CPullConsumer* consumer, const char* topic, CMessageQueue** mqs, int* size) {
if (consumer == NULL) {
return NULL_POINTER;
}
unsigned int index = 0;
CMessageQueue* temMQ = NULL;
std::vector<MQMessageQueue> fullMQ;
try {
((DefaultMQPullConsumer*)consumer)->fetchSubscribeMessageQueues(topic, fullMQ);
*size = fullMQ.size();
// Alloc memory to save the pointer to CPP MessageQueue, and the MessageQueues may be changed.
// Thus, this memory should be released by users using @ReleaseSubscribeMessageQueue every time.
temMQ = (CMessageQueue*)malloc(*size * sizeof(CMessageQueue));
if (temMQ == NULL) {
*size = 0;
*mqs = NULL;
return MALLOC_FAILED;
}
auto iter = fullMQ.begin();
for (index = 0; iter != fullMQ.end() && index <= fullMQ.size(); ++iter, index++) {
strncpy(temMQ[index].topic, iter->getTopic().c_str(), MAX_TOPIC_LENGTH - 1);
strncpy(temMQ[index].brokerName, iter->getBrokerName().c_str(), MAX_BROKER_NAME_ID_LENGTH - 1);
temMQ[index].queueId = iter->getQueueId();
}
*mqs = temMQ;
} catch (MQException& e) {
*size = 0;
*mqs = NULL;
MQClientErrorContainer::setErr(string(e.what()));
return PULLCONSUMER_FETCH_MQ_FAILED;
}
return OK;
}
int ReleaseSubscriptionMessageQueue(CMessageQueue* mqs) {
if (mqs == NULL) {
return NULL_POINTER;
}
free((void*)mqs);
mqs = NULL;
return OK;
}
CPullResult Pull(CPullConsumer* consumer,
const CMessageQueue* mq,
const char* subExpression,
long long offset,
int maxNums) {
CPullResult pullResult;
memset(&pullResult, 0, sizeof(CPullResult));
if (consumer == NULL || subExpression == NULL) {
pullResult.pullStatus = E_BROKER_TIMEOUT;
return pullResult;
}
MQMessageQueue messageQueue(mq->topic, mq->brokerName, mq->queueId);
PullResult cppPullResult;
try {
cppPullResult = ((DefaultMQPullConsumer*)consumer)->pull(messageQueue, subExpression, offset, maxNums);
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
cppPullResult.pullStatus = BROKER_TIMEOUT;
}
if (cppPullResult.pullStatus != BROKER_TIMEOUT) {
pullResult.maxOffset = cppPullResult.maxOffset;
pullResult.minOffset = cppPullResult.minOffset;
pullResult.nextBeginOffset = cppPullResult.nextBeginOffset;
}
switch (cppPullResult.pullStatus) {
case FOUND: {
pullResult.pullStatus = E_FOUND;
pullResult.size = cppPullResult.msgFoundList.size();
PullResult* tmpPullResult = new PullResult(cppPullResult);
pullResult.pData = tmpPullResult;
// Alloc memory to save the pointer to CPP MQMessageExt, which will be release by the CPP SDK core.
// Thus, this memory should be released by users using @ReleasePullResult
pullResult.msgFoundList = (CMessageExt**)malloc(pullResult.size * sizeof(CMessageExt*));
for (size_t i = 0; i < cppPullResult.msgFoundList.size(); i++) {
MQMessageExt* msg = const_cast<MQMessageExt*>(&tmpPullResult->msgFoundList[i]);
pullResult.msgFoundList[i] = (CMessageExt*)(msg);
}
break;
}
case NO_NEW_MSG: {
pullResult.pullStatus = E_NO_NEW_MSG;
break;
}
case NO_MATCHED_MSG: {
pullResult.pullStatus = E_NO_MATCHED_MSG;
break;
}
case OFFSET_ILLEGAL: {
pullResult.pullStatus = E_OFFSET_ILLEGAL;
break;
}
case BROKER_TIMEOUT: {
pullResult.pullStatus = E_BROKER_TIMEOUT;
break;
}
default:
pullResult.pullStatus = E_NO_NEW_MSG;
break;
}
return pullResult;
}
int ReleasePullResult(CPullResult pullResult) {
if (pullResult.size == 0 || pullResult.msgFoundList == NULL || pullResult.pData == NULL) {
return NULL_POINTER;
}
if (pullResult.pData != NULL) {
try {
delete ((PullResult*)pullResult.pData);
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return NULL_POINTER;
}
}
free((void*)pullResult.msgFoundList);
pullResult.msgFoundList = NULL;
return OK;
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,309 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CPushConsumer.h"
#include <map>
#include "CCommon.h"
#include "CMessageExt.h"
#include "DefaultMQPushConsumer.h"
#include "MQClientErrorContainer.h"
using namespace rocketmq;
using namespace std;
class MessageListenerInner : public MessageListenerConcurrently {
public:
MessageListenerInner() {}
MessageListenerInner(CPushConsumer* consumer, MessageCallBack pCallback) {
m_pconsumer = consumer;
m_pMsgReceiveCallback = pCallback;
}
~MessageListenerInner() {}
ConsumeStatus consumeMessage(const std::vector<MQMessageExt>& msgs) {
// to do user call back
if (m_pMsgReceiveCallback == NULL) {
return RECONSUME_LATER;
}
for (size_t i = 0; i < msgs.size(); ++i) {
MQMessageExt* msg = const_cast<MQMessageExt*>(&msgs[i]);
CMessageExt* message = (CMessageExt*)(msg);
if (m_pMsgReceiveCallback(m_pconsumer, message) != E_CONSUME_SUCCESS)
return RECONSUME_LATER;
}
return CONSUME_SUCCESS;
}
private:
MessageCallBack m_pMsgReceiveCallback;
CPushConsumer* m_pconsumer;
};
class MessageListenerOrderlyInner : public MessageListenerOrderly {
public:
MessageListenerOrderlyInner(CPushConsumer* consumer, MessageCallBack pCallback) {
m_pconsumer = consumer;
m_pMsgReceiveCallback = pCallback;
}
ConsumeStatus consumeMessage(const std::vector<MQMessageExt>& msgs) {
if (m_pMsgReceiveCallback == NULL) {
return RECONSUME_LATER;
}
for (size_t i = 0; i < msgs.size(); ++i) {
MQMessageExt* msg = const_cast<MQMessageExt*>(&msgs[i]);
CMessageExt* message = (CMessageExt*)(msg);
if (m_pMsgReceiveCallback(m_pconsumer, message) != E_CONSUME_SUCCESS)
return RECONSUME_LATER;
}
return CONSUME_SUCCESS;
}
private:
MessageCallBack m_pMsgReceiveCallback;
CPushConsumer* m_pconsumer;
};
map<CPushConsumer*, MessageListenerInner*> g_ListenerMap;
map<CPushConsumer*, MessageListenerOrderlyInner*> g_OrderListenerMap;
#ifdef __cplusplus
extern "C" {
#endif
char VERSION_FOR_PUSH_CONSUMER[MAX_SDK_VERSION_LENGTH];
CPushConsumer* CreatePushConsumer(const char* groupId) {
if (groupId == NULL) {
return NULL;
}
DefaultMQPushConsumer* defaultMQPushConsumer = new DefaultMQPushConsumer(groupId);
defaultMQPushConsumer->setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET);
strncpy(VERSION_FOR_PUSH_CONSUMER, defaultMQPushConsumer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1);
VERSION_FOR_PUSH_CONSUMER[MAX_SDK_VERSION_LENGTH - 1] = 0;
return (CPushConsumer*)defaultMQPushConsumer;
}
int DestroyPushConsumer(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
delete reinterpret_cast<DefaultMQPushConsumer*>(consumer);
return OK;
}
int StartPushConsumer(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
try {
((DefaultMQPushConsumer*)consumer)->start();
} catch (exception& e) {
MQClientErrorContainer::setErr(string(e.what()));
return PUSHCONSUMER_START_FAILED;
}
return OK;
}
int ShutdownPushConsumer(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->shutdown();
return OK;
}
const char* ShowPushConsumerVersion(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL;
}
return VERSION_FOR_PUSH_CONSUMER;
}
int SetPushConsumerGroupID(CPushConsumer* consumer, const char* groupId) {
if (consumer == NULL || groupId == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setGroupName(groupId);
return OK;
}
const char* GetPushConsumerGroupID(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL;
}
return ((DefaultMQPushConsumer*)consumer)->getGroupName().c_str();
}
int SetPushConsumerNameServerAddress(CPushConsumer* consumer, const char* namesrv) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setNamesrvAddr(namesrv);
return OK;
}
int SetPushConsumerNameServerDomain(CPushConsumer* consumer, const char* domain) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setNamesrvDomain(domain);
return OK;
}
int Subscribe(CPushConsumer* consumer, const char* topic, const char* expression) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->subscribe(topic, expression);
return OK;
}
int RegisterMessageCallback(CPushConsumer* consumer, MessageCallBack pCallback) {
if (consumer == NULL || pCallback == NULL) {
return NULL_POINTER;
}
MessageListenerInner* listenerInner = new MessageListenerInner(consumer, pCallback);
((DefaultMQPushConsumer*)consumer)->registerMessageListener(listenerInner);
g_ListenerMap[consumer] = listenerInner;
return OK;
}
int RegisterMessageCallbackOrderly(CPushConsumer* consumer, MessageCallBack pCallback) {
if (consumer == NULL || pCallback == NULL) {
return NULL_POINTER;
}
MessageListenerOrderlyInner* messageListenerOrderlyInner = new MessageListenerOrderlyInner(consumer, pCallback);
((DefaultMQPushConsumer*)consumer)->registerMessageListener(messageListenerOrderlyInner);
g_OrderListenerMap[consumer] = messageListenerOrderlyInner;
return OK;
}
int UnregisterMessageCallbackOrderly(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
map<CPushConsumer*, MessageListenerOrderlyInner*>::iterator iter;
iter = g_OrderListenerMap.find(consumer);
if (iter != g_OrderListenerMap.end()) {
MessageListenerOrderlyInner* listenerInner = iter->second;
if (listenerInner != NULL) {
delete listenerInner;
}
g_OrderListenerMap.erase(iter);
}
return OK;
}
int UnregisterMessageCallback(CPushConsumer* consumer) {
if (consumer == NULL) {
return NULL_POINTER;
}
map<CPushConsumer*, MessageListenerInner*>::iterator iter;
iter = g_ListenerMap.find(consumer);
if (iter != g_ListenerMap.end()) {
MessageListenerInner* listenerInner = iter->second;
if (listenerInner != NULL) {
delete listenerInner;
}
g_ListenerMap.erase(iter);
}
return OK;
}
int SetPushConsumerMessageModel(CPushConsumer* consumer, CMessageModel messageModel) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setMessageModel(MessageModel((int)messageModel));
return OK;
}
int SetPushConsumerThreadCount(CPushConsumer* consumer, int threadCount) {
if (consumer == NULL || threadCount == 0) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setConsumeThreadCount(threadCount);
return OK;
}
int SetPushConsumerMessageBatchMaxSize(CPushConsumer* consumer, int batchSize) {
if (consumer == NULL || batchSize == 0) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setConsumeMessageBatchMaxSize(batchSize);
return OK;
}
int SetPushConsumerMaxCacheMessageSize(CPushConsumer* consumer, int maxCacheSize) {
if (consumer == NULL || maxCacheSize <= 0) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setMaxCacheMsgSizePerQueue(maxCacheSize);
return OK;
}
int SetPushConsumerMaxCacheMessageSizeInMb(CPushConsumer* consumer, int maxCacheSizeInMb) {
if (consumer == NULL || maxCacheSizeInMb <= 0) {
return NULL_POINTER;
}
return Not_Support;
}
int SetPushConsumerInstanceName(CPushConsumer* consumer, const char* instanceName) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setInstanceName(instanceName);
return OK;
}
int SetPushConsumerSessionCredentials(CPushConsumer* consumer,
const char* accessKey,
const char* secretKey,
const char* channel) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setSessionCredentials(accessKey, secretKey, channel);
return OK;
}
int SetPushConsumerLogPath(CPushConsumer* consumer, const char* logPath) {
if (consumer == NULL) {
return NULL_POINTER;
}
// Todo, This api should be implemented by core api.
//((DefaultMQPushConsumer *) consumer)->setInstanceName(instanceName);
return OK;
}
int SetPushConsumerLogFileNumAndSize(CPushConsumer* consumer, int fileNum, long fileSize) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setLogFileSizeAndNum(fileNum, fileSize);
return OK;
}
int SetPushConsumerLogLevel(CPushConsumer* consumer, CLogLevel level) {
if (consumer == NULL) {
return NULL_POINTER;
}
((DefaultMQPushConsumer*)consumer)->setLogLevel((elogLevel)level);
return OK;
}
int SetPushConsumerMessageTrace(CPushConsumer* consumer, CTraceModel openTrace) {
if (consumer == NULL) {
return NULL_POINTER;
}
bool messageTrace = openTrace == OPEN ? true : false;
((DefaultMQPushConsumer*)consumer)->setMessageTrace(messageTrace);
return OK;
}
#ifdef __cplusplus
};
#endif

View File

@@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "CSendResult.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __BATCHMESSAGE_H__
#define __BATCHMESSAGE_H__
#include <string>
#include "MQMessage.h"
namespace rocketmq {
class BatchMessage : public MQMessage {
public:
static std::string encode(std::vector<MQMessage>& msgs);
static std::string encode(MQMessage& message);
};
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,209 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __DEFAULTMQADMIN_H__
#define __DEFAULTMQADMIN_H__
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include "MQClient.h"
#include "MQMessageExt.h"
#include "MQMessageQueue.h"
#include "QueryResult.h"
#include "RocketMQClient.h"
#include "SessionCredentials.h"
#include "UtilAll.h"
namespace rocketmq {
class MQClientFactory;
//<!***************************************************************************
class DefaultMQClient {
public:
DefaultMQClient();
virtual ~DefaultMQClient();
public:
// clientid=processId-ipAddr@instanceName;
std::string getClientVersionString() const;
std::string getMQClientId() const;
const std::string& getNamesrvAddr() const;
void setNamesrvAddr(const std::string& namesrvAddr);
const std::string& getNamesrvDomain() const;
void setNamesrvDomain(const std::string& namesrvDomain);
const std::string& getInstanceName() const;
void setInstanceName(const std::string& instanceName);
// nameSpace
const std::string& getNameSpace() const;
void setNameSpace(const std::string& nameSpace);
const std::string& getGroupName() const;
void setGroupName(const std::string& groupname);
/**
* no realization
*/
void createTopic(const std::string& key, const std::string& newTopic, int queueNum);
/**
* search earliest msg store time for specified queue
*
* @param mq
* message queue
* @return earliest store time, ms
*/
int64 earliestMsgStoreTime(const MQMessageQueue& mq);
/**
* search maxOffset of queue
*
* @param mq
* message queue
* @return minOffset of queue
*/
int64 minOffset(const MQMessageQueue& mq);
/**
* search maxOffset of queue
* Note: maxOffset-1 is max offset that could get msg
* @param mq
* message queue
* @return maxOffset of queue
*/
int64 maxOffset(const MQMessageQueue& mq);
/**
* get queue offset by timestamp
*
* @param mq
* mq queue
* @param timestamp
* timestamp with ms unit
* @return queue offset according to timestamp
*/
int64 searchOffset(const MQMessageQueue& mq, uint64_t timestamp);
/**
* get whole msg info from broker by msgId
*
* @param msgId
* @return MQMessageExt
*/
MQMessageExt* viewMessage(const std::string& msgId);
/**
* query message by topic and key
*
* @param topic
* topic name
* @param key
* topic key
* @param maxNum
* query num
* @param begin
* begin timestamp
* @param end
* end timestamp
* @return
* according to QueryResult
*/
QueryResult queryMessage(const std::string& topic, const std::string& key, int maxNum, int64 begin, int64 end);
std::vector<MQMessageQueue> getTopicMessageQueueInfo(const std::string& topic);
// log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default
// log file num is 3, each log size is 100M
void setLogLevel(elogLevel inputLevel);
elogLevel getLogLevel();
void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit
/** set TcpTransport pull thread num, which dermine the num of threads to
distribute network data,
1. its default value is CPU num, it must be setted before producer/consumer
start, minimum value is CPU num;
2. this pullThread num must be tested on your environment to find the best
value for RT of sendMsg or delay time of consume msg before you change it;
3. producer and consumer need different pullThread num, if set this num,
producer and consumer must set different instanceName.
4. configuration suggestion:
1>. minimum RT of sendMsg:
pullThreadNum = brokerNum*2
**/
void setTcpTransportPullThreadNum(int num);
int getTcpTransportPullThreadNum() const;
/** timeout of tcp connect, it is same meaning for both producer and consumer;
1. default value is 3000ms
2. input parameter could only be milliSecond, suggestion value is
1000-3000ms;
**/
void setTcpTransportConnectTimeout(uint64_t timeout); // ms
uint64_t getTcpTransportConnectTimeout() const;
/** timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout,
returns NULL
1. paremeter unit is ms, default value is 3000ms, the minimun value is
1000ms
suggestion value is 3000ms;
2. if configured with value smaller than 1000ms, the tryLockTimeout value
will be setted to 1000ms
**/
void setTcpTransportTryLockTimeout(uint64_t timeout); // ms
uint64_t getTcpTransportTryLockTimeout() const;
void setUnitName(std::string unitName);
const std::string& getUnitName() const;
void setSessionCredentials(const std::string& input_accessKey,
const std::string& input_secretKey,
const std::string& input_onsChannel);
const SessionCredentials& getSessionCredentials() const;
virtual void setFactory(MQClientFactory*);
void setEnableSsl(bool enableSsl);
bool getEnableSsl() const;
void setSslPropertyFile(const std::string& sslPropertyFile);
const std::string& getSslPropertyFile() const;
bool getMessageTrace() const;
void setMessageTrace(bool mMessageTrace);
protected:
virtual void start();
virtual void shutdown();
MQClientFactory* getFactory() const;
virtual bool isServiceStateOk();
void showClientConfigs();
protected:
std::string m_namesrvAddr;
std::string m_namesrvDomain;
std::string m_instanceName;
std::string m_nameSpace;
std::string m_GroupName;
std::string m_sslPropertyFile{DEFAULT_SSL_PROPERTY_FILE};
bool m_enableSsl{false};
MQClientFactory* m_clientFactory;
int m_serviceState;
int m_pullThreadNum;
uint64_t m_tcpConnectTimeout; // ms
uint64_t m_tcpTransportTryLockTimeout; // s
std::string m_unitName;
SessionCredentials m_SessionCredentials;
bool m_messageTrace;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQCONSUMER_H__
#define __MQCONSUMER_H__
#include <string>
#include "AsyncCallback.h"
#include "ConsumeType.h"
#include "DefaultMQClient.h"
#include "RocketMQClient.h"
namespace rocketmq {
class SubscriptionData;
class PullRequest;
class Rebalance;
class ConsumerRunningInfo;
//<!************************************************************************
class MQConsumer : public DefaultMQClient {
public:
virtual ~MQConsumer() {}
virtual bool sendMessageBack(MQMessageExt& msg, int delayLevel, std::string& brokerName) = 0;
virtual void fetchSubscribeMessageQueues(const std::string& topic, std::vector<MQMessageQueue>& mqs) = 0;
virtual void doRebalance() = 0;
virtual void persistConsumerOffset() = 0;
virtual void persistConsumerOffsetByResetOffset() = 0;
virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector<MQMessageQueue>& info) = 0;
virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset) = 0;
virtual void removeConsumeOffset(const MQMessageQueue& mq) = 0;
virtual ConsumeType getConsumeType() = 0;
virtual ConsumeFromWhere getConsumeFromWhere() = 0;
virtual void getSubscriptions(std::vector<SubscriptionData>&) = 0;
virtual bool producePullMsgTask(boost::weak_ptr<PullRequest>) = 0;
virtual Rebalance* getRebalance() const = 0;
virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums) = 0;
virtual void pull(const MQMessageQueue& mq,
const std::string& subExpression,
int64 offset,
int maxNums,
PullCallback* pPullCallback) = 0;
virtual ConsumerRunningInfo* getConsumerRunningInfo() = 0;
public:
MessageModel getMessageModel() const { return m_messageModel; }
void setMessageModel(MessageModel messageModel) { m_messageModel = messageModel; }
bool isUseNameSpaceMode() const { return m_useNameSpaceMode; }
protected:
MessageModel m_messageModel;
bool m_useNameSpaceMode = false;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __MQPRODUCER_H__
#define __MQPRODUCER_H__
#include "AsyncCallback.h"
#include "DefaultMQClient.h"
#include "MQMessageQueue.h"
#include "MQSelector.h"
#include "RocketMQClient.h"
#include "SendResult.h"
namespace rocketmq {
//<!***************************************************************************
class MQProducer : public DefaultMQClient {
public:
MQProducer() {}
virtual ~MQProducer() {}
// if setted bActiveBroker, will search brokers with best service state
// firstly, then search brokers that had been sent failed by last time;
virtual SendResult send(MQMessage& msg, bool bSelectActiveBroker = false) = 0;
virtual SendResult send(MQMessage& msg, const MQMessageQueue& mq) = 0;
// strict order msg, if send failed on seleted MessageQueue, throw exception
// to up layer
virtual SendResult send(MQMessage& msg, MessageQueueSelector* selector, void* arg) = 0;
// non-strict order msg, if send failed on seleted MessageQueue, will auto
// retry others Broker queues with autoRetryTimes;
// if setted bActiveBroker, if send failed on seleted MessageQueue, , and then
// search brokers with best service state, lastly will search brokers that had
// been sent failed by last time;
virtual SendResult send(MQMessage& msg,
MessageQueueSelector* selector,
void* arg,
int autoRetryTimes,
bool bActiveBroker = false) = 0;
virtual void send(MQMessage& msg, SendCallback* sendCallback, bool bSelectActiveBroker = false) = 0;
virtual void send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* sendCallback) = 0;
virtual void send(MQMessage& msg, MessageQueueSelector* selector, void* arg, SendCallback* sendCallback) = 0;
virtual SendResult send(std::vector<MQMessage>& msgs) = 0;
virtual SendResult send(std::vector<MQMessage>& msgs, const MQMessageQueue& mq) = 0;
virtual void sendOneway(MQMessage& msg, bool bSelectActiveBroker = false) = 0;
virtual void sendOneway(MQMessage& msg, const MQMessageQueue& mq) = 0;
virtual void sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg) = 0;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

View File

@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef __QUERYRESULT_H__
#define __QUERYRESULT_H__
#include "MQMessageExt.h"
#include "RocketMQClient.h"
namespace rocketmq {
//<!************************************************************************
class ROCKETMQCLIENT_API QueryResult {
public:
QueryResult(uint64 indexLastUpdateTimestamp, const std::vector<MQMessageExt*>& messageList) {
m_indexLastUpdateTimestamp = indexLastUpdateTimestamp;
m_messageList = messageList;
}
uint64 getIndexLastUpdateTimestamp() { return m_indexLastUpdateTimestamp; }
std::vector<MQMessageExt*>& getMessageList() { return m_messageList; }
private:
uint64 m_indexLastUpdateTimestamp;
std::vector<MQMessageExt*> m_messageList;
};
//<!***************************************************************************
} // namespace rocketmq
#endif

Some files were not shown because too many files have changed in this diff Show More