Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Kwan的解忧杂货铺@新空间代码工作室
Rocketmq
提交
64e4ca72
R
Rocketmq
项目概览
Kwan的解忧杂货铺@新空间代码工作室
/
Rocketmq
与 Fork 源项目一致
Fork自
Apache RocketMQ / Rocketmq
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rocketmq
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
未验证
提交
64e4ca72
编写于
2月 28, 2020
作者:
H
Heng Du
提交者:
GitHub
2月 28, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1516 from shenhui0509/sync_pipeline
[ISSUE #1515] SYNC_MASTER could be change into pipeline manner
上级
0e7d2712
b143ff6d
变更
31
显示空白变更内容
内联
并排
Showing
31 changed file
with
1079 addition
and
213 deletion
+1079
-213
broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
...he/rocketmq/broker/plugin/AbstractPluginMessageStore.java
+12
-0
broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
...cketmq/broker/processor/AbstractSendMessageProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
...pache/rocketmq/broker/processor/AdminBrokerProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
...ache/rocketmq/broker/processor/ClientManageProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
...he/rocketmq/broker/processor/ConsumerManageProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java
...he/rocketmq/broker/processor/EndTransactionProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java
...he/rocketmq/broker/processor/ForwardRequestProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
...pache/rocketmq/broker/processor/PullMessageProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java
...ache/rocketmq/broker/processor/QueryMessageProcessor.java
+2
-1
broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
...pache/rocketmq/broker/processor/SendMessageProcessor.java
+180
-96
broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageService.java
...ketmq/broker/transaction/TransactionalMessageService.java
+9
-0
broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java
.../broker/transaction/queue/TransactionalMessageBridge.java
+5
-0
broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java
...er/transaction/queue/TransactionalMessageServiceImpl.java
+6
-0
broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
...e/rocketmq/broker/processor/SendMessageProcessorTest.java
+25
-12
broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java
...ker/transaction/queue/TransactionalMessageBridgeTest.java
+9
-0
broker/src/test/java/org/apache/rocketmq/broker/util/TransactionalMessageServiceImpl.java
...rocketmq/broker/util/TransactionalMessageServiceImpl.java
+7
-0
client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java
.../apache/rocketmq/client/impl/ClientRemotingProcessor.java
+2
-1
namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
...e/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+2
-1
remoting/src/main/java/org/apache/rocketmq/remoting/netty/AsyncNettyRequestProcessor.java
...e/rocketmq/remoting/netty/AsyncNettyRequestProcessor.java
+29
-0
remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
...apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+27
-16
remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java
...apache/rocketmq/remoting/netty/NettyRequestProcessor.java
+1
-0
remoting/src/main/java/org/apache/rocketmq/remoting/netty/RemotingResponseCallback.java
...che/rocketmq/remoting/netty/RemotingResponseCallback.java
+24
-0
remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
...java/org/apache/rocketmq/remoting/RemotingServerTest.java
+2
-7
store/src/main/java/org/apache/rocketmq/store/CommitLog.java
store/src/main/java/org/apache/rocketmq/store/CommitLog.java
+306
-18
store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
...n/java/org/apache/rocketmq/store/DefaultMessageStore.java
+114
-52
store/src/main/java/org/apache/rocketmq/store/MessageStore.java
...src/main/java/org/apache/rocketmq/store/MessageStore.java
+22
-0
store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java
...a/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java
+11
-0
store/src/test/java/org/apache/rocketmq/store/HATest.java
store/src/test/java/org/apache/rocketmq/store/HATest.java
+37
-2
test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQTransactionalProducer.java
...he/rocketmq/test/client/rmq/RMQTransactionalProducer.java
+106
-0
test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java
...src/test/java/org/apache/rocketmq/test/base/BaseConf.java
+11
-0
test/src/test/java/org/apache/rocketmq/test/client/producer/transaction/TransactionalMsgIT.java
.../test/client/producer/transaction/TransactionalMsgIT.java
+116
-0
未找到文件。
broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
浏览文件 @
64e4ca72
...
...
@@ -20,7 +20,9 @@ package org.apache.rocketmq.broker.plugin;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
org.apache.rocketmq.common.message.MessageExt
;
import
org.apache.rocketmq.common.message.MessageExtBatch
;
import
org.apache.rocketmq.store.CommitLogDispatcher
;
import
org.apache.rocketmq.store.ConsumeQueue
;
import
org.apache.rocketmq.store.GetMessageResult
;
...
...
@@ -86,6 +88,16 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
return
next
.
putMessage
(
msg
);
}
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessage
(
MessageExtBrokerInner
msg
)
{
return
next
.
asyncPutMessage
(
msg
);
}
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessages
(
MessageExtBatch
messageExtBatch
)
{
return
next
.
asyncPutMessages
(
messageExtBatch
);
}
@Override
public
GetMessageResult
getMessage
(
String
group
,
String
topic
,
int
queueId
,
long
offset
,
int
maxMsgNums
,
final
MessageFilter
messageFilter
)
{
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -49,11 +49,12 @@ import org.apache.rocketmq.logging.InternalLogger;
import
org.apache.rocketmq.logging.InternalLoggerFactory
;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.apache.rocketmq.store.MessageExtBrokerInner
;
public
abstract
class
AbstractSendMessageProcessor
implements
NettyRequestProcessor
{
public
abstract
class
AbstractSendMessageProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
protected
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
protected
final
static
int
DLQ_NUMS_PER_GROUP
=
1
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -122,6 +122,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.exception.RemotingTimeoutException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.LanguageCode
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
...
...
@@ -136,7 +137,7 @@ import org.apache.rocketmq.store.PutMessageResult;
import
org.apache.rocketmq.store.PutMessageStatus
;
import
org.apache.rocketmq.store.SelectMappedBufferResult
;
public
class
AdminBrokerProcessor
implements
NettyRequestProcessor
{
public
class
AdminBrokerProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -40,9 +40,10 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
class
ClientManageProcessor
implements
NettyRequestProcessor
{
public
class
ClientManageProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -34,10 +34,11 @@ import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHe
import
org.apache.rocketmq.logging.InternalLoggerFactory
;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
class
ConsumerManageProcessor
implements
NettyRequestProcessor
{
public
class
ConsumerManageProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -32,6 +32,7 @@ import org.apache.rocketmq.logging.InternalLogger;
import
org.apache.rocketmq.logging.InternalLoggerFactory
;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.apache.rocketmq.store.MessageExtBrokerInner
;
...
...
@@ -41,7 +42,7 @@ import org.apache.rocketmq.store.config.BrokerRole;
/**
* EndTransaction processor: process commit and rollback message
*/
public
class
EndTransactionProcessor
implements
NettyRequestProcessor
{
public
class
EndTransactionProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
LOGGER
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
TRANSACTION_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -21,10 +21,11 @@ import org.apache.rocketmq.broker.BrokerController;
import
org.apache.rocketmq.common.constant.LoggerName
;
import
org.apache.rocketmq.logging.InternalLogger
;
import
org.apache.rocketmq.logging.InternalLoggerFactory
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
class
ForwardRequestProcessor
implements
NettyRequestProcessor
{
public
class
ForwardRequestProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -57,6 +57,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.common.RemotingUtil
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.RequestTask
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
...
...
@@ -67,7 +68,7 @@ import org.apache.rocketmq.store.PutMessageResult;
import
org.apache.rocketmq.store.config.BrokerRole
;
import
org.apache.rocketmq.store.stats.BrokerStatsManager
;
public
class
PullMessageProcessor
implements
NettyRequestProcessor
{
public
class
PullMessageProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
private
List
<
ConsumeMessageHook
>
consumeMessageHookList
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -33,12 +33,13 @@ import org.apache.rocketmq.common.protocol.header.QueryMessageRequestHeader;
import
org.apache.rocketmq.common.protocol.header.QueryMessageResponseHeader
;
import
org.apache.rocketmq.common.protocol.header.ViewMessageRequestHeader
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.apache.rocketmq.store.QueryMessageResult
;
import
org.apache.rocketmq.store.SelectMappedBufferResult
;
public
class
QueryMessageProcessor
implements
NettyRequestProcessor
{
public
class
QueryMessageProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
BROKER_LOGGER_NAME
);
private
final
BrokerController
brokerController
;
...
...
broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -19,6 +19,8 @@ package org.apache.rocketmq.broker.processor;
import
java.net.SocketAddress
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ExecutionException
;
import
io.netty.channel.ChannelHandlerContext
;
import
org.apache.rocketmq.broker.BrokerController
;
...
...
@@ -48,6 +50,7 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag;
import
org.apache.rocketmq.common.sysflag.TopicSysFlag
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.RemotingResponseCallback
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.apache.rocketmq.store.MessageExtBrokerInner
;
import
org.apache.rocketmq.store.PutMessageResult
;
...
...
@@ -65,28 +68,38 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
@Override
public
RemotingCommand
processRequest
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
)
throws
RemotingCommandException
{
SendMessageContext
mqtraceContext
;
RemotingCommand
response
=
null
;
try
{
response
=
asyncProcessRequest
(
ctx
,
request
).
get
();
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
log
.
error
(
"process SendMessage error, request : "
+
request
.
toString
(),
e
);
}
return
response
;
}
@Override
public
void
asyncProcessRequest
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
,
RemotingResponseCallback
responseCallback
)
throws
Exception
{
asyncProcessRequest
(
ctx
,
request
).
thenAccept
(
responseCallback:
:
callback
);
}
public
CompletableFuture
<
RemotingCommand
>
asyncProcessRequest
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
)
throws
RemotingCommandException
{
final
SendMessageContext
mqtraceContext
;
switch
(
request
.
getCode
())
{
case
RequestCode
.
CONSUMER_SEND_MSG_BACK
:
return
this
.
c
onsumerSendMsgBack
(
ctx
,
request
);
return
this
.
asyncC
onsumerSendMsgBack
(
ctx
,
request
);
default
:
SendMessageRequestHeader
requestHeader
=
parseRequestHeader
(
request
);
if
(
requestHeader
==
null
)
{
return
null
;
return
CompletableFuture
.
completedFuture
(
null
)
;
}
mqtraceContext
=
buildMsgContext
(
ctx
,
requestHeader
);
this
.
executeSendMessageHookBefore
(
ctx
,
request
,
mqtraceContext
);
RemotingCommand
response
;
if
(
requestHeader
.
isBatch
())
{
re
sponse
=
this
.
s
endBatchMessage
(
ctx
,
request
,
mqtraceContext
,
requestHeader
);
re
turn
this
.
asyncS
endBatchMessage
(
ctx
,
request
,
mqtraceContext
,
requestHeader
);
}
else
{
re
sponse
=
this
.
s
endMessage
(
ctx
,
request
,
mqtraceContext
,
requestHeader
);
re
turn
this
.
asyncS
endMessage
(
ctx
,
request
,
mqtraceContext
,
requestHeader
);
}
this
.
executeSendMessageHookAfter
(
response
,
mqtraceContext
);
return
response
;
}
}
...
...
@@ -96,50 +109,38 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
this
.
brokerController
.
getMessageStore
().
isTransientStorePoolDeficient
();
}
private
RemotingCommand
consumerSendMsgBack
(
final
ChannelHandlerContext
ctx
,
final
RemotingCommand
request
)
throws
RemotingCommandException
{
private
CompletableFuture
<
RemotingCommand
>
asyncConsumerSendMsgBack
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
)
throws
RemotingCommandException
{
final
RemotingCommand
response
=
RemotingCommand
.
createResponseCommand
(
null
);
final
ConsumerSendMsgBackRequestHeader
requestHeader
=
(
ConsumerSendMsgBackRequestHeader
)
request
.
decodeCommandCustomHeader
(
ConsumerSendMsgBackRequestHeader
.
class
);
String
namespace
=
NamespaceUtil
.
getNamespaceFromResource
(
requestHeader
.
getGroup
());
if
(
this
.
hasConsumeMessageHook
()
&&
!
UtilAll
.
isBlank
(
requestHeader
.
getOriginMsgId
()))
{
ConsumeMessageContext
context
=
new
ConsumeMessageContext
();
context
.
setNamespace
(
namespace
);
context
.
setConsumerGroup
(
requestHeader
.
getGroup
());
context
.
setTopic
(
requestHeader
.
getOriginTopic
());
context
.
setCommercialRcvStats
(
BrokerStatsManager
.
StatsType
.
SEND_BACK
);
context
.
setCommercialRcvTimes
(
1
);
context
.
setCommercialOwner
(
request
.
getExtFields
().
get
(
BrokerStatsManager
.
COMMERCIAL_OWNER
));
ConsumeMessageContext
context
=
buildConsumeMessageContext
(
namespace
,
requestHeader
,
request
);
this
.
executeConsumeMessageHookAfter
(
context
);
}
SubscriptionGroupConfig
subscriptionGroupConfig
=
this
.
brokerController
.
getSubscriptionGroupManager
().
findSubscriptionGroupConfig
(
requestHeader
.
getGroup
());
if
(
null
==
subscriptionGroupConfig
)
{
response
.
setCode
(
ResponseCode
.
SUBSCRIPTION_GROUP_NOT_EXIST
);
response
.
setRemark
(
"subscription group not exist, "
+
requestHeader
.
getGroup
()
+
" "
+
FAQUrl
.
suggestTodo
(
FAQUrl
.
SUBSCRIPTION_GROUP_NOT_EXIST
));
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
if
(!
PermName
.
isWriteable
(
this
.
brokerController
.
getBrokerConfig
().
getBrokerPermission
()))
{
response
.
setCode
(
ResponseCode
.
NO_PERMISSION
);
response
.
setRemark
(
"the broker["
+
this
.
brokerController
.
getBrokerConfig
().
getBrokerIP1
()
+
"] sending message is forbidden"
);
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
if
(
subscriptionGroupConfig
.
getRetryQueueNums
()
<=
0
)
{
response
.
setCode
(
ResponseCode
.
SUCCESS
);
response
.
setRemark
(
null
);
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
String
newTopic
=
MixAll
.
getRetryTopic
(
requestHeader
.
getGroup
());
int
queueIdInt
=
Math
.
abs
(
this
.
random
.
nextInt
()
%
99999999
)
%
subscriptionGroupConfig
.
getRetryQueueNums
();
int
topicSysFlag
=
0
;
if
(
requestHeader
.
isUnitMode
())
{
topicSysFlag
=
TopicSysFlag
.
buildSysFlag
(
false
,
true
);
...
...
@@ -152,20 +153,19 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
if
(
null
==
topicConfig
)
{
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
"topic["
+
newTopic
+
"] not exist"
);
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
if
(!
PermName
.
isWriteable
(
topicConfig
.
getPerm
()))
{
response
.
setCode
(
ResponseCode
.
NO_PERMISSION
);
response
.
setRemark
(
String
.
format
(
"the topic[%s] sending message is forbidden"
,
newTopic
));
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
MessageExt
msgExt
=
this
.
brokerController
.
getMessageStore
().
lookMessageByOffset
(
requestHeader
.
getOffset
());
if
(
null
==
msgExt
)
{
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
"look message by offset failed, "
+
requestHeader
.
getOffset
());
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
final
String
retryTopic
=
msgExt
.
getProperty
(
MessageConst
.
PROPERTY_RETRY_TOPIC
);
...
...
@@ -188,18 +188,16 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
topicConfig
=
this
.
brokerController
.
getTopicConfigManager
().
createTopicInSendMessageBackMethod
(
newTopic
,
DLQ_NUMS_PER_GROUP
,
PermName
.
PERM_WRITE
,
0
);
PermName
.
PERM_WRITE
,
0
);
if
(
null
==
topicConfig
)
{
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
"topic["
+
newTopic
+
"] not exist"
);
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
}
else
{
if
(
0
==
delayLevel
)
{
delayLevel
=
3
+
msgExt
.
getReconsumeTimes
();
}
msgExt
.
setDelayTimeLevel
(
delayLevel
);
}
...
...
@@ -215,40 +213,103 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
msgInner
.
setSysFlag
(
msgExt
.
getSysFlag
());
msgInner
.
setBornTimestamp
(
msgExt
.
getBornTimestamp
());
msgInner
.
setBornHost
(
msgExt
.
getBornHost
());
msgInner
.
setStoreHost
(
this
.
getStoreHost
());
msgInner
.
setStoreHost
(
msgExt
.
getStoreHost
());
msgInner
.
setReconsumeTimes
(
msgExt
.
getReconsumeTimes
()
+
1
);
String
originMsgId
=
MessageAccessor
.
getOriginMessageId
(
msgExt
);
MessageAccessor
.
setOriginMessageId
(
msgInner
,
UtilAll
.
isBlank
(
originMsgId
)
?
msgExt
.
getMsgId
()
:
originMsgId
);
PutMessageResult
putMessageResult
=
this
.
brokerController
.
getMessageStore
().
putMessage
(
msgInner
);
if
(
putMessageResult
!=
null
)
{
switch
(
putMessageResult
.
getPutMessageStatus
())
{
CompletableFuture
<
PutMessageResult
>
putMessageResult
=
this
.
brokerController
.
getMessageStore
().
asyncPutMessage
(
msgInner
);
return
putMessageResult
.
thenApply
((
r
)
->
{
if
(
r
!=
null
)
{
switch
(
r
.
getPutMessageStatus
())
{
case
PUT_OK:
String
backTopic
=
msgExt
.
getTopic
();
String
correctTopic
=
msgExt
.
getProperty
(
MessageConst
.
PROPERTY_RETRY_TOPIC
);
if
(
correctTopic
!=
null
)
{
backTopic
=
correctTopic
;
}
this
.
brokerController
.
getBrokerStatsManager
().
incSendBackNums
(
requestHeader
.
getGroup
(),
backTopic
);
response
.
setCode
(
ResponseCode
.
SUCCESS
);
response
.
setRemark
(
null
);
return
response
;
default
:
break
;
}
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
putMessageResult
.
getPutMessageStatus
().
name
());
response
.
setRemark
(
r
.
getPutMessageStatus
().
name
());
return
response
;
}
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
"putMessageResult is null"
);
return
response
;
});
}
private
CompletableFuture
<
RemotingCommand
>
asyncSendMessage
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
,
SendMessageContext
mqtraceContext
,
SendMessageRequestHeader
requestHeader
)
{
final
RemotingCommand
response
=
preSend
(
ctx
,
request
,
requestHeader
);
final
SendMessageResponseHeader
responseHeader
=
(
SendMessageResponseHeader
)
response
.
readCustomHeader
();
if
(
response
.
getCode
()
!=
-
1
)
{
return
CompletableFuture
.
completedFuture
(
response
);
}
final
byte
[]
body
=
request
.
getBody
();
int
queueIdInt
=
requestHeader
.
getQueueId
();
TopicConfig
topicConfig
=
this
.
brokerController
.
getTopicConfigManager
().
selectTopicConfig
(
requestHeader
.
getTopic
());
if
(
queueIdInt
<
0
)
{
queueIdInt
=
randomQueueId
(
topicConfig
.
getWriteQueueNums
());
}
MessageExtBrokerInner
msgInner
=
new
MessageExtBrokerInner
();
msgInner
.
setTopic
(
requestHeader
.
getTopic
());
msgInner
.
setQueueId
(
queueIdInt
);
if
(!
handleRetryAndDLQ
(
requestHeader
,
response
,
request
,
msgInner
,
topicConfig
))
{
return
CompletableFuture
.
completedFuture
(
response
);
}
msgInner
.
setBody
(
body
);
msgInner
.
setFlag
(
requestHeader
.
getFlag
());
MessageAccessor
.
setProperties
(
msgInner
,
MessageDecoder
.
string2messageProperties
(
requestHeader
.
getProperties
()));
msgInner
.
setPropertiesString
(
requestHeader
.
getProperties
());
msgInner
.
setBornTimestamp
(
requestHeader
.
getBornTimestamp
());
msgInner
.
setBornHost
(
ctx
.
channel
().
remoteAddress
());
msgInner
.
setStoreHost
(
this
.
getStoreHost
());
msgInner
.
setReconsumeTimes
(
requestHeader
.
getReconsumeTimes
()
==
null
?
0
:
requestHeader
.
getReconsumeTimes
());
CompletableFuture
<
PutMessageResult
>
putMessageResult
=
null
;
Map
<
String
,
String
>
origProps
=
MessageDecoder
.
string2messageProperties
(
requestHeader
.
getProperties
());
String
transFlag
=
origProps
.
get
(
MessageConst
.
PROPERTY_TRANSACTION_PREPARED
);
if
(
transFlag
!=
null
&&
Boolean
.
parseBoolean
(
transFlag
))
{
if
(
this
.
brokerController
.
getBrokerConfig
().
isRejectTransactionMessage
())
{
response
.
setCode
(
ResponseCode
.
NO_PERMISSION
);
response
.
setRemark
(
"the broker["
+
this
.
brokerController
.
getBrokerConfig
().
getBrokerIP1
()
+
"] sending transaction message is forbidden"
);
return
CompletableFuture
.
completedFuture
(
response
);
}
putMessageResult
=
this
.
brokerController
.
getTransactionalMessageService
().
asyncPrepareMessage
(
msgInner
);
}
else
{
putMessageResult
=
this
.
brokerController
.
getMessageStore
().
asyncPutMessage
(
msgInner
);
}
return
handlePutMessageResultFuture
(
putMessageResult
,
response
,
request
,
msgInner
,
responseHeader
,
mqtraceContext
,
ctx
,
queueIdInt
);
}
private
CompletableFuture
<
RemotingCommand
>
handlePutMessageResultFuture
(
CompletableFuture
<
PutMessageResult
>
putMessageResult
,
RemotingCommand
response
,
RemotingCommand
request
,
MessageExt
msgInner
,
SendMessageResponseHeader
responseHeader
,
SendMessageContext
sendMessageContext
,
ChannelHandlerContext
ctx
,
int
queueIdInt
)
{
return
putMessageResult
.
thenApply
((
r
)
->
handlePutMessageResult
(
r
,
response
,
request
,
msgInner
,
responseHeader
,
sendMessageContext
,
ctx
,
queueIdInt
)
);
}
private
boolean
handleRetryAndDLQ
(
SendMessageRequestHeader
requestHeader
,
RemotingCommand
response
,
...
...
@@ -476,52 +537,29 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
return
response
;
}
private
RemotingCommand
sendBatchMessage
(
final
ChannelHandlerContext
ctx
,
final
RemotingCommand
request
,
final
SendMessageContext
sendMessageContext
,
final
SendMessageRequestHeader
requestHeader
)
throws
RemotingCommandException
{
final
RemotingCommand
response
=
RemotingCommand
.
createResponseCommand
(
SendMessageResponseHeader
.
class
);
private
CompletableFuture
<
RemotingCommand
>
asyncSendBatchMessage
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
,
SendMessageContext
mqtraceContext
,
SendMessageRequestHeader
requestHeader
)
{
final
RemotingCommand
response
=
preSend
(
ctx
,
request
,
requestHeader
);
final
SendMessageResponseHeader
responseHeader
=
(
SendMessageResponseHeader
)
response
.
readCustomHeader
();
response
.
setOpaque
(
request
.
getOpaque
());
response
.
addExtField
(
MessageConst
.
PROPERTY_MSG_REGION
,
this
.
brokerController
.
getBrokerConfig
().
getRegionId
());
response
.
addExtField
(
MessageConst
.
PROPERTY_TRACE_SWITCH
,
String
.
valueOf
(
this
.
brokerController
.
getBrokerConfig
().
isTraceOn
()));
log
.
debug
(
"Receive SendMessage request command {}"
,
request
);
final
long
startTimstamp
=
this
.
brokerController
.
getBrokerConfig
().
getStartAcceptSendRequestTimeStamp
();
if
(
this
.
brokerController
.
getMessageStore
().
now
()
<
startTimstamp
)
{
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
String
.
format
(
"broker unable to service, until %s"
,
UtilAll
.
timeMillisToHumanString2
(
startTimstamp
)));
return
response
;
}
response
.
setCode
(-
1
);
super
.
msgCheck
(
ctx
,
requestHeader
,
response
);
if
(
response
.
getCode
()
!=
-
1
)
{
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
int
queueIdInt
=
requestHeader
.
getQueueId
();
TopicConfig
topicConfig
=
this
.
brokerController
.
getTopicConfigManager
().
selectTopicConfig
(
requestHeader
.
getTopic
());
if
(
queueIdInt
<
0
)
{
queueIdInt
=
Math
.
abs
(
this
.
random
.
nextInt
()
%
99999999
)
%
topicConfig
.
getWriteQueueNums
(
);
queueIdInt
=
randomQueueId
(
topicConfig
.
getWriteQueueNums
()
);
}
if
(
requestHeader
.
getTopic
().
length
()
>
Byte
.
MAX_VALUE
)
{
response
.
setCode
(
ResponseCode
.
MESSAGE_ILLEGAL
);
response
.
setRemark
(
"message topic length too long "
+
requestHeader
.
getTopic
().
length
());
return
response
;
return
CompletableFuture
.
completedFuture
(
response
)
;
}
if
(
requestHeader
.
getTopic
()
!=
null
&&
requestHeader
.
getTopic
().
startsWith
(
MixAll
.
RETRY_GROUP_TOPIC_PREFIX
))
{
response
.
setCode
(
ResponseCode
.
MESSAGE_ILLEGAL
);
response
.
setRemark
(
"batch request does not support retry group "
+
requestHeader
.
getTopic
());
return
response
;
}
MessageExtBatch
messageExtBatch
=
new
MessageExtBatch
();
messageExtBatch
.
setTopic
(
requestHeader
.
getTopic
());
messageExtBatch
.
setQueueId
(
queueIdInt
);
...
...
@@ -542,11 +580,12 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
String
clusterName
=
this
.
brokerController
.
getBrokerConfig
().
getBrokerClusterName
();
MessageAccessor
.
putProperty
(
messageExtBatch
,
MessageConst
.
PROPERTY_CLUSTER
,
clusterName
);
PutMessageResult
putMessageResult
=
this
.
brokerController
.
getMessageStore
().
putMessages
(
messageExtBatch
);
return
handlePutMessageResult
(
putMessageResult
,
response
,
request
,
messageExtBatch
,
responseHeader
,
sendMessageContext
,
ctx
,
queueIdInt
);
CompletableFuture
<
PutMessageResult
>
putMessageResult
=
this
.
brokerController
.
getMessageStore
().
asyncPutMessages
(
messageExtBatch
);
return
handlePutMessageResultFuture
(
putMessageResult
,
response
,
request
,
messageExtBatch
,
responseHeader
,
mqtraceContext
,
ctx
,
queueIdInt
);
}
public
boolean
hasConsumeMessageHook
()
{
return
consumeMessageHookList
!=
null
&&
!
this
.
consumeMessageHookList
.
isEmpty
();
}
...
...
@@ -585,4 +624,49 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
public
void
registerConsumeMessageHook
(
List
<
ConsumeMessageHook
>
consumeMessageHookList
)
{
this
.
consumeMessageHookList
=
consumeMessageHookList
;
}
static
private
ConsumeMessageContext
buildConsumeMessageContext
(
String
namespace
,
ConsumerSendMsgBackRequestHeader
requestHeader
,
RemotingCommand
request
)
{
ConsumeMessageContext
context
=
new
ConsumeMessageContext
();
context
.
setNamespace
(
namespace
);
context
.
setConsumerGroup
(
requestHeader
.
getGroup
());
context
.
setTopic
(
requestHeader
.
getOriginTopic
());
context
.
setCommercialRcvStats
(
BrokerStatsManager
.
StatsType
.
SEND_BACK
);
context
.
setCommercialRcvTimes
(
1
);
context
.
setCommercialOwner
(
request
.
getExtFields
().
get
(
BrokerStatsManager
.
COMMERCIAL_OWNER
));
return
context
;
}
private
int
randomQueueId
(
int
writeQueueNums
)
{
return
(
this
.
random
.
nextInt
()
%
99999999
)
%
writeQueueNums
;
}
private
RemotingCommand
preSend
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
,
SendMessageRequestHeader
requestHeader
)
{
final
RemotingCommand
response
=
RemotingCommand
.
createResponseCommand
(
SendMessageResponseHeader
.
class
);
response
.
setOpaque
(
request
.
getOpaque
());
response
.
addExtField
(
MessageConst
.
PROPERTY_MSG_REGION
,
this
.
brokerController
.
getBrokerConfig
().
getRegionId
());
response
.
addExtField
(
MessageConst
.
PROPERTY_TRACE_SWITCH
,
String
.
valueOf
(
this
.
brokerController
.
getBrokerConfig
().
isTraceOn
()));
log
.
debug
(
"Receive SendMessage request command {}"
,
request
);
final
long
startTimestamp
=
this
.
brokerController
.
getBrokerConfig
().
getStartAcceptSendRequestTimeStamp
();
if
(
this
.
brokerController
.
getMessageStore
().
now
()
<
startTimestamp
)
{
response
.
setCode
(
ResponseCode
.
SYSTEM_ERROR
);
response
.
setRemark
(
String
.
format
(
"broker unable to service, until %s"
,
UtilAll
.
timeMillisToHumanString2
(
startTimestamp
)));
return
response
;
}
response
.
setCode
(-
1
);
super
.
msgCheck
(
ctx
,
requestHeader
,
response
);
if
(
response
.
getCode
()
!=
-
1
)
{
return
response
;
}
return
response
;
}
}
broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageService.java
浏览文件 @
64e4ca72
...
...
@@ -20,6 +20,7 @@ import org.apache.rocketmq.common.message.MessageExt;
import
org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader
;
import
org.apache.rocketmq.store.MessageExtBrokerInner
;
import
org.apache.rocketmq.store.PutMessageResult
;
import
java.util.concurrent.CompletableFuture
;
public
interface
TransactionalMessageService
{
...
...
@@ -31,6 +32,14 @@ public interface TransactionalMessageService {
*/
PutMessageResult
prepareMessage
(
MessageExtBrokerInner
messageInner
);
/**
* Process prepare message in async manner, we should put this message to storage service
*
* @param messageInner Prepare(Half) message.
* @return CompletableFuture of put result, will be completed at put success(flush and replica done)
*/
CompletableFuture
<
PutMessageResult
>
asyncPrepareMessage
(
MessageExtBrokerInner
messageInner
);
/**
* Delete prepare message when this message has been committed or rolled back.
*
...
...
broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java
浏览文件 @
64e4ca72
...
...
@@ -47,6 +47,7 @@ import java.util.ArrayList;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ConcurrentHashMap
;
public
class
TransactionalMessageBridge
{
...
...
@@ -195,6 +196,10 @@ public class TransactionalMessageBridge {
return
store
.
putMessage
(
parseHalfMessageInner
(
messageInner
));
}
public
CompletableFuture
<
PutMessageResult
>
asyncPutHalfMessage
(
MessageExtBrokerInner
messageInner
)
{
return
store
.
asyncPutMessage
(
parseHalfMessageInner
(
messageInner
));
}
private
MessageExtBrokerInner
parseHalfMessageInner
(
MessageExtBrokerInner
msgInner
)
{
MessageAccessor
.
putProperty
(
msgInner
,
MessageConst
.
PROPERTY_REAL_TOPIC
,
msgInner
.
getTopic
());
MessageAccessor
.
putProperty
(
msgInner
,
MessageConst
.
PROPERTY_REAL_QUEUE_ID
,
...
...
broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java
浏览文件 @
64e4ca72
...
...
@@ -40,6 +40,7 @@ import java.util.Date;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ConcurrentHashMap
;
public
class
TransactionalMessageServiceImpl
implements
TransactionalMessageService
{
...
...
@@ -59,6 +60,11 @@ public class TransactionalMessageServiceImpl implements TransactionalMessageServ
private
ConcurrentHashMap
<
MessageQueue
,
MessageQueue
>
opQueueMap
=
new
ConcurrentHashMap
<>();
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPrepareMessage
(
MessageExtBrokerInner
messageInner
)
{
return
transactionalMessageBridge
.
asyncPutHalfMessage
(
messageInner
);
}
@Override
public
PutMessageResult
prepareMessage
(
MessageExtBrokerInner
messageInner
)
{
return
transactionalMessageBridge
.
putHalfMessage
(
messageInner
);
...
...
broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
浏览文件 @
64e4ca72
...
...
@@ -56,6 +56,7 @@ import java.net.InetSocketAddress;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CompletableFuture
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
...
...
@@ -93,13 +94,15 @@ public class SendMessageProcessorTest {
@Test
public
void
testProcessRequest
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
))));
assertPutResult
(
ResponseCode
.
SUCCESS
);
}
@Test
public
void
testProcessRequest_WithHook
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
))));
List
<
SendMessageHook
>
sendMessageHookList
=
new
ArrayList
<>();
final
SendMessageContext
[]
sendMessageContext
=
new
SendMessageContext
[
1
];
SendMessageHook
sendMessageHook
=
new
SendMessageHook
()
{
...
...
@@ -129,55 +132,64 @@ public class SendMessageProcessorTest {
@Test
public
void
testProcessRequest_FlushTimeOut
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
FLUSH_DISK_TIMEOUT
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
FLUSH_DISK_TIMEOUT
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
FLUSH_DISK_TIMEOUT
);
}
@Test
public
void
testProcessRequest_MessageIllegal
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
MESSAGE_ILLEGAL
);
}
@Test
public
void
testProcessRequest_CreateMappedFileFailed
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
SYSTEM_ERROR
);
}
@Test
public
void
testProcessRequest_FlushSlaveTimeout
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
FLUSH_SLAVE_TIMEOUT
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
FLUSH_SLAVE_TIMEOUT
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
FLUSH_SLAVE_TIMEOUT
);
}
@Test
public
void
testProcessRequest_PageCacheBusy
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
OS_PAGECACHE_BUSY
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
OS_PAGECACHE_BUSY
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
SYSTEM_ERROR
);
}
@Test
public
void
testProcessRequest_PropertiesTooLong
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
PROPERTIES_SIZE_EXCEEDED
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PROPERTIES_SIZE_EXCEEDED
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
MESSAGE_ILLEGAL
);
}
@Test
public
void
testProcessRequest_ServiceNotAvailable
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
SERVICE_NOT_AVAILABLE
);
}
@Test
public
void
testProcessRequest_SlaveNotAvailable
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
SLAVE_NOT_AVAILABLE
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
SLAVE_NOT_AVAILABLE
,
new
AppendMessageResult
(
AppendMessageStatus
.
UNKNOWN_ERROR
))));
assertPutResult
(
ResponseCode
.
SLAVE_NOT_AVAILABLE
);
}
@Test
public
void
testProcessRequest_WithMsgBack
()
throws
RemotingCommandException
{
when
(
messageStore
.
putMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
)));
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
))));
final
RemotingCommand
request
=
createSendMsgBackCommand
(
RequestCode
.
CONSUMER_SEND_MSG_BACK
);
sendMessageProcessor
=
new
SendMessageProcessor
(
brokerController
);
...
...
@@ -189,7 +201,8 @@ public class SendMessageProcessorTest {
@Test
public
void
testProcessRequest_Transaction
()
throws
RemotingCommandException
{
brokerController
.
setTransactionalMessageService
(
transactionMsgService
);
when
(
brokerController
.
getTransactionalMessageService
().
prepareMessage
(
any
(
MessageExtBrokerInner
.
class
))).
thenReturn
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
)));
when
(
brokerController
.
getTransactionalMessageService
().
asyncPrepareMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
))));
RemotingCommand
request
=
createSendTransactionMsgCommand
(
RequestCode
.
SEND_MESSAGE
);
final
RemotingCommand
[]
response
=
new
RemotingCommand
[
1
];
doAnswer
(
new
Answer
()
{
...
...
broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java
浏览文件 @
64e4ca72
...
...
@@ -47,6 +47,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
...
...
@@ -87,6 +88,14 @@ public class TransactionalMessageBridgeTest {
assertThat
(
result
.
getPutMessageStatus
()).
isEqualTo
(
PutMessageStatus
.
PUT_OK
);
}
@Test
public
void
testAsyncPutHalfMessage
()
throws
Exception
{
when
(
messageStore
.
asyncPutMessage
(
any
(
MessageExtBrokerInner
.
class
)))
.
thenReturn
(
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
new
AppendMessageResult
(
AppendMessageStatus
.
PUT_OK
))));
CompletableFuture
<
PutMessageResult
>
result
=
transactionBridge
.
asyncPutHalfMessage
(
createMessageBrokerInner
());
assertThat
(
result
.
get
().
getPutMessageStatus
()).
isEqualTo
(
PutMessageStatus
.
PUT_OK
);
}
@Test
public
void
testFetchMessageQueues
()
{
Set
<
MessageQueue
>
messageQueues
=
transactionBridge
.
fetchMessageQueues
(
MixAll
.
RMQ_SYS_TRANS_HALF_TOPIC
);
...
...
broker/src/test/java/org/apache/rocketmq/broker/util/TransactionalMessageServiceImpl.java
浏览文件 @
64e4ca72
...
...
@@ -27,6 +27,8 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
import
org.apache.rocketmq.store.MessageExtBrokerInner
;
import
org.apache.rocketmq.store.PutMessageResult
;
import
java.util.concurrent.CompletableFuture
;
public
class
TransactionalMessageServiceImpl
implements
TransactionalMessageService
{
private
static
final
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
TRANSACTION_LOGGER_NAME
);
...
...
@@ -35,6 +37,11 @@ public class TransactionalMessageServiceImpl implements TransactionalMessageServ
return
null
;
}
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPrepareMessage
(
MessageExtBrokerInner
messageInner
)
{
return
null
;
}
@Override
public
boolean
deletePrepareMessage
(
MessageExt
messageExt
)
{
return
false
;
...
...
client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -52,10 +52,11 @@ import org.apache.rocketmq.logging.InternalLogger;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.common.RemotingUtil
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
class
ClientRemotingProcessor
implements
NettyRequestProcessor
{
public
class
ClientRemotingProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
final
InternalLogger
log
=
ClientLogger
.
getLog
();
private
final
MQClientInstance
mqClientFactory
;
...
...
namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -54,10 +54,11 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import
org.apache.rocketmq.namesrv.NamesrvController
;
import
org.apache.rocketmq.remoting.common.RemotingHelper
;
import
org.apache.rocketmq.remoting.exception.RemotingCommandException
;
import
org.apache.rocketmq.remoting.netty.AsyncNettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
class
DefaultRequestProcessor
implements
NettyRequestProcessor
{
public
class
DefaultRequestProcessor
extends
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
private
static
InternalLogger
log
=
InternalLoggerFactory
.
getLogger
(
LoggerName
.
NAMESRV_LOGGER_NAME
);
protected
final
NamesrvController
namesrvController
;
...
...
remoting/src/main/java/org/apache/rocketmq/remoting/netty/AsyncNettyRequestProcessor.java
0 → 100644
浏览文件 @
64e4ca72
/*
* 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.
*/
package
org.apache.rocketmq.remoting.netty
;
import
io.netty.channel.ChannelHandlerContext
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
abstract
class
AsyncNettyRequestProcessor
implements
NettyRequestProcessor
{
public
void
asyncProcessRequest
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
,
RemotingResponseCallback
responseCallback
)
throws
Exception
{
RemotingCommand
response
=
processRequest
(
ctx
,
request
);
responseCallback
.
callback
(
response
);
}
}
remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
浏览文件 @
64e4ca72
...
...
@@ -36,6 +36,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import
java.util.concurrent.RejectedExecutionException
;
import
java.util.concurrent.Semaphore
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.rocketmq.logging.InternalLogger
;
import
org.apache.rocketmq.logging.InternalLoggerFactory
;
import
org.apache.rocketmq.remoting.ChannelEventListener
;
...
...
@@ -102,7 +103,6 @@ public abstract class NettyRemotingAbstract {
protected
List
<
RPCHook
>
rpcHooks
=
new
ArrayList
<
RPCHook
>();
static
{
NettyLogger
.
initNettyLogger
();
}
...
...
@@ -200,9 +200,10 @@ public abstract class NettyRemotingAbstract {
public
void
run
()
{
try
{
doBeforeRpcHooks
(
RemotingHelper
.
parseChannelRemoteAddr
(
ctx
.
channel
()),
cmd
);
final
RemotingCommand
response
=
pair
.
getObject1
().
processRequest
(
ctx
,
cmd
);
final
RemotingResponseCallback
callback
=
new
RemotingResponseCallback
()
{
@Override
public
void
callback
(
RemotingCommand
response
)
{
doAfterRpcHooks
(
RemotingHelper
.
parseChannelRemoteAddr
(
ctx
.
channel
()),
cmd
,
response
);
if
(!
cmd
.
isOnewayRPC
())
{
if
(
response
!=
null
)
{
response
.
setOpaque
(
opaque
);
...
...
@@ -215,9 +216,19 @@ public abstract class NettyRemotingAbstract {
log
.
error
(
response
.
toString
());
}
}
else
{
}
}
}
};
if
(
pair
.
getObject1
()
instanceof
AsyncNettyRequestProcessor
)
{
AsyncNettyRequestProcessor
processor
=
(
AsyncNettyRequestProcessor
)
pair
.
getObject1
();
processor
.
asyncProcessRequest
(
ctx
,
cmd
,
callback
);
}
else
{
NettyRequestProcessor
processor
=
pair
.
getObject1
();
RemotingCommand
response
=
processor
.
processRequest
(
ctx
,
cmd
);
doAfterRpcHooks
(
RemotingHelper
.
parseChannelRemoteAddr
(
ctx
.
channel
()),
cmd
,
response
);
callback
.
callback
(
response
);
}
}
catch
(
Throwable
e
)
{
log
.
error
(
"process request exception"
,
e
);
log
.
error
(
cmd
.
toString
());
...
...
remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java
浏览文件 @
64e4ca72
...
...
@@ -27,4 +27,5 @@ public interface NettyRequestProcessor {
throws
Exception
;
boolean
rejectRequest
();
}
remoting/src/main/java/org/apache/rocketmq/remoting/netty/RemotingResponseCallback.java
0 → 100644
浏览文件 @
64e4ca72
/*
* 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.
*/
package
org.apache.rocketmq.remoting.netty
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
public
interface
RemotingResponseCallback
{
void
callback
(
RemotingCommand
response
);
}
remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
浏览文件 @
64e4ca72
...
...
@@ -26,12 +26,7 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
import
org.apache.rocketmq.remoting.exception.RemotingSendRequestException
;
import
org.apache.rocketmq.remoting.exception.RemotingTimeoutException
;
import
org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException
;
import
org.apache.rocketmq.remoting.netty.NettyClientConfig
;
import
org.apache.rocketmq.remoting.netty.NettyRemotingClient
;
import
org.apache.rocketmq.remoting.netty.NettyRemotingServer
;
import
org.apache.rocketmq.remoting.netty.NettyRequestProcessor
;
import
org.apache.rocketmq.remoting.netty.NettyServerConfig
;
import
org.apache.rocketmq.remoting.netty.ResponseFuture
;
import
org.apache.rocketmq.remoting.netty.*
;
import
org.apache.rocketmq.remoting.protocol.LanguageCode
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.junit.AfterClass
;
...
...
@@ -48,7 +43,7 @@ public class RemotingServerTest {
public
static
RemotingServer
createRemotingServer
()
throws
InterruptedException
{
NettyServerConfig
config
=
new
NettyServerConfig
();
RemotingServer
remotingServer
=
new
NettyRemotingServer
(
config
);
remotingServer
.
registerProcessor
(
0
,
new
NettyRequestProcessor
()
{
remotingServer
.
registerProcessor
(
0
,
new
Async
NettyRequestProcessor
()
{
@Override
public
RemotingCommand
processRequest
(
ChannelHandlerContext
ctx
,
RemotingCommand
request
)
{
request
.
setRemark
(
"Hi "
+
ctx
.
channel
().
remoteAddress
());
...
...
store/src/main/java/org/apache/rocketmq/store/CommitLog.java
浏览文件 @
64e4ca72
...
...
@@ -23,8 +23,11 @@ import java.util.ArrayList;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
import
org.apache.rocketmq.common.ServiceThread
;
import
org.apache.rocketmq.common.UtilAll
;
import
org.apache.rocketmq.common.constant.LoggerName
;
...
...
@@ -63,6 +66,7 @@ public class CommitLog {
protected
volatile
long
confirmOffset
=
-
1L
;
private
volatile
long
beginTimeInLock
=
0
;
protected
final
PutMessageLock
putMessageLock
;
public
CommitLog
(
final
DefaultMessageStore
defaultMessageStore
)
{
...
...
@@ -550,6 +554,228 @@ public class CommitLog {
return
beginTimeInLock
;
}
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessage
(
final
MessageExtBrokerInner
msg
)
{
// Set the storage time
msg
.
setStoreTimestamp
(
System
.
currentTimeMillis
());
// Set the message body BODY CRC (consider the most appropriate setting
// on the client)
msg
.
setBodyCRC
(
UtilAll
.
crc32
(
msg
.
getBody
()));
// Back to Results
AppendMessageResult
result
=
null
;
StoreStatsService
storeStatsService
=
this
.
defaultMessageStore
.
getStoreStatsService
();
String
topic
=
msg
.
getTopic
();
int
queueId
=
msg
.
getQueueId
();
final
int
tranType
=
MessageSysFlag
.
getTransactionValue
(
msg
.
getSysFlag
());
if
(
tranType
==
MessageSysFlag
.
TRANSACTION_NOT_TYPE
||
tranType
==
MessageSysFlag
.
TRANSACTION_COMMIT_TYPE
)
{
// Delay Delivery
if
(
msg
.
getDelayTimeLevel
()
>
0
)
{
if
(
msg
.
getDelayTimeLevel
()
>
this
.
defaultMessageStore
.
getScheduleMessageService
().
getMaxDelayLevel
())
{
msg
.
setDelayTimeLevel
(
this
.
defaultMessageStore
.
getScheduleMessageService
().
getMaxDelayLevel
());
}
topic
=
ScheduleMessageService
.
SCHEDULE_TOPIC
;
queueId
=
ScheduleMessageService
.
delayLevel2QueueId
(
msg
.
getDelayTimeLevel
());
// Backup real topic, queueId
MessageAccessor
.
putProperty
(
msg
,
MessageConst
.
PROPERTY_REAL_TOPIC
,
msg
.
getTopic
());
MessageAccessor
.
putProperty
(
msg
,
MessageConst
.
PROPERTY_REAL_QUEUE_ID
,
String
.
valueOf
(
msg
.
getQueueId
()));
msg
.
setPropertiesString
(
MessageDecoder
.
messageProperties2String
(
msg
.
getProperties
()));
msg
.
setTopic
(
topic
);
msg
.
setQueueId
(
queueId
);
}
}
long
elapsedTimeInLock
=
0
;
MappedFile
unlockMappedFile
=
null
;
MappedFile
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
();
putMessageLock
.
lock
();
//spin or ReentrantLock ,depending on store config
try
{
long
beginLockTimestamp
=
this
.
defaultMessageStore
.
getSystemClock
().
now
();
this
.
beginTimeInLock
=
beginLockTimestamp
;
// Here settings are stored timestamp, in order to ensure an orderly
// global
msg
.
setStoreTimestamp
(
beginLockTimestamp
);
if
(
null
==
mappedFile
||
mappedFile
.
isFull
())
{
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
(
0
);
// Mark: NewFile may be cause noise
}
if
(
null
==
mappedFile
)
{
log
.
error
(
"create mapped file1 error, topic: "
+
msg
.
getTopic
()
+
" clientAddr: "
+
msg
.
getBornHostString
());
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
null
));
}
result
=
mappedFile
.
appendMessage
(
msg
,
this
.
appendMessageCallback
);
switch
(
result
.
getStatus
())
{
case
PUT_OK:
break
;
case
END_OF_FILE:
unlockMappedFile
=
mappedFile
;
// Create a new file, re-write the message
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
(
0
);
if
(
null
==
mappedFile
)
{
// XXX: warn and notify me
log
.
error
(
"create mapped file2 error, topic: "
+
msg
.
getTopic
()
+
" clientAddr: "
+
msg
.
getBornHostString
());
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
result
));
}
result
=
mappedFile
.
appendMessage
(
msg
,
this
.
appendMessageCallback
);
break
;
case
MESSAGE_SIZE_EXCEEDED:
case
PROPERTIES_SIZE_EXCEEDED:
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
result
));
case
UNKNOWN_ERROR:
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
UNKNOWN_ERROR
,
result
));
default
:
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
UNKNOWN_ERROR
,
result
));
}
elapsedTimeInLock
=
this
.
defaultMessageStore
.
getSystemClock
().
now
()
-
beginLockTimestamp
;
beginTimeInLock
=
0
;
}
finally
{
putMessageLock
.
unlock
();
}
if
(
elapsedTimeInLock
>
500
)
{
log
.
warn
(
"[NOTIFYME]putMessage in lock cost time(ms)={}, bodyLength={} AppendMessageResult={}"
,
elapsedTimeInLock
,
msg
.
getBody
().
length
,
result
);
}
if
(
null
!=
unlockMappedFile
&&
this
.
defaultMessageStore
.
getMessageStoreConfig
().
isWarmMapedFileEnable
())
{
this
.
defaultMessageStore
.
unlockMappedFile
(
unlockMappedFile
);
}
PutMessageResult
putMessageResult
=
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
result
);
// Statistics
storeStatsService
.
getSinglePutMessageTopicTimesTotal
(
msg
.
getTopic
()).
incrementAndGet
();
storeStatsService
.
getSinglePutMessageTopicSizeTotal
(
topic
).
addAndGet
(
result
.
getWroteBytes
());
CompletableFuture
<
PutMessageStatus
>
flushResultFuture
=
submitFlushRequest
(
result
,
putMessageResult
,
msg
);
CompletableFuture
<
PutMessageStatus
>
replicaResultFuture
=
submitReplicaRequest
(
result
,
putMessageResult
,
msg
);
return
flushResultFuture
.
thenCombine
(
replicaResultFuture
,
(
flushStatus
,
replicaStatus
)
->
{
if
(
flushStatus
!=
PutMessageStatus
.
PUT_OK
)
{
putMessageResult
.
setPutMessageStatus
(
PutMessageStatus
.
FLUSH_DISK_TIMEOUT
);
}
if
(
replicaStatus
!=
PutMessageStatus
.
PUT_OK
)
{
putMessageResult
.
setPutMessageStatus
(
replicaStatus
);
}
return
putMessageResult
;
});
}
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessages
(
final
MessageExtBatch
messageExtBatch
)
{
messageExtBatch
.
setStoreTimestamp
(
System
.
currentTimeMillis
());
AppendMessageResult
result
;
StoreStatsService
storeStatsService
=
this
.
defaultMessageStore
.
getStoreStatsService
();
final
int
tranType
=
MessageSysFlag
.
getTransactionValue
(
messageExtBatch
.
getSysFlag
());
if
(
tranType
!=
MessageSysFlag
.
TRANSACTION_NOT_TYPE
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
));
}
if
(
messageExtBatch
.
getDelayTimeLevel
()
>
0
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
));
}
long
elapsedTimeInLock
=
0
;
MappedFile
unlockMappedFile
=
null
;
MappedFile
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
();
//fine-grained lock instead of the coarse-grained
MessageExtBatchEncoder
batchEncoder
=
batchEncoderThreadLocal
.
get
();
messageExtBatch
.
setEncodedBuff
(
batchEncoder
.
encode
(
messageExtBatch
));
putMessageLock
.
lock
();
try
{
long
beginLockTimestamp
=
this
.
defaultMessageStore
.
getSystemClock
().
now
();
this
.
beginTimeInLock
=
beginLockTimestamp
;
// Here settings are stored timestamp, in order to ensure an orderly
// global
messageExtBatch
.
setStoreTimestamp
(
beginLockTimestamp
);
if
(
null
==
mappedFile
||
mappedFile
.
isFull
())
{
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
(
0
);
// Mark: NewFile may be cause noise
}
if
(
null
==
mappedFile
)
{
log
.
error
(
"Create mapped file1 error, topic: {} clientAddr: {}"
,
messageExtBatch
.
getTopic
(),
messageExtBatch
.
getBornHostString
());
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
null
));
}
result
=
mappedFile
.
appendMessages
(
messageExtBatch
,
this
.
appendMessageCallback
);
switch
(
result
.
getStatus
())
{
case
PUT_OK:
break
;
case
END_OF_FILE:
unlockMappedFile
=
mappedFile
;
// Create a new file, re-write the message
mappedFile
=
this
.
mappedFileQueue
.
getLastMappedFile
(
0
);
if
(
null
==
mappedFile
)
{
// XXX: warn and notify me
log
.
error
(
"Create mapped file2 error, topic: {} clientAddr: {}"
,
messageExtBatch
.
getTopic
(),
messageExtBatch
.
getBornHostString
());
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
CREATE_MAPEDFILE_FAILED
,
result
));
}
result
=
mappedFile
.
appendMessages
(
messageExtBatch
,
this
.
appendMessageCallback
);
break
;
case
MESSAGE_SIZE_EXCEEDED:
case
PROPERTIES_SIZE_EXCEEDED:
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
result
));
case
UNKNOWN_ERROR:
default
:
beginTimeInLock
=
0
;
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
PutMessageStatus
.
UNKNOWN_ERROR
,
result
));
}
elapsedTimeInLock
=
this
.
defaultMessageStore
.
getSystemClock
().
now
()
-
beginLockTimestamp
;
beginTimeInLock
=
0
;
}
finally
{
putMessageLock
.
unlock
();
}
if
(
elapsedTimeInLock
>
500
)
{
log
.
warn
(
"[NOTIFYME]putMessages in lock cost time(ms)={}, bodyLength={} AppendMessageResult={}"
,
elapsedTimeInLock
,
messageExtBatch
.
getBody
().
length
,
result
);
}
if
(
null
!=
unlockMappedFile
&&
this
.
defaultMessageStore
.
getMessageStoreConfig
().
isWarmMapedFileEnable
())
{
this
.
defaultMessageStore
.
unlockMappedFile
(
unlockMappedFile
);
}
PutMessageResult
putMessageResult
=
new
PutMessageResult
(
PutMessageStatus
.
PUT_OK
,
result
);
// Statistics
storeStatsService
.
getSinglePutMessageTopicTimesTotal
(
messageExtBatch
.
getTopic
()).
addAndGet
(
result
.
getMsgNum
());
storeStatsService
.
getSinglePutMessageTopicSizeTotal
(
messageExtBatch
.
getTopic
()).
addAndGet
(
result
.
getWroteBytes
());
CompletableFuture
<
PutMessageStatus
>
flushOKFuture
=
submitFlushRequest
(
result
,
putMessageResult
,
messageExtBatch
);
CompletableFuture
<
PutMessageStatus
>
replicaOKFuture
=
submitReplicaRequest
(
result
,
putMessageResult
,
messageExtBatch
);
return
flushOKFuture
.
thenCombine
(
replicaOKFuture
,
(
flushStatus
,
replicaStatus
)
->
{
if
(
flushStatus
!=
PutMessageStatus
.
PUT_OK
)
{
putMessageResult
.
setPutMessageStatus
(
PutMessageStatus
.
FLUSH_DISK_TIMEOUT
);
}
if
(
replicaStatus
!=
PutMessageStatus
.
PUT_OK
)
{
putMessageResult
.
setPutMessageStatus
(
replicaStatus
);
}
return
putMessageResult
;
});
}
public
PutMessageResult
putMessage
(
final
MessageExtBrokerInner
msg
)
{
// Set the storage time
msg
.
setStoreTimestamp
(
System
.
currentTimeMillis
());
...
...
@@ -673,6 +899,53 @@ public class CommitLog {
return
putMessageResult
;
}
public
CompletableFuture
<
PutMessageStatus
>
submitFlushRequest
(
AppendMessageResult
result
,
PutMessageResult
putMessageResult
,
MessageExt
messageExt
)
{
// Synchronization flush
if
(
FlushDiskType
.
SYNC_FLUSH
==
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getFlushDiskType
())
{
final
GroupCommitService
service
=
(
GroupCommitService
)
this
.
flushCommitLogService
;
if
(
messageExt
.
isWaitStoreMsgOK
())
{
GroupCommitRequest
request
=
new
GroupCommitRequest
(
result
.
getWroteOffset
()
+
result
.
getWroteBytes
(),
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
());
service
.
putRequest
(
request
);
return
request
.
future
();
}
else
{
service
.
wakeup
();
return
CompletableFuture
.
completedFuture
(
PutMessageStatus
.
PUT_OK
);
}
}
// Asynchronous flush
else
{
if
(!
this
.
defaultMessageStore
.
getMessageStoreConfig
().
isTransientStorePoolEnable
())
{
flushCommitLogService
.
wakeup
();
}
else
{
commitLogService
.
wakeup
();
}
return
CompletableFuture
.
completedFuture
(
PutMessageStatus
.
PUT_OK
);
}
}
public
CompletableFuture
<
PutMessageStatus
>
submitReplicaRequest
(
AppendMessageResult
result
,
PutMessageResult
putMessageResult
,
MessageExt
messageExt
)
{
if
(
BrokerRole
.
SYNC_MASTER
==
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getBrokerRole
())
{
HAService
service
=
this
.
defaultMessageStore
.
getHaService
();
if
(
messageExt
.
isWaitStoreMsgOK
())
{
if
(
service
.
isSlaveOK
(
result
.
getWroteBytes
()
+
result
.
getWroteOffset
()))
{
GroupCommitRequest
request
=
new
GroupCommitRequest
(
result
.
getWroteOffset
()
+
result
.
getWroteBytes
(),
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
());
service
.
putRequest
(
request
);
service
.
getWaitNotifyObject
().
wakeupAll
();
return
request
.
future
();
}
else
{
return
CompletableFuture
.
completedFuture
(
PutMessageStatus
.
SLAVE_NOT_AVAILABLE
);
}
}
}
return
CompletableFuture
.
completedFuture
(
PutMessageStatus
.
PUT_OK
);
}
public
void
handleDiskFlush
(
AppendMessageResult
result
,
PutMessageResult
putMessageResult
,
MessageExt
messageExt
)
{
// Synchronization flush
if
(
FlushDiskType
.
SYNC_FLUSH
==
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getFlushDiskType
())
{
...
...
@@ -680,8 +953,15 @@ public class CommitLog {
if
(
messageExt
.
isWaitStoreMsgOK
())
{
GroupCommitRequest
request
=
new
GroupCommitRequest
(
result
.
getWroteOffset
()
+
result
.
getWroteBytes
());
service
.
putRequest
(
request
);
boolean
flushOK
=
request
.
waitForFlush
(
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
());
if
(!
flushOK
)
{
CompletableFuture
<
PutMessageStatus
>
flushOkFuture
=
request
.
future
();
PutMessageStatus
flushStatus
=
null
;
try
{
flushStatus
=
flushOkFuture
.
get
(
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
(),
TimeUnit
.
MILLISECONDS
);
}
catch
(
InterruptedException
|
ExecutionException
|
TimeoutException
e
)
{
//flushOK=false;
}
if
(
flushStatus
!=
PutMessageStatus
.
PUT_OK
)
{
log
.
error
(
"do groupcommit, wait for flush failed, topic: "
+
messageExt
.
getTopic
()
+
" tags: "
+
messageExt
.
getTags
()
+
" client address: "
+
messageExt
.
getBornHostString
());
putMessageResult
.
setPutMessageStatus
(
PutMessageStatus
.
FLUSH_DISK_TIMEOUT
);
...
...
@@ -709,9 +989,13 @@ public class CommitLog {
GroupCommitRequest
request
=
new
GroupCommitRequest
(
result
.
getWroteOffset
()
+
result
.
getWroteBytes
());
service
.
putRequest
(
request
);
service
.
getWaitNotifyObject
().
wakeupAll
();
boolean
flushOK
=
request
.
waitForFlush
(
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
());
if
(!
flushOK
)
{
PutMessageStatus
replicaStatus
=
null
;
try
{
replicaStatus
=
request
.
future
().
get
(
this
.
defaultMessageStore
.
getMessageStoreConfig
().
getSyncFlushTimeout
(),
TimeUnit
.
MILLISECONDS
);
}
catch
(
InterruptedException
|
ExecutionException
|
TimeoutException
e
)
{
}
if
(
replicaStatus
!=
PutMessageStatus
.
PUT_OK
)
{
log
.
error
(
"do sync transfer other node, wait return, but failed, topic: "
+
messageExt
.
getTopic
()
+
" tags: "
+
messageExt
.
getTags
()
+
" client address: "
+
messageExt
.
getBornHostNameString
());
putMessageResult
.
setPutMessageStatus
(
PutMessageStatus
.
FLUSH_SLAVE_TIMEOUT
);
...
...
@@ -1081,31 +1365,35 @@ public class CommitLog {
public
static
class
GroupCommitRequest
{
private
final
long
nextOffset
;
private
final
CountDownLatch
countDownLatch
=
new
CountDownLatch
(
1
);
private
volatile
boolean
flushOK
=
false
;
private
CompletableFuture
<
PutMessageStatus
>
flushOKFuture
=
new
CompletableFuture
<>();
private
final
long
startTimestamp
=
System
.
currentTimeMillis
();
private
long
timeoutMillis
=
Long
.
MAX_VALUE
;
public
GroupCommitRequest
(
long
nextOffset
,
long
timeoutMillis
)
{
this
.
nextOffset
=
nextOffset
;
this
.
timeoutMillis
=
timeoutMillis
;
}
public
GroupCommitRequest
(
long
nextOffset
)
{
this
.
nextOffset
=
nextOffset
;
}
public
long
getNextOffset
()
{
return
nextOffset
;
}
public
void
wakeupCustomer
(
final
boolean
flushOK
)
{
this
.
flushOK
=
flushOK
;
this
.
countDownLatch
.
countDown
();
long
endTimestamp
=
System
.
currentTimeMillis
();
PutMessageStatus
result
=
(
flushOK
&&
((
endTimestamp
-
this
.
startTimestamp
)
<=
this
.
timeoutMillis
))
?
PutMessageStatus
.
PUT_OK
:
PutMessageStatus
.
FLUSH_SLAVE_TIMEOUT
;
this
.
flushOKFuture
.
complete
(
result
);
}
public
boolean
waitForFlush
(
long
timeout
)
{
try
{
this
.
countDownLatch
.
await
(
timeout
,
TimeUnit
.
MILLISECONDS
);
return
this
.
flushOK
;
}
catch
(
InterruptedException
e
)
{
log
.
error
(
"Interrupted"
,
e
);
return
false
;
}
public
CompletableFuture
<
PutMessageStatus
>
future
()
{
return
flushOKFuture
;
}
}
/**
...
...
store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
浏览文件 @
64e4ca72
...
...
@@ -31,6 +31,7 @@ import java.util.LinkedList;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.Executors
;
...
...
@@ -351,49 +352,79 @@ public class DefaultMessageStore implements MessageStore {
}
}
public
PutMessageResult
putMessage
(
MessageExtBrokerInner
msg
)
{
private
PutMessageStatus
checkMessage
(
MessageExtBrokerInner
msg
)
{
if
(
msg
.
getTopic
().
length
()
>
Byte
.
MAX_VALUE
)
{
log
.
warn
(
"putMessage message topic length too long "
+
msg
.
getTopic
().
length
());
return
PutMessageStatus
.
MESSAGE_ILLEGAL
;
}
if
(
msg
.
getPropertiesString
()
!=
null
&&
msg
.
getPropertiesString
().
length
()
>
Short
.
MAX_VALUE
)
{
log
.
warn
(
"putMessage message properties length too long "
+
msg
.
getPropertiesString
().
length
());
return
PutMessageStatus
.
MESSAGE_ILLEGAL
;
}
return
PutMessageStatus
.
PUT_OK
;
}
private
PutMessageStatus
checkMessages
(
MessageExtBatch
messageExtBatch
)
{
if
(
messageExtBatch
.
getTopic
().
length
()
>
Byte
.
MAX_VALUE
)
{
log
.
warn
(
"putMessage message topic length too long "
+
messageExtBatch
.
getTopic
().
length
());
return
PutMessageStatus
.
MESSAGE_ILLEGAL
;
}
if
(
messageExtBatch
.
getBody
().
length
>
messageStoreConfig
.
getMaxMessageSize
())
{
log
.
warn
(
"PutMessages body length too long "
+
messageExtBatch
.
getBody
().
length
);
return
PutMessageStatus
.
MESSAGE_ILLEGAL
;
}
return
PutMessageStatus
.
PUT_OK
;
}
private
PutMessageStatus
checkStoreStatus
()
{
if
(
this
.
shutdown
)
{
log
.
warn
(
"message store has shutdown, so putMessage is forbidden"
);
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
)
;
return
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
;
}
if
(
BrokerRole
.
SLAVE
==
this
.
messageStoreConfig
.
getBrokerRole
())
{
long
value
=
this
.
printTimes
.
getAndIncrement
();
if
((
value
%
50000
)
==
0
)
{
log
.
warn
(
"message store
is slave mode, so putMessage is forbidden
"
);
log
.
warn
(
"message store
has shutdown, so putMessage is forbidden
"
);
}
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
);
return
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
;
}
if
(!
this
.
runningFlags
.
isWriteable
())
{
long
value
=
this
.
printTimes
.
getAndIncrement
();
if
((
value
%
50000
)
==
0
)
{
log
.
warn
(
"message store
is not writeable, so putMessage is forbidden "
+
this
.
runningFlags
.
getFlagBits
()
);
log
.
warn
(
"message store
has shutdown, so putMessage is forbidden"
);
}
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
);
return
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
;
}
else
{
this
.
printTimes
.
set
(
0
);
}
if
(
msg
.
getTopic
().
length
()
>
Byte
.
MAX_VALUE
)
{
log
.
warn
(
"putMessage message topic length too long "
+
msg
.
getTopic
().
length
());
return
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
);
if
(
this
.
isOSPageCacheBusy
())
{
return
PutMessageStatus
.
OS_PAGECACHE_BUSY
;
}
return
PutMessageStatus
.
PUT_OK
;
}
if
(
msg
.
getPropertiesString
()
!=
null
&&
msg
.
getPropertiesString
().
length
()
>
Short
.
MAX_VALUE
)
{
log
.
warn
(
"putMessage message properties length too long "
+
msg
.
getPropertiesString
().
length
());
return
new
PutMessageResult
(
PutMessageStatus
.
PROPERTIES_SIZE_EXCEEDED
,
null
);
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessage
(
MessageExtBrokerInner
msg
)
{
PutMessageStatus
checkStoreStatus
=
this
.
checkStoreStatus
();
if
(
checkStoreStatus
!=
PutMessageStatus
.
PUT_OK
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
checkStoreStatus
,
null
));
}
if
(
this
.
isOSPageCacheBusy
())
{
return
new
PutMessageResult
(
PutMessageStatus
.
OS_PAGECACHE_BUSY
,
null
);
PutMessageStatus
msgCheckStatus
=
this
.
checkMessage
(
msg
);
if
(
msgCheckStatus
==
PutMessageStatus
.
MESSAGE_ILLEGAL
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
msgCheckStatus
,
null
));
}
long
beginTime
=
this
.
getSystemClock
().
now
();
PutMessageResult
result
=
this
.
commitLog
.
p
utMessage
(
msg
);
CompletableFuture
<
PutMessageResult
>
putResultFuture
=
this
.
commitLog
.
asyncP
utMessage
(
msg
);
putResultFuture
.
thenAccept
((
result
)
->
{
long
elapsedTime
=
this
.
getSystemClock
().
now
()
-
beginTime
;
if
(
elapsedTime
>
500
)
{
log
.
warn
(
"putMessage not in lock elapsed time(ms)={}, bodyLength={}"
,
elapsedTime
,
msg
.
getBody
().
length
);
...
...
@@ -403,57 +434,88 @@ public class DefaultMessageStore implements MessageStore {
if
(
null
==
result
||
!
result
.
isOk
())
{
this
.
storeStatsService
.
getPutMessageFailedTimes
().
incrementAndGet
();
}
});
return
result
;
return
putResultFuture
;
}
public
PutMessageResult
p
utMessages
(
MessageExtBatch
messageExtBatch
)
{
if
(
this
.
shutdown
)
{
log
.
warn
(
"DefaultMessageStore has shutdown, so putMessages is forbidden"
);
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
);
public
CompletableFuture
<
PutMessageResult
>
asyncP
utMessages
(
MessageExtBatch
messageExtBatch
)
{
PutMessageStatus
checkStoreStatus
=
this
.
checkStoreStatus
();
if
(
checkStoreStatus
!=
PutMessageStatus
.
PUT_OK
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
checkStoreStatus
,
null
)
);
}
if
(
BrokerRole
.
SLAVE
==
this
.
messageStoreConfig
.
getBrokerRole
())
{
long
value
=
this
.
printTimes
.
getAndIncrement
();
if
((
value
%
50000
)
==
0
)
{
log
.
warn
(
"DefaultMessageStore is in slave mode, so putMessages is forbidden "
);
PutMessageStatus
msgCheckStatus
=
this
.
checkMessages
(
messageExtBatch
);
if
(
msgCheckStatus
==
PutMessageStatus
.
MESSAGE_ILLEGAL
)
{
return
CompletableFuture
.
completedFuture
(
new
PutMessageResult
(
msgCheckStatus
,
null
));
}
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
);
long
beginTime
=
this
.
getSystemClock
().
now
();
CompletableFuture
<
PutMessageResult
>
resultFuture
=
this
.
commitLog
.
asyncPutMessages
(
messageExtBatch
);
resultFuture
.
thenAccept
((
result
)
->
{
long
elapsedTime
=
this
.
getSystemClock
().
now
()
-
beginTime
;
if
(
elapsedTime
>
500
)
{
log
.
warn
(
"not in lock elapsed time(ms)={}, bodyLength={}"
,
elapsedTime
,
messageExtBatch
.
getBody
().
length
);
}
if
(!
this
.
runningFlags
.
isWriteable
())
{
long
value
=
this
.
printTimes
.
getAndIncrement
();
if
(
(
value
%
50000
)
==
0
)
{
log
.
warn
(
"DefaultMessageStore is not writable, so putMessages is forbidden "
+
this
.
runningFlags
.
getFlagBits
()
);
this
.
storeStatsService
.
setPutMessageEntireTimeMax
(
elapsedTime
);
if
(
null
==
result
||
!
result
.
isOk
()
)
{
this
.
storeStatsService
.
getPutMessageFailedTimes
().
incrementAndGet
(
);
}
});
return
new
PutMessageResult
(
PutMessageStatus
.
SERVICE_NOT_AVAILABLE
,
null
);
}
else
{
this
.
printTimes
.
set
(
0
);
return
resultFuture
;
}
if
(
messageExtBatch
.
getTopic
().
length
()
>
Byte
.
MAX_VALUE
)
{
log
.
warn
(
"PutMessages topic length too long "
+
messageExtBatch
.
getTopic
().
length
());
return
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
);
@Override
public
PutMessageResult
putMessage
(
MessageExtBrokerInner
msg
)
{
PutMessageStatus
checkStoreStatus
=
this
.
checkStoreStatus
();
if
(
checkStoreStatus
!=
PutMessageStatus
.
PUT_OK
)
{
return
new
PutMessageResult
(
checkStoreStatus
,
null
);
}
if
(
messageExtBatch
.
getBody
().
length
>
messageStoreConfig
.
getMaxMessageSize
())
{
log
.
warn
(
"PutMessages body length too long "
+
messageExtBatch
.
getBody
().
length
);
return
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
);
PutMessageStatus
msgCheckStatus
=
this
.
checkMessage
(
msg
);
if
(
msgCheckStatus
==
PutMessageStatus
.
MESSAGE_ILLEGAL
)
{
return
new
PutMessageResult
(
msgCheckStatus
,
null
);
}
if
(
this
.
isOSPageCacheBusy
())
{
return
new
PutMessageResult
(
PutMessageStatus
.
OS_PAGECACHE_BUSY
,
null
);
long
beginTime
=
this
.
getSystemClock
().
now
();
PutMessageResult
result
=
this
.
commitLog
.
putMessage
(
msg
);
long
elapsedTime
=
this
.
getSystemClock
().
now
()
-
beginTime
;
if
(
elapsedTime
>
500
)
{
log
.
warn
(
"not in lock elapsed time(ms)={}, bodyLength={}"
,
elapsedTime
,
msg
.
getBody
().
length
);
}
this
.
storeStatsService
.
setPutMessageEntireTimeMax
(
elapsedTime
);
if
(
null
==
result
||
!
result
.
isOk
())
{
this
.
storeStatsService
.
getPutMessageFailedTimes
().
incrementAndGet
();
}
return
result
;
}
@Override
public
PutMessageResult
putMessages
(
MessageExtBatch
messageExtBatch
)
{
PutMessageStatus
checkStoreStatus
=
this
.
checkStoreStatus
();
if
(
checkStoreStatus
!=
PutMessageStatus
.
PUT_OK
)
{
return
new
PutMessageResult
(
checkStoreStatus
,
null
);
}
PutMessageStatus
msgCheckStatus
=
this
.
checkMessages
(
messageExtBatch
);
if
(
msgCheckStatus
==
PutMessageStatus
.
MESSAGE_ILLEGAL
)
{
return
new
PutMessageResult
(
msgCheckStatus
,
null
);
}
long
beginTime
=
this
.
getSystemClock
().
now
();
PutMessageResult
result
=
this
.
commitLog
.
putMessages
(
messageExtBatch
);
long
elapsedTime
=
this
.
getSystemClock
().
now
()
-
beginTime
;
if
(
elapsedTime
>
500
)
{
log
.
warn
(
"not in lock elapsed time(ms)={}, bodyLength={}"
,
elapsedTime
,
messageExtBatch
.
getBody
().
length
);
}
this
.
storeStatsService
.
setPutMessageEntireTimeMax
(
elapsedTime
);
if
(
null
==
result
||
!
result
.
isOk
())
{
...
...
store/src/main/java/org/apache/rocketmq/store/MessageStore.java
浏览文件 @
64e4ca72
...
...
@@ -19,6 +19,8 @@ package org.apache.rocketmq.store;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.Set
;
import
java.util.concurrent.CompletableFuture
;
import
org.apache.rocketmq.common.message.MessageExt
;
import
org.apache.rocketmq.common.message.MessageExtBatch
;
import
org.apache.rocketmq.store.config.BrokerRole
;
...
...
@@ -53,6 +55,26 @@ public interface MessageStore {
*/
void
destroy
();
/** Store a message into store in async manner, the processor can process the next request
* rather than wait for result
* when result is completed, notify the client in async manner
*
* @param msg MessageInstance to store
* @return a CompletableFuture for the result of store operation
*/
default
CompletableFuture
<
PutMessageResult
>
asyncPutMessage
(
final
MessageExtBrokerInner
msg
)
{
return
CompletableFuture
.
completedFuture
(
putMessage
(
msg
));
}
/**
* Store a batch of messages in async manner
* @param messageExtBatch the message batch
* @return a CompletableFuture for the result of store operation
*/
default
CompletableFuture
<
PutMessageResult
>
asyncPutMessages
(
final
MessageExtBatch
messageExtBatch
)
{
return
CompletableFuture
.
completedFuture
(
putMessages
(
messageExtBatch
));
}
/**
* Store a message into store.
*
...
...
store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java
浏览文件 @
64e4ca72
...
...
@@ -30,6 +30,7 @@ import io.openmessaging.storage.dledger.store.file.SelectMmapBufferResult;
import
io.openmessaging.storage.dledger.utils.DLedgerUtils
;
import
java.nio.ByteBuffer
;
import
java.util.HashMap
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.rocketmq.common.UtilAll
;
import
org.apache.rocketmq.common.message.MessageAccessor
;
...
...
@@ -489,6 +490,16 @@ public class DLedgerCommitLog extends CommitLog {
return
new
PutMessageResult
(
PutMessageStatus
.
MESSAGE_ILLEGAL
,
null
);
}
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessage
(
MessageExtBrokerInner
msg
)
{
return
CompletableFuture
.
completedFuture
(
this
.
putMessage
(
msg
));
}
@Override
public
CompletableFuture
<
PutMessageResult
>
asyncPutMessages
(
MessageExtBatch
messageExtBatch
)
{
return
CompletableFuture
.
completedFuture
(
putMessages
(
messageExtBatch
));
}
@Override
public
SelectMappedBufferResult
getMessage
(
final
long
offset
,
final
int
size
)
{
if
(
offset
<
dividedCommitlogOffset
)
{
...
...
store/src/test/java/org/apache/rocketmq/store/HATest.java
浏览文件 @
64e4ca72
...
...
@@ -19,6 +19,8 @@ package org.apache.rocketmq.store;
import
org.apache.rocketmq.common.BrokerConfig
;
import
org.apache.rocketmq.common.UtilAll
;
import
org.apache.rocketmq.common.message.MessageDecoder
;
import
org.apache.rocketmq.common.message.MessageExt
;
import
org.apache.rocketmq.store.config.BrokerRole
;
import
org.apache.rocketmq.store.config.FlushDiskType
;
import
org.apache.rocketmq.store.config.MessageStoreConfig
;
...
...
@@ -34,12 +36,13 @@ import java.lang.reflect.Method;
import
java.net.InetAddress
;
import
java.net.InetSocketAddress
;
import
java.net.SocketAddress
;
import
java.util.Arrays
;
import
java.util.UUID
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.*;
/**
* HATest
...
...
@@ -119,6 +122,37 @@ public class HATest {
}
}
@Test
public
void
testSemiSyncReplica
()
throws
Exception
{
long
totalMsgs
=
5
;
QUEUE_TOTAL
=
1
;
MessageBody
=
StoreMessage
.
getBytes
();
for
(
long
i
=
0
;
i
<
totalMsgs
;
i
++)
{
MessageExtBrokerInner
msg
=
buildMessage
();
CompletableFuture
<
PutMessageResult
>
putResultFuture
=
messageStore
.
asyncPutMessage
(
msg
);
PutMessageResult
result
=
putResultFuture
.
get
();
assertEquals
(
PutMessageStatus
.
PUT_OK
,
result
.
getPutMessageStatus
());
//message has been replicated to slave's commitLog, but maybe not dispatch to ConsumeQueue yet
//so direct read from commitLog by physical offset
MessageExt
slaveMsg
=
slaveMessageStore
.
lookMessageByOffset
(
result
.
getAppendMessageResult
().
getWroteOffset
());
assertNotNull
(
slaveMsg
);
assertTrue
(
Arrays
.
equals
(
msg
.
getBody
(),
slaveMsg
.
getBody
()));
assertEquals
(
msg
.
getTopic
(),
slaveMsg
.
getTopic
());
assertEquals
(
msg
.
getTags
(),
slaveMsg
.
getTags
());
assertEquals
(
msg
.
getKeys
(),
slaveMsg
.
getKeys
());
}
//shutdown slave, putMessage should return FLUSH_SLAVE_TIMEOUT
slaveMessageStore
.
shutdown
();
//wait to let master clean the slave's connection
Thread
.
sleep
(
masterMessageStoreConfig
.
getHaHousekeepingInterval
()
+
500
);
for
(
long
i
=
0
;
i
<
totalMsgs
;
i
++)
{
CompletableFuture
<
PutMessageResult
>
putResultFuture
=
messageStore
.
asyncPutMessage
(
buildMessage
());
PutMessageResult
result
=
putResultFuture
.
get
();
assertEquals
(
PutMessageStatus
.
SLAVE_NOT_AVAILABLE
,
result
.
getPutMessageStatus
());
}
}
@After
public
void
destroy
()
throws
Exception
{
Thread
.
sleep
(
5000L
);
...
...
@@ -156,6 +190,7 @@ public class HATest {
msg
.
setBornTimestamp
(
System
.
currentTimeMillis
());
msg
.
setStoreHost
(
StoreHost
);
msg
.
setBornHost
(
BornHost
);
msg
.
setPropertiesString
(
MessageDecoder
.
messageProperties2String
(
msg
.
getProperties
()));
return
msg
;
}
...
...
test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQTransactionalProducer.java
0 → 100644
浏览文件 @
64e4ca72
/*
* 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.
*/
package
org.apache.rocketmq.test.client.rmq
;
import
org.apache.log4j.Logger
;
import
org.apache.rocketmq.client.exception.MQClientException
;
import
org.apache.rocketmq.client.producer.LocalTransactionState
;
import
org.apache.rocketmq.client.producer.TransactionListener
;
import
org.apache.rocketmq.client.producer.TransactionMQProducer
;
import
org.apache.rocketmq.common.Pair
;
import
org.apache.rocketmq.common.message.Message
;
import
org.apache.rocketmq.test.clientinterface.AbstractMQProducer
;
import
org.apache.rocketmq.test.sendresult.ResultWrapper
;
public
class
RMQTransactionalProducer
extends
AbstractMQProducer
{
private
static
Logger
logger
=
Logger
.
getLogger
(
RMQTransactionalProducer
.
class
);
private
TransactionMQProducer
producer
=
null
;
private
String
nsAddr
=
null
;
public
RMQTransactionalProducer
(
String
nsAddr
,
String
topic
,
TransactionListener
transactionListener
)
{
this
(
nsAddr
,
topic
,
false
,
transactionListener
);
}
public
RMQTransactionalProducer
(
String
nsAddr
,
String
topic
,
boolean
useTLS
,
TransactionListener
transactionListener
)
{
super
(
topic
);
this
.
nsAddr
=
nsAddr
;
create
(
useTLS
,
transactionListener
);
start
();
}
protected
void
create
(
boolean
useTLS
,
TransactionListener
transactionListener
)
{
producer
=
new
TransactionMQProducer
();
producer
.
setProducerGroup
(
getProducerGroupName
());
producer
.
setInstanceName
(
getProducerInstanceName
());
producer
.
setTransactionListener
(
transactionListener
);
producer
.
setUseTLS
(
useTLS
);
if
(
nsAddr
!=
null
)
{
producer
.
setNamesrvAddr
(
nsAddr
);
}
}
public
void
start
()
{
try
{
producer
.
start
();
super
.
setStartSuccess
(
true
);
}
catch
(
MQClientException
e
)
{
super
.
setStartSuccess
(
false
);
logger
.
error
(
e
);
e
.
printStackTrace
();
}
}
@Override
public
ResultWrapper
send
(
Object
msg
,
Object
arg
)
{
boolean
commitMsg
=
((
Pair
<
Boolean
,
LocalTransactionState
>)
arg
).
getObject2
()
==
LocalTransactionState
.
COMMIT_MESSAGE
;
org
.
apache
.
rocketmq
.
client
.
producer
.
SendResult
metaqResult
=
null
;
Message
message
=
(
Message
)
msg
;
try
{
long
start
=
System
.
currentTimeMillis
();
metaqResult
=
producer
.
sendMessageInTransaction
(
message
,
arg
);
this
.
msgRTs
.
addData
(
System
.
currentTimeMillis
()
-
start
);
if
(
isDebug
)
{
logger
.
info
(
metaqResult
);
}
sendResult
.
setMsgId
(
metaqResult
.
getMsgId
());
sendResult
.
setSendResult
(
true
);
sendResult
.
setBrokerIp
(
metaqResult
.
getMessageQueue
().
getBrokerName
());
if
(
commitMsg
)
{
msgBodys
.
addData
(
new
String
(
message
.
getBody
()));
}
originMsgs
.
addData
(
msg
);
originMsgIndex
.
put
(
new
String
(
message
.
getBody
()),
metaqResult
);
}
catch
(
MQClientException
e
)
{
if
(
isDebug
)
{
e
.
printStackTrace
();
}
sendResult
.
setSendResult
(
false
);
sendResult
.
setSendException
(
e
);
errorMsgs
.
addData
(
msg
);
}
return
sendResult
;
}
@Override
public
void
shutdown
()
{
producer
.
shutdown
();
}
}
test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java
浏览文件 @
64e4ca72
...
...
@@ -22,12 +22,14 @@ import java.util.List;
import
org.apache.log4j.Logger
;
import
org.apache.rocketmq.broker.BrokerController
;
import
org.apache.rocketmq.client.producer.TransactionListener
;
import
org.apache.rocketmq.common.MQVersion
;
import
org.apache.rocketmq.namesrv.NamesrvController
;
import
org.apache.rocketmq.remoting.protocol.RemotingCommand
;
import
org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer
;
import
org.apache.rocketmq.test.client.rmq.RMQNormalConsumer
;
import
org.apache.rocketmq.test.client.rmq.RMQNormalProducer
;
import
org.apache.rocketmq.test.client.rmq.RMQTransactionalProducer
;
import
org.apache.rocketmq.test.clientinterface.AbstractMQConsumer
;
import
org.apache.rocketmq.test.clientinterface.AbstractMQProducer
;
import
org.apache.rocketmq.test.factory.ConsumerFactory
;
...
...
@@ -96,6 +98,15 @@ public class BaseConf {
return
producer
;
}
public
static
RMQTransactionalProducer
getTransactionalProducer
(
String
nsAddr
,
String
topic
,
TransactionListener
transactionListener
)
{
RMQTransactionalProducer
producer
=
new
RMQTransactionalProducer
(
nsAddr
,
topic
,
false
,
transactionListener
);
if
(
debug
)
{
producer
.
setDebug
();
}
mqClients
.
add
(
producer
);
return
producer
;
}
public
static
RMQNormalProducer
getProducer
(
String
nsAddr
,
String
topic
,
String
producerGoup
,
String
instanceName
)
{
RMQNormalProducer
producer
=
new
RMQNormalProducer
(
nsAddr
,
topic
,
producerGoup
,
...
...
test/src/test/java/org/apache/rocketmq/test/client/producer/transaction/TransactionalMsgIT.java
0 → 100644
浏览文件 @
64e4ca72
/*
* 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.
*/
package
org.apache.rocketmq.test.client.producer.transaction
;
import
org.apache.log4j.Logger
;
import
org.apache.rocketmq.client.producer.LocalTransactionState
;
import
org.apache.rocketmq.client.producer.TransactionListener
;
import
org.apache.rocketmq.common.Pair
;
import
org.apache.rocketmq.common.message.Message
;
import
org.apache.rocketmq.common.message.MessageExt
;
import
org.apache.rocketmq.test.base.BaseConf
;
import
org.apache.rocketmq.test.client.rmq.RMQNormalConsumer
;
import
org.apache.rocketmq.test.client.rmq.RMQTransactionalProducer
;
import
org.apache.rocketmq.test.factory.MQMessageFactory
;
import
org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListener
;
import
org.apache.rocketmq.test.util.MQWait
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Test
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
java.util.List
;
import
java.util.concurrent.ConcurrentHashMap
;
public
class
TransactionalMsgIT
extends
BaseConf
{
private
static
Logger
logger
=
Logger
.
getLogger
(
TransactionalMsgIT
.
class
);
private
RMQTransactionalProducer
producer
=
null
;
private
RMQNormalConsumer
consumer
=
null
;
private
String
topic
=
null
;
@Before
public
void
setUp
()
{
topic
=
initTopic
();
logger
.
info
(
String
.
format
(
"use topic: %s;"
,
topic
));
producer
=
getTransactionalProducer
(
nsAddr
,
topic
,
new
TransactionListenerImpl
());
consumer
=
getConsumer
(
nsAddr
,
topic
,
"*"
,
new
RMQNormalListener
());
}
@After
public
void
tearDown
()
{
super
.
shutdown
();
}
@Test
public
void
testMessageVisibility
()
throws
Exception
{
Thread
.
sleep
(
3000
);
int
msgSize
=
120
;
List
<
Object
>
msgs
=
MQMessageFactory
.
getMsg
(
topic
,
msgSize
);
for
(
int
i
=
0
;
i
<
msgSize
;
i
++)
{
producer
.
send
(
msgs
.
get
(
i
),
getTransactionHandle
(
i
));
}
boolean
recvAll
=
MQWait
.
waitConsumeAll
(
consumeTime
,
producer
.
getAllMsgBody
(),
consumer
.
getListener
());
assertThat
(
recvAll
).
isEqualTo
(
true
);
}
static
Pair
<
Boolean
,
LocalTransactionState
>
getTransactionHandle
(
int
msgIndex
)
{
switch
(
msgIndex
%
5
)
{
case
0
:
//commit immediately
return
new
Pair
<>(
true
,
LocalTransactionState
.
COMMIT_MESSAGE
);
case
1
:
//rollback immediately
return
new
Pair
<>(
true
,
LocalTransactionState
.
ROLLBACK_MESSAGE
);
case
2
:
//commit in check
return
new
Pair
<>(
false
,
LocalTransactionState
.
COMMIT_MESSAGE
);
case
3
:
//rollback in check
return
new
Pair
<>(
false
,
LocalTransactionState
.
ROLLBACK_MESSAGE
);
case
4
:
default
:
return
new
Pair
<>(
false
,
LocalTransactionState
.
UNKNOW
);
}
}
static
private
class
TransactionListenerImpl
implements
TransactionListener
{
ConcurrentHashMap
<
String
,
LocalTransactionState
>
checkStatus
=
new
ConcurrentHashMap
<>();
@Override
public
LocalTransactionState
executeLocalTransaction
(
Message
msg
,
Object
arg
)
{
Pair
<
Boolean
,
LocalTransactionState
>
transactionHandle
=
(
Pair
<
Boolean
,
LocalTransactionState
>)
arg
;
if
(
transactionHandle
.
getObject1
())
{
return
transactionHandle
.
getObject2
();
}
else
{
checkStatus
.
put
(
msg
.
getTransactionId
(),
transactionHandle
.
getObject2
());
return
LocalTransactionState
.
UNKNOW
;
}
}
@Override
public
LocalTransactionState
checkLocalTransaction
(
MessageExt
msg
)
{
LocalTransactionState
state
=
checkStatus
.
get
(
msg
.
getTransactionId
());
if
(
state
==
null
)
{
return
LocalTransactionState
.
UNKNOW
;
}
else
{
return
state
;
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录