diff --git a/.bazelrc b/.bazelrc
index 7333057fba1..b0c5e1695af 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -24,6 +24,7 @@ build --enable_platform_specific_config
test --action_env=TEST_TMPDIR=/tmp
test --experimental_strict_java_deps=warn
+test --experimental_ui_max_stdouterr_bytes=10485760
build --experimental_strict_java_deps=warn
test --test_output=errors
diff --git a/README.md b/README.md
index 56d253ce1f4..5aaa2ba73c3 100644
--- a/README.md
+++ b/README.md
@@ -49,21 +49,21 @@ $ java -version
java version "1.8.0_121"
```
-For Windows users, click [here](https://dist.apache.org/repos/dist/release/rocketmq/5.1.3/rocketmq-all-5.1.3-bin-release.zip) to download the 5.1.3 RocketMQ binary release,
+For Windows users, click [here](https://dist.apache.org/repos/dist/release/rocketmq/5.1.4/rocketmq-all-5.1.4-bin-release.zip) to download the 5.1.4 RocketMQ binary release,
unpack it to your local disk, such as `D:\rocketmq`.
For macOS and Linux users, execute following commands:
```shell
# Download release from the Apache mirror
-$ wget https://dist.apache.org/repos/dist/release/rocketmq/5.1.3/rocketmq-all-5.1.3-bin-release.zip
+$ wget https://dist.apache.org/repos/dist/release/rocketmq/5.1.4/rocketmq-all-5.1.4-bin-release.zip
# Unpack the release
-$ unzip rocketmq-all-5.1.3-bin-release.zip
+$ unzip rocketmq-all-5.1.4-bin-release.zip
```
Prepare a terminal and change to the extracted `bin` directory:
```shell
-$ cd rocketmq-all-5.1.3-bin-release/bin
+$ cd rocketmq-all-5.1.4-bin-release/bin
```
**1) Start NameServer**
diff --git a/WORKSPACE b/WORKSPACE
index 3126f2d1d5d..c749ba2f26c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -92,6 +92,7 @@ maven_install(
"io.opentelemetry:opentelemetry-exporter-prometheus:1.29.0-alpha",
"io.opentelemetry:opentelemetry-exporter-logging:1.29.0",
"io.opentelemetry:opentelemetry-sdk:1.29.0",
+ "io.opentelemetry:opentelemetry-exporter-logging-otlp:1.29.0",
"com.squareup.okio:okio-jvm:3.0.0",
"io.opentelemetry:opentelemetry-api:1.29.0",
"io.opentelemetry:opentelemetry-sdk-metrics:1.29.0",
@@ -105,7 +106,7 @@ maven_install(
"com.fasterxml.jackson.core:jackson-databind:2.13.4.2",
"com.adobe.testing:s3mock-junit4:2.11.0",
"io.github.aliyunmq:rocketmq-grpc-netty-codec-haproxy:1.0.0",
- "io.github.aliyunmq:rocketmq-rocksdb:1.0.3",
+ "org.apache.rocketmq:rocketmq-rocksdb:1.0.2",
],
fetch_sources = True,
repositories = [
diff --git a/acl/pom.xml b/acl/pom.xml
index 989c0cf77f7..8a296e5ae9e 100644
--- a/acl/pom.xml
+++ b/acl/pom.xml
@@ -13,7 +13,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
rocketmq-acl
rocketmq-acl ${project.version}
diff --git a/broker/BUILD.bazel b/broker/BUILD.bazel
index 6adcdc7b99c..ab413d3d060 100644
--- a/broker/BUILD.bazel
+++ b/broker/BUILD.bazel
@@ -44,6 +44,7 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_exporter_otlp",
"@maven//:io_opentelemetry_opentelemetry_exporter_prometheus",
"@maven//:io_opentelemetry_opentelemetry_exporter_logging",
+ "@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
"@maven//:io_opentelemetry_opentelemetry_sdk",
"@maven//:io_opentelemetry_opentelemetry_sdk_common",
"@maven//:io_opentelemetry_opentelemetry_sdk_metrics",
@@ -53,7 +54,7 @@ java_library(
"@maven//:io_github_aliyunmq_rocketmq_logback_classic",
"@maven//:org_slf4j_jul_to_slf4j",
"@maven//:io_github_aliyunmq_rocketmq_shaded_slf4j_api_bridge",
- "@maven//:io_github_aliyunmq_rocketmq_rocksdb",
+ "@maven//:org_apache_rocketmq_rocketmq_rocksdb",
"@maven//:net_java_dev_jna_jna",
],
)
diff --git a/broker/pom.xml b/broker/pom.xml
index 16e0262766f..add83045dcb 100644
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -13,7 +13,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 30b1d2299a5..9f1fd0ad028 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -16,7 +16,33 @@
*/
package org.apache.rocketmq.broker;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
import com.google.common.collect.Lists;
+
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.plain.PlainAccessValidator;
import org.apache.rocketmq.broker.client.ClientHousekeepingService;
@@ -34,7 +60,6 @@
import org.apache.rocketmq.broker.filter.CommitLogDispatcherCalcBitMap;
import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
import org.apache.rocketmq.broker.latency.BrokerFastFailure;
-import org.apache.rocketmq.broker.latency.BrokerFixedThreadPoolExecutor;
import org.apache.rocketmq.broker.longpolling.LmqPullRequestHoldService;
import org.apache.rocketmq.broker.longpolling.NotifyMessageArrivingListener;
import org.apache.rocketmq.broker.longpolling.PullRequestHoldService;
@@ -98,6 +123,7 @@
import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.common.stats.MomentStatsItem;
import org.apache.rocketmq.common.utils.ServiceProvider;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.Configuration;
@@ -126,7 +152,7 @@
import org.apache.rocketmq.store.MessageArrivingListener;
import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.PutMessageResult;
-import org.apache.rocketmq.store.StoreType;
+import org.apache.rocketmq.store.RocksDBMessageStore;
import org.apache.rocketmq.store.config.BrokerRole;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.dledger.DLedgerCommitLog;
@@ -141,32 +167,6 @@
import org.apache.rocketmq.store.timer.TimerMessageStore;
import org.apache.rocketmq.store.timer.TimerMetrics;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
public class BrokerController {
protected static final Logger LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private static final Logger LOG_PROTECTION = LoggerFactory.getLogger(LoggerName.PROTECTION_LOGGER_NAME);
@@ -309,7 +309,7 @@ public BrokerController(
this.setStoreHost(new InetSocketAddress(this.getBrokerConfig().getBrokerIP1(), getListenPort()));
this.brokerStatsManager = messageStoreConfig.isEnableLmq() ? new LmqBrokerStatsManager(this.brokerConfig.getBrokerClusterName(), this.brokerConfig.isEnableDetailStat()) : new BrokerStatsManager(this.brokerConfig.getBrokerClusterName(), this.brokerConfig.isEnableDetailStat());
this.broadcastOffsetManager = new BroadcastOffsetManager(this);
- if (isEnableRocksDBStore()) {
+ if (this.messageStoreConfig.isEnableRocksDBStore()) {
this.topicConfigManager = messageStoreConfig.isEnableLmq() ? new RocksDBLmqTopicConfigManager(this) : new RocksDBTopicConfigManager(this);
this.subscriptionGroupManager = messageStoreConfig.isEnableLmq() ? new RocksDBLmqSubscriptionGroupManager(this) : new RocksDBSubscriptionGroupManager(this);
this.consumerOffsetManager = messageStoreConfig.isEnableLmq() ? new RocksDBLmqConsumerOffsetManager(this) : new RocksDBConsumerOffsetManager(this);
@@ -455,10 +455,10 @@ protected void initializeRemotingServer() throws CloneNotSupportedException {
* Initialize resources including remoting server and thread executors.
*/
protected void initializeResources() {
- this.scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ this.scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("BrokerControllerScheduledThread", true, getBrokerIdentity()));
- this.sendMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.sendMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getSendMessageThreadPoolNums(),
this.brokerConfig.getSendMessageThreadPoolNums(),
1000 * 60,
@@ -466,7 +466,7 @@ protected void initializeResources() {
this.sendThreadPoolQueue,
new ThreadFactoryImpl("SendMessageThread_", getBrokerIdentity()));
- this.pullMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.pullMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getPullMessageThreadPoolNums(),
this.brokerConfig.getPullMessageThreadPoolNums(),
1000 * 60,
@@ -474,7 +474,7 @@ protected void initializeResources() {
this.pullThreadPoolQueue,
new ThreadFactoryImpl("PullMessageThread_", getBrokerIdentity()));
- this.litePullMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.litePullMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getLitePullMessageThreadPoolNums(),
this.brokerConfig.getLitePullMessageThreadPoolNums(),
1000 * 60,
@@ -482,7 +482,7 @@ protected void initializeResources() {
this.litePullThreadPoolQueue,
new ThreadFactoryImpl("LitePullMessageThread_", getBrokerIdentity()));
- this.putMessageFutureExecutor = new BrokerFixedThreadPoolExecutor(
+ this.putMessageFutureExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getPutMessageFutureThreadPoolNums(),
this.brokerConfig.getPutMessageFutureThreadPoolNums(),
1000 * 60,
@@ -490,7 +490,7 @@ protected void initializeResources() {
this.putThreadPoolQueue,
new ThreadFactoryImpl("SendMessageThread_", getBrokerIdentity()));
- this.ackMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.ackMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getAckMessageThreadPoolNums(),
this.brokerConfig.getAckMessageThreadPoolNums(),
1000 * 60,
@@ -498,7 +498,7 @@ protected void initializeResources() {
this.ackThreadPoolQueue,
new ThreadFactoryImpl("AckMessageThread_", getBrokerIdentity()));
- this.queryMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.queryMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getQueryMessageThreadPoolNums(),
this.brokerConfig.getQueryMessageThreadPoolNums(),
1000 * 60,
@@ -506,7 +506,7 @@ protected void initializeResources() {
this.queryThreadPoolQueue,
new ThreadFactoryImpl("QueryMessageThread_", getBrokerIdentity()));
- this.adminBrokerExecutor = new BrokerFixedThreadPoolExecutor(
+ this.adminBrokerExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getAdminBrokerThreadPoolNums(),
this.brokerConfig.getAdminBrokerThreadPoolNums(),
1000 * 60,
@@ -514,7 +514,7 @@ protected void initializeResources() {
this.adminBrokerThreadPoolQueue,
new ThreadFactoryImpl("AdminBrokerThread_", getBrokerIdentity()));
- this.clientManageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.clientManageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getClientManageThreadPoolNums(),
this.brokerConfig.getClientManageThreadPoolNums(),
1000 * 60,
@@ -522,7 +522,7 @@ protected void initializeResources() {
this.clientManagerThreadPoolQueue,
new ThreadFactoryImpl("ClientManageThread_", getBrokerIdentity()));
- this.heartbeatExecutor = new BrokerFixedThreadPoolExecutor(
+ this.heartbeatExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getHeartbeatThreadPoolNums(),
this.brokerConfig.getHeartbeatThreadPoolNums(),
1000 * 60,
@@ -530,7 +530,7 @@ protected void initializeResources() {
this.heartbeatThreadPoolQueue,
new ThreadFactoryImpl("HeartbeatThread_", true, getBrokerIdentity()));
- this.consumerManageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.consumerManageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getConsumerManageThreadPoolNums(),
this.brokerConfig.getConsumerManageThreadPoolNums(),
1000 * 60,
@@ -538,7 +538,7 @@ protected void initializeResources() {
this.consumerManagerThreadPoolQueue,
new ThreadFactoryImpl("ConsumerManageThread_", true, getBrokerIdentity()));
- this.replyMessageExecutor = new BrokerFixedThreadPoolExecutor(
+ this.replyMessageExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getProcessReplyMessageThreadPoolNums(),
this.brokerConfig.getProcessReplyMessageThreadPoolNums(),
1000 * 60,
@@ -546,7 +546,7 @@ protected void initializeResources() {
this.replyThreadPoolQueue,
new ThreadFactoryImpl("ProcessReplyMessageThread_", getBrokerIdentity()));
- this.endTransactionExecutor = new BrokerFixedThreadPoolExecutor(
+ this.endTransactionExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getEndTransactionThreadPoolNums(),
this.brokerConfig.getEndTransactionThreadPoolNums(),
1000 * 60,
@@ -554,7 +554,7 @@ protected void initializeResources() {
this.endTransactionThreadPoolQueue,
new ThreadFactoryImpl("EndTransactionThread_", getBrokerIdentity()));
- this.loadBalanceExecutor = new BrokerFixedThreadPoolExecutor(
+ this.loadBalanceExecutor = ThreadUtils.newThreadPoolExecutor(
this.brokerConfig.getLoadBalanceProcessorThreadPoolNums(),
this.brokerConfig.getLoadBalanceProcessorThreadPoolNums(),
1000 * 60,
@@ -562,9 +562,9 @@ protected void initializeResources() {
this.loadBalanceThreadPoolQueue,
new ThreadFactoryImpl("LoadBalanceProcessorThread_", getBrokerIdentity()));
- this.syncBrokerMemberGroupExecutorService = new ScheduledThreadPoolExecutor(1,
+ this.syncBrokerMemberGroupExecutorService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("BrokerControllerSyncBrokerScheduledThread", getBrokerIdentity()));
- this.brokerHeartbeatExecutorService = new ScheduledThreadPoolExecutor(1,
+ this.brokerHeartbeatExecutorService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("BrokerControllerHeartbeatScheduledThread", getBrokerIdentity()));
this.topicQueueMappingCleanService = new TopicQueueMappingCleanService(this);
@@ -663,7 +663,7 @@ public void run() {
BrokerController.this.getSlaveSynchronize().syncAll();
lastSyncTimeMs = System.currentTimeMillis();
}
-
+
//timer checkpoint, latency-sensitive, so sync it more frequently
if (messageStoreConfig.isTimerWheelEnable()) {
BrokerController.this.getSlaveSynchronize().syncTimerCheckPoint();
@@ -698,17 +698,6 @@ protected void initializeScheduledTasks() {
initializeBrokerScheduledTasks();
- this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
- @Override
- public void run() {
- try {
- BrokerController.this.brokerOuterAPI.refreshMetadata();
- } catch (Exception e) {
- LOG.error("ScheduledTask refresh metadata exception", e);
- }
- }
- }, 10, 5, TimeUnit.SECONDS);
-
if (this.brokerConfig.getNamesrvAddr() != null) {
this.updateNamesrvAddr();
LOG.info("Set user specified name server address: {}", this.brokerConfig.getNamesrvAddr());
@@ -759,7 +748,12 @@ public boolean initializeMetadata() {
public boolean initializeMessageStore() {
boolean result = true;
try {
- DefaultMessageStore defaultMessageStore = new DefaultMessageStore(this.messageStoreConfig, this.brokerStatsManager, this.messageArrivingListener, this.brokerConfig, topicConfigManager.getTopicConfigTable());
+ DefaultMessageStore defaultMessageStore;
+ if (this.messageStoreConfig.isEnableRocksDBStore()) {
+ defaultMessageStore = new RocksDBMessageStore(this.messageStoreConfig, this.brokerStatsManager, this.messageArrivingListener, this.brokerConfig, topicConfigManager.getTopicConfigTable());
+ } else {
+ defaultMessageStore = new DefaultMessageStore(this.messageStoreConfig, this.brokerStatsManager, this.messageArrivingListener, this.brokerConfig, topicConfigManager.getTopicConfigTable());
+ }
if (messageStoreConfig.isEnableDLegerCommitLog()) {
DLedgerRoleChangeHandler roleChangeHandler =
@@ -956,16 +950,16 @@ private void initialTransaction() {
this.transactionalMessageService = ServiceProvider.loadClass(TransactionalMessageService.class);
if (null == this.transactionalMessageService) {
this.transactionalMessageService = new TransactionalMessageServiceImpl(
- new TransactionalMessageBridge(this, this.getMessageStore()));
+ new TransactionalMessageBridge(this, this.getMessageStore()));
LOG.warn("Load default transaction message hook service: {}",
- TransactionalMessageServiceImpl.class.getSimpleName());
+ TransactionalMessageServiceImpl.class.getSimpleName());
}
this.transactionalMessageCheckListener = ServiceProvider.loadClass(
- AbstractTransactionalMessageCheckListener.class);
+ AbstractTransactionalMessageCheckListener.class);
if (null == this.transactionalMessageCheckListener) {
this.transactionalMessageCheckListener = new DefaultTransactionalMessageCheckListener();
LOG.warn("Load default discard message hook service: {}",
- DefaultTransactionalMessageCheckListener.class.getSimpleName());
+ DefaultTransactionalMessageCheckListener.class.getSimpleName());
}
this.transactionalMessageCheckListener.setBrokerController(this);
this.transactionalMessageCheckService = new TransactionalMessageCheckService(this);
@@ -1194,6 +1188,7 @@ public void printWaterMark() {
LOG_WATER_MARK.info("[WATERMARK] ClientManager Queue Size: {} SlowTimeMills: {}", this.clientManagerThreadPoolQueue.size(), this.headSlowTimeMills(this.clientManagerThreadPoolQueue));
LOG_WATER_MARK.info("[WATERMARK] Heartbeat Queue Size: {} SlowTimeMills: {}", this.heartbeatThreadPoolQueue.size(), this.headSlowTimeMills(this.heartbeatThreadPoolQueue));
LOG_WATER_MARK.info("[WATERMARK] Ack Queue Size: {} SlowTimeMills: {}", this.ackThreadPoolQueue.size(), headSlowTimeMills(this.ackThreadPoolQueue));
+ LOG_WATER_MARK.info("[WATERMARK] Admin Queue Size: {} SlowTimeMills: {}", this.adminBrokerThreadPoolQueue.size(), headSlowTimeMills(this.adminBrokerThreadPoolQueue));
}
public MessageStore getMessageStore() {
@@ -1313,6 +1308,10 @@ protected void shutdownBasicService() {
this.fastRemotingServer.shutdown();
}
+ if (this.brokerMetricsManager != null) {
+ this.brokerMetricsManager.shutdown();
+ }
+
if (this.brokerStatsManager != null) {
this.brokerStatsManager.shutdown();
}
@@ -1335,6 +1334,10 @@ protected void shutdownBasicService() {
this.ackMessageProcessor.shutdownPopReviveService();
}
+ if (this.transactionalMessageService != null) {
+ this.transactionalMessageService.close();
+ }
+
if (this.notificationProcessor != null) {
this.notificationProcessor.getPopLongPollingService().shutdown();
}
@@ -1682,6 +1685,17 @@ public void run0() {
if (brokerConfig.isSkipPreOnline()) {
startServiceWithoutCondition();
}
+
+ this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ BrokerController.this.brokerOuterAPI.refreshMetadata();
+ } catch (Exception e) {
+ LOG.error("ScheduledTask refresh metadata exception", e);
+ }
+ }
+ }, 10, 5, TimeUnit.SECONDS);
}
protected void scheduleSendHeartbeat() {
@@ -1733,7 +1747,8 @@ public synchronized void registerIncrementBrokerData(List topicConf
new TopicConfig(topicConfig.getTopicName(),
topicConfig.getReadQueueNums(),
topicConfig.getWriteQueueNums(),
- this.brokerConfig.getBrokerPermission(), topicConfig.getTopicSysFlag());
+ topicConfig.getPerm()
+ & this.brokerConfig.getBrokerPermission(), topicConfig.getTopicSysFlag());
} else {
registerTopicConfig = new TopicConfig(topicConfig);
}
@@ -1757,29 +1772,34 @@ public synchronized void registerIncrementBrokerData(List topicConf
}
public synchronized void registerBrokerAll(final boolean checkOrderConfig, boolean oneway, boolean forceRegister) {
+ ConcurrentMap topicConfigMap = this.getTopicConfigManager().getTopicConfigTable();
+ ConcurrentHashMap topicConfigTable = new ConcurrentHashMap<>();
- TopicConfigAndMappingSerializeWrapper topicConfigWrapper = new TopicConfigAndMappingSerializeWrapper();
-
- topicConfigWrapper.setDataVersion(this.getTopicConfigManager().getDataVersion());
- topicConfigWrapper.setTopicConfigTable(this.getTopicConfigManager().getTopicConfigTable());
-
- topicConfigWrapper.setTopicQueueMappingInfoMap(this.getTopicQueueMappingManager().getTopicQueueMappingTable().entrySet().stream().map(
- entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), TopicQueueMappingDetail.cloneAsMappingInfo(entry.getValue()))
- ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
-
- if (!PermName.isWriteable(this.getBrokerConfig().getBrokerPermission())
- || !PermName.isReadable(this.getBrokerConfig().getBrokerPermission())) {
- ConcurrentHashMap topicConfigTable = new ConcurrentHashMap<>();
- for (TopicConfig topicConfig : topicConfigWrapper.getTopicConfigTable().values()) {
- TopicConfig tmp =
+ for (TopicConfig topicConfig : topicConfigMap.values()) {
+ if (!PermName.isWriteable(this.getBrokerConfig().getBrokerPermission())
+ || !PermName.isReadable(this.getBrokerConfig().getBrokerPermission())) {
+ topicConfigTable.put(topicConfig.getTopicName(),
new TopicConfig(topicConfig.getTopicName(), topicConfig.getReadQueueNums(), topicConfig.getWriteQueueNums(),
- topicConfig.getPerm() & this.brokerConfig.getBrokerPermission(), topicConfig.getTopicSysFlag());
- topicConfigTable.put(topicConfig.getTopicName(), tmp);
+ topicConfig.getPerm() & getBrokerConfig().getBrokerPermission()));
+ } else {
+ topicConfigTable.put(topicConfig.getTopicName(), topicConfig);
+ }
+
+ if (this.brokerConfig.isEnableSplitRegistration()
+ && topicConfigTable.size() >= this.brokerConfig.getSplitRegistrationSize()) {
+ TopicConfigAndMappingSerializeWrapper topicConfigWrapper = this.getTopicConfigManager().buildSerializeWrapper(topicConfigTable);
+ doRegisterBrokerAll(checkOrderConfig, oneway, topicConfigWrapper);
+ topicConfigTable.clear();
}
- topicConfigWrapper.setTopicConfigTable(topicConfigTable);
}
- if (forceRegister || needRegister(this.brokerConfig.getBrokerClusterName(),
+ Map topicQueueMappingInfoMap = this.getTopicQueueMappingManager().getTopicQueueMappingTable().entrySet().stream()
+ .map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), TopicQueueMappingDetail.cloneAsMappingInfo(entry.getValue())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+ TopicConfigAndMappingSerializeWrapper topicConfigWrapper = this.getTopicConfigManager().
+ buildSerializeWrapper(topicConfigTable, topicQueueMappingInfoMap);
+ if (this.brokerConfig.isEnableSplitRegistration() || forceRegister || needRegister(this.brokerConfig.getBrokerClusterName(),
this.getBrokerAddr(),
this.brokerConfig.getBrokerName(),
this.brokerConfig.getBrokerId(),
@@ -1793,7 +1813,7 @@ protected void doRegisterBrokerAll(boolean checkOrderConfig, boolean oneway,
TopicConfigSerializeWrapper topicConfigWrapper) {
if (shutdown) {
- BrokerController.LOG.info("BrokerController#doResterBrokerAll: broker has shutdown, no need to register any more.");
+ BrokerController.LOG.info("BrokerController#doRegisterBrokerAll: broker has shutdown, no need to register any more.");
return;
}
List registerBrokerResultList = this.brokerOuterAPI.registerBrokerAll(
@@ -2398,8 +2418,4 @@ public ColdDataCgCtrService getColdDataCgCtrService() {
public void setColdDataCgCtrService(ColdDataCgCtrService coldDataCgCtrService) {
this.coldDataCgCtrService = coldDataCgCtrService;
}
-
- public boolean isEnableRocksDBStore() {
- return StoreType.DEFAULT_ROCKSDB.getStoreType().equalsIgnoreCase(this.messageStoreConfig.getStoreType());
- }
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
index 98e5f450f3f..cbb81f632b4 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
@@ -18,11 +18,11 @@
import io.netty.channel.Channel;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.ChannelEventListener;
@@ -35,7 +35,7 @@ public class ClientHousekeepingService implements ChannelEventListener {
public ClientHousekeepingService(final BrokerController brokerController) {
this.brokerController = brokerController;
- scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("ClientHousekeepingScheduledThread", brokerController.getBrokerIdentity()));
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
index 2ce036a0ffc..d17a2a5470c 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
@@ -22,7 +22,6 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.AbstractBrokerRunnable;
@@ -37,7 +36,7 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen
private final BrokerController brokerController;
private final int cacheSize = 8096;
- private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ private final ScheduledExecutorService scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
ThreadUtils.newGenericThreadFactory("DefaultConsumerIdsChangeListener", true));
private ConcurrentHashMap> consumerChannelMap = new ConcurrentHashMap<>(cacheSize);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/controller/ReplicasManager.java b/broker/src/main/java/org/apache/rocketmq/broker/controller/ReplicasManager.java
index abae7cdb01a..a1d711cb275 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/controller/ReplicasManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/controller/ReplicasManager.java
@@ -27,10 +27,8 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
@@ -42,6 +40,7 @@
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.EpochEntry;
@@ -107,9 +106,9 @@ public class ReplicasManager {
public ReplicasManager(final BrokerController brokerController) {
this.brokerController = brokerController;
this.brokerOuterAPI = brokerController.getBrokerOuterAPI();
- this.scheduledService = Executors.newScheduledThreadPool(3, new ThreadFactoryImpl("ReplicasManager_ScheduledService_", brokerController.getBrokerIdentity()));
- this.executorService = Executors.newFixedThreadPool(3, new ThreadFactoryImpl("ReplicasManager_ExecutorService_", brokerController.getBrokerIdentity()));
- this.scanExecutor = new ThreadPoolExecutor(4, 10, 60, TimeUnit.SECONDS,
+ this.scheduledService = ThreadUtils.newScheduledThreadPool(3, new ThreadFactoryImpl("ReplicasManager_ScheduledService_", brokerController.getBrokerIdentity()));
+ this.executorService = ThreadUtils.newThreadPoolExecutor(3, new ThreadFactoryImpl("ReplicasManager_ExecutorService_", brokerController.getBrokerIdentity()));
+ this.scanExecutor = ThreadUtils.newThreadPoolExecutor(4, 10, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(32), new ThreadFactoryImpl("ReplicasManager_scan_thread_", brokerController.getBrokerIdentity()));
this.haService = (AutoSwitchHAService) brokerController.getMessageStore().getHaService();
this.brokerConfig = brokerController.getBrokerConfig();
@@ -225,7 +224,7 @@ public void shutdown() {
public synchronized void changeBrokerRole(final Long newMasterBrokerId, final String newMasterAddress,
final Integer newMasterEpoch,
- final Integer syncStateSetEpoch, final Set syncStateSet) {
+ final Integer syncStateSetEpoch, final Set syncStateSet) throws Exception {
if (newMasterBrokerId != null && newMasterEpoch > this.masterEpoch) {
if (newMasterBrokerId.equals(this.brokerControllerId)) {
changeToMaster(newMasterEpoch, syncStateSetEpoch, syncStateSet);
@@ -235,7 +234,7 @@ public synchronized void changeBrokerRole(final Long newMasterBrokerId, final St
}
}
- public void changeToMaster(final int newMasterEpoch, final int syncStateSetEpoch, final Set syncStateSet) {
+ public void changeToMaster(final int newMasterEpoch, final int syncStateSetEpoch, final Set syncStateSet) throws Exception {
synchronized (this) {
if (newMasterEpoch > this.masterEpoch) {
LOGGER.info("Begin to change to master, brokerName:{}, replicas:{}, new Epoch:{}", this.brokerConfig.getBrokerName(), this.brokerAddress, newMasterEpoch);
@@ -542,7 +541,7 @@ private boolean createMetadataFileAndDeleteTemp() {
this.brokerMetadata.updateAndPersist(brokerConfig.getBrokerClusterName(), brokerConfig.getBrokerName(), tempBrokerMetadata.getBrokerId());
this.tempBrokerMetadata.clear();
this.brokerControllerId = this.brokerMetadata.getBrokerId();
- this.haService.setBrokerControllerId(this.brokerControllerId);
+ this.haService.setLocalBrokerId(this.brokerControllerId);
return true;
} catch (Exception e) {
LOGGER.error("fail to create metadata file", e);
@@ -594,7 +593,7 @@ private void confirmNowRegisteringState() {
if (this.brokerMetadata.isLoaded()) {
this.registerState = RegisterState.CREATE_METADATA_FILE_DONE;
this.brokerControllerId = brokerMetadata.getBrokerId();
- this.haService.setBrokerControllerId(this.brokerControllerId);
+ this.haService.setLocalBrokerId(this.brokerControllerId);
return;
}
// 2. check if temp metadata exist
@@ -735,23 +734,26 @@ private void schedulingCheckSyncStateSet() {
if (this.checkSyncStateSetTaskFuture != null) {
this.checkSyncStateSetTaskFuture.cancel(false);
}
- this.checkSyncStateSetTaskFuture = this.scheduledService.scheduleAtFixedRate(() -> {
- checkSyncStateSetAndDoReport();
- }, 3 * 1000, this.brokerConfig.getCheckSyncStateSetPeriod(), TimeUnit.MILLISECONDS);
+ this.checkSyncStateSetTaskFuture = this.scheduledService.scheduleAtFixedRate(this::checkSyncStateSetAndDoReport, 3 * 1000,
+ this.brokerConfig.getCheckSyncStateSetPeriod(), TimeUnit.MILLISECONDS);
}
private void checkSyncStateSetAndDoReport() {
- final Set newSyncStateSet = this.haService.maybeShrinkSyncStateSet();
- newSyncStateSet.add(this.brokerControllerId);
- synchronized (this) {
- if (this.syncStateSet != null) {
- // Check if syncStateSet changed
- if (this.syncStateSet.size() == newSyncStateSet.size() && this.syncStateSet.containsAll(newSyncStateSet)) {
- return;
+ try {
+ final Set newSyncStateSet = this.haService.maybeShrinkSyncStateSet();
+ newSyncStateSet.add(this.brokerControllerId);
+ synchronized (this) {
+ if (this.syncStateSet != null) {
+ // Check if syncStateSet changed
+ if (this.syncStateSet.size() == newSyncStateSet.size() && this.syncStateSet.containsAll(newSyncStateSet)) {
+ return;
+ }
}
}
+ doReportSyncStateSetChanged(newSyncStateSet);
+ } catch (Exception e) {
+ LOGGER.error("Check syncStateSet error", e);
}
- doReportSyncStateSetChanged(newSyncStateSet);
}
private void doReportSyncStateSetChanged(Set newSyncStateSet) {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java b/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java
index 75023ee1b8b..e6cb97640bd 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java
@@ -21,12 +21,12 @@
import io.openmessaging.storage.dledger.MemberState;
import io.openmessaging.storage.dledger.utils.DLedgerUtils;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.store.DefaultMessageStore;
@@ -49,7 +49,7 @@ public DLedgerRoleChangeHandler(BrokerController brokerController, DefaultMessag
this.messageStore = messageStore;
this.dLedgerCommitLog = (DLedgerCommitLog) messageStore.getCommitLog();
this.dLegerServer = dLedgerCommitLog.getdLedgerServer();
- this.executorService = Executors.newSingleThreadExecutor(
+ this.executorService = ThreadUtils.newSingleThreadExecutor(
new ThreadFactoryImpl("DLegerRoleChangeHandler_", brokerController.getBrokerIdentity()));
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/failover/EscapeBridge.java b/broker/src/main/java/org/apache/rocketmq/broker/failover/EscapeBridge.java
index 7c350fc1d7d..6a081748014 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/failover/EscapeBridge.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/failover/EscapeBridge.java
@@ -24,7 +24,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.broker.BrokerController;
@@ -43,6 +42,7 @@
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.exception.RemotingException;
@@ -72,7 +72,7 @@ public EscapeBridge(BrokerController brokerController) {
public void start() throws Exception {
if (brokerController.getBrokerConfig().isEnableSlaveActingMaster() && brokerController.getBrokerConfig().isEnableRemoteEscape()) {
final BlockingQueue asyncSenderThreadPoolQueue = new LinkedBlockingQueue<>(50000);
- this.defaultAsyncSenderExecutor = new ThreadPoolExecutor(
+ this.defaultAsyncSenderExecutor = ThreadUtils.newThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
1000 * 60,
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFastFailure.java b/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFastFailure.java
index d3d0bc8ba3a..3b6e9dc676e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFastFailure.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFastFailure.java
@@ -18,13 +18,14 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.AbstractBrokerRunnable;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.future.FutureTaskExt;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.netty.RequestTask;
@@ -43,7 +44,7 @@ public class BrokerFastFailure {
public BrokerFastFailure(final BrokerController brokerController) {
this.brokerController = brokerController;
- this.scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ this.scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("BrokerFastFailureScheduledThread", true,
brokerController == null ? null : brokerController.getBrokerConfig()));
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFixedThreadPoolExecutor.java b/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFixedThreadPoolExecutor.java
deleted file mode 100644
index d2d1143a348..00000000000
--- a/broker/src/main/java/org/apache/rocketmq/broker/latency/BrokerFixedThreadPoolExecutor.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.broker.latency;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.RunnableFuture;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-public class BrokerFixedThreadPoolExecutor extends ThreadPoolExecutor {
- public BrokerFixedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime,
- final TimeUnit unit,
- final BlockingQueue workQueue) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
- }
-
- public BrokerFixedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime,
- final TimeUnit unit,
- final BlockingQueue workQueue, final ThreadFactory threadFactory) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
- }
-
- public BrokerFixedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime,
- final TimeUnit unit,
- final BlockingQueue workQueue, final RejectedExecutionHandler handler) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
- }
-
- public BrokerFixedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime,
- final TimeUnit unit,
- final BlockingQueue workQueue, final ThreadFactory threadFactory,
- final RejectedExecutionHandler handler) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
- }
-
- @Override
- protected RunnableFuture newTaskFor(final Runnable runnable, final T value) {
- return new FutureTaskExt<>(runnable, value);
- }
-}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsManager.java b/broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsManager.java
index 6af5afc1413..39af18b9faa 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsManager.java
@@ -23,7 +23,7 @@
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableLongGauge;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
+import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
@@ -36,6 +36,7 @@
import io.opentelemetry.sdk.metrics.View;
import io.opentelemetry.sdk.metrics.ViewBuilder;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
import io.opentelemetry.sdk.resources.Resource;
@@ -113,7 +114,7 @@ public class BrokerMetricsManager {
private OtlpGrpcMetricExporter metricExporter;
private PeriodicMetricReader periodicMetricReader;
private PrometheusHttpServer prometheusHttpServer;
- private LoggingMetricExporter loggingMetricExporter;
+ private MetricExporter loggingMetricExporter;
private Meter brokerMeter;
public static Supplier attributesBuilderSupplier = Attributes::builder;
@@ -327,8 +328,8 @@ private void init() {
if (metricsExporterType == MetricsExporterType.LOG) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
- loggingMetricExporter = LoggingMetricExporter.create(brokerConfig.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
- java.util.logging.Logger.getLogger(LoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
+ loggingMetricExporter = OtlpJsonLoggingMetricExporter.create(brokerConfig.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
+ java.util.logging.Logger.getLogger(OtlpJsonLoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
periodicMetricReader = PeriodicMetricReader.builder(loggingMetricExporter)
.setInterval(brokerConfig.getMetricLoggingExporterIntervalInMills(), TimeUnit.MILLISECONDS)
.build();
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/RocksDBConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/RocksDBConsumerOffsetManager.java
index 5695a335624..05b53b0bcf2 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/offset/RocksDBConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/RocksDBConsumerOffsetManager.java
@@ -33,7 +33,7 @@ public class RocksDBConsumerOffsetManager extends ConsumerOffsetManager {
public RocksDBConsumerOffsetManager(BrokerController brokerController) {
super(brokerController);
- this.rocksDBConfigManager = new RocksDBConfigManager(this.brokerController.getMessageStoreConfig().getMemTableFlushInterval());
+ this.rocksDBConfigManager = new RocksDBConfigManager(brokerController.getMessageStoreConfig().getMemTableFlushIntervalMs());
}
@Override
@@ -49,7 +49,7 @@ public boolean stop() {
@Override
protected void removeConsumerOffset(String topicAtGroup) {
try {
- byte[] keyBytes = topicAtGroup.getBytes(DataConverter.charset);
+ byte[] keyBytes = topicAtGroup.getBytes(DataConverter.CHARSET_UTF8);
this.rocksDBConfigManager.delete(keyBytes);
} catch (Exception e) {
LOG.error("kv remove consumerOffset Failed, {}", topicAtGroup);
@@ -58,7 +58,7 @@ protected void removeConsumerOffset(String topicAtGroup) {
@Override
protected void decode0(final byte[] key, final byte[] body) {
- String topicAtGroup = new String(key, DataConverter.charset);
+ String topicAtGroup = new String(key, DataConverter.CHARSET_UTF8);
RocksDBOffsetSerializeWrapper wrapper = JSON.parseObject(body, RocksDBOffsetSerializeWrapper.class);
this.offsetTable.put(topicAtGroup, wrapper.getOffsetTable());
@@ -93,7 +93,7 @@ public synchronized void persist() {
}
private void putWriteBatch(final WriteBatch writeBatch, final String topicGroupName, final ConcurrentMap offsetMap) throws Exception {
- byte[] keyBytes = topicGroupName.getBytes(DataConverter.charset);
+ byte[] keyBytes = topicGroupName.getBytes(DataConverter.CHARSET_UTF8);
RocksDBOffsetSerializeWrapper wrapper = new RocksDBOffsetSerializeWrapper();
wrapper.setOffsetTable(offsetMap);
byte[] valueBytes = JSON.toJSONBytes(wrapper, SerializerFeature.BrowserCompatible);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index ae81e8b11df..6fde48dd995 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -27,9 +27,9 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
-import org.apache.rocketmq.broker.latency.BrokerFixedThreadPoolExecutor;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.client.exception.MQBrokerException;
@@ -59,6 +59,7 @@
import org.apache.rocketmq.common.namesrv.TopAddressing;
import org.apache.rocketmq.common.sysflag.PullSysFlag;
import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.InvokeCallback;
@@ -72,6 +73,7 @@
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.ResponseFuture;
import org.apache.rocketmq.remoting.protocol.BrokerSyncInfo;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -106,6 +108,8 @@
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeaderV2;
import org.apache.rocketmq.remoting.protocol.header.SendMessageResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.AlterSyncStateSetRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetReplicaInfoRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetReplicaInfoResponseHeader;
@@ -123,8 +127,6 @@
import org.apache.rocketmq.remoting.protocol.header.namesrv.RegisterBrokerResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.RegisterTopicRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.UnRegisterBrokerRequestHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterRequestHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.remoting.protocol.namesrv.RegisterBrokerResult;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
@@ -144,13 +146,12 @@ public class BrokerOuterAPI {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private final RemotingClient remotingClient;
private final TopAddressing topAddressing = new DefaultTopAddressing(MixAll.getWSAddr());
- private final BrokerFixedThreadPoolExecutor brokerOuterExecutor = new BrokerFixedThreadPoolExecutor(4, 10, 1, TimeUnit.MINUTES,
+ private final ExecutorService brokerOuterExecutor = ThreadUtils.newThreadPoolExecutor(4, 10, 1, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(32), new ThreadFactoryImpl("brokerOutApi_thread_", true));
private final ClientMetadata clientMetadata;
private final RpcClient rpcClient;
private String nameSrvAddr = null;
-
public BrokerOuterAPI(final NettyClientConfig nettyClientConfig) {
this(nettyClientConfig, new DynamicalExtFieldRPCHook(), new ClientMetadata());
}
@@ -458,7 +459,7 @@ public List registerBrokerAll(
* @param filterServerList
* @param oneway
* @param timeoutMills
- * @param compressed default false
+ * @param compressed default false
* @return
*/
public List registerBrokerAll(
@@ -642,7 +643,6 @@ public void registerSingleTopicAll(
queueDatas.add(queueData);
final byte[] topicRouteBody = topicRouteData.encode();
-
List nameServerAddressList = this.remotingClient.getNameServerAddressList();
final CountDownLatch countDownLatch = new CountDownLatch(nameServerAddressList.size());
for (final String namesrvAddr : nameServerAddressList) {
@@ -909,25 +909,33 @@ public void lockBatchMQAsync(
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.LOCK_BATCH_MQ, null);
request.setBody(requestBody.encode());
- this.remotingClient.invokeAsync(addr, request, timeoutMillis, responseFuture -> {
- if (callback == null) {
- return;
+ this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
}
- try {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- if (response.getCode() == ResponseCode.SUCCESS) {
- LockBatchResponseBody responseBody = LockBatchResponseBody.decode(response.getBody(),
- LockBatchResponseBody.class);
- Set messageQueues = responseBody.getLockOKMQSet();
- callback.onSuccess(messageQueues);
- } else {
- callback.onException(new MQBrokerException(response.getCode(), response.getRemark()));
- }
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ if (callback == null) {
+ return;
}
- } catch (Throwable ignored) {
+ if (response.getCode() == ResponseCode.SUCCESS) {
+ LockBatchResponseBody responseBody = LockBatchResponseBody.decode(response.getBody(),
+ LockBatchResponseBody.class);
+ Set messageQueues = responseBody.getLockOKMQSet();
+ callback.onSuccess(messageQueues);
+ } else {
+ callback.onException(new MQBrokerException(response.getCode(), response.getRemark()));
+ }
+ }
+ @Override
+ public void operationFail(Throwable throwable) {
+ if (callback == null) {
+ return;
+ }
+ callback.onException(throwable);
}
});
}
@@ -941,22 +949,30 @@ public void unlockBatchMQAsync(
request.setBody(requestBody.encode());
- this.remotingClient.invokeAsync(addr, request, timeoutMillis, responseFuture -> {
- if (callback == null) {
- return;
+ this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
}
- try {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- if (response.getCode() == ResponseCode.SUCCESS) {
- callback.onSuccess();
- } else {
- callback.onException(new MQBrokerException(response.getCode(), response.getRemark()));
- }
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ if (callback == null) {
+ return;
}
- } catch (Throwable ignored) {
+ if (response.getCode() == ResponseCode.SUCCESS) {
+ callback.onSuccess();
+ } else {
+ callback.onException(new MQBrokerException(response.getCode(), response.getRemark()));
+ }
+ }
+ @Override
+ public void operationFail(Throwable throwable) {
+ if (callback == null) {
+ return;
+ }
+ callback.onException(throwable);
}
});
}
@@ -982,21 +998,27 @@ public CompletableFuture sendMessageToSpecificBrokerAsync(String bro
CompletableFuture cf = new CompletableFuture<>();
final String msgId = msg.getMsgId();
try {
- this.remotingClient.invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (null != response) {
- SendResult sendResult = null;
+ this.remotingClient.invokeAsync(brokerAddr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
try {
- sendResult = this.processSendResponse(brokerName, msg, response);
+ SendResult sendResult = processSendResponse(brokerName, msg, response);
cf.complete(sendResult);
} catch (MQBrokerException | RemotingCommandException e) {
LOGGER.error("processSendResponse in sendMessageToSpecificBrokerAsync failed, msgId=" + msgId, e);
cf.completeExceptionally(e);
}
- } else {
- cf.complete(null);
}
+ @Override
+ public void operationFail(Throwable throwable) {
+ cf.completeExceptionally(throwable);
+ }
});
} catch (Throwable t) {
LOGGER.error("invokeAsync failed in sendMessageToSpecificBrokerAsync, msgId=" + msgId, t);
@@ -1056,7 +1078,7 @@ private SendResult processSendResponse(
}
if (sendStatus != null) {
SendMessageResponseHeader responseHeader =
- (SendMessageResponseHeader) response.decodeCommandCustomHeader(SendMessageResponseHeader.class);
+ (SendMessageResponseHeader) response.decodeCommandCustomHeader(SendMessageResponseHeader.class);
//If namespace not null , reset Topic without namespace.
String topic = msg.getTopic();
@@ -1072,8 +1094,8 @@ private SendResult processSendResponse(
uniqMsgId = sb.toString();
}
SendResult sendResult = new SendResult(sendStatus,
- uniqMsgId,
- responseHeader.getMsgId(), messageQueue, responseHeader.getQueueOffset());
+ uniqMsgId,
+ responseHeader.getMsgId(), messageQueue, responseHeader.getQueueOffset());
sendResult.setTransactionId(responseHeader.getTransactionId());
String regionId = response.getExtFields().get(MessageConst.PROPERTY_MSG_REGION);
String traceOn = response.getExtFields().get(MessageConst.PROPERTY_TRACE_SWITCH);
@@ -1092,7 +1114,7 @@ private SendResult processSendResponse(
throw new MQBrokerException(response.getCode(), response.getRemark());
}
- public BrokerFixedThreadPoolExecutor getBrokerOuterExecutor() {
+ public ExecutorService getBrokerOuterExecutor() {
return brokerOuterExecutor;
}
@@ -1217,8 +1239,9 @@ public SyncStateSet alterSyncStateSet(
/**
* Broker try to elect itself as a master in broker set
*/
- public Pair> brokerElect(String controllerAddress, String clusterName, String brokerName,
- Long brokerId) throws Exception {
+ public Pair> brokerElect(String controllerAddress, String clusterName,
+ String brokerName,
+ Long brokerId) throws Exception {
final ElectMasterRequestHeader requestHeader = ElectMasterRequestHeader.ofBrokerTrigger(clusterName, brokerName, brokerId);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONTROLLER_ELECT_MASTER, requestHeader);
@@ -1236,7 +1259,8 @@ public Pair> brokerElect(String controllerA
throw new MQBrokerException(response.getCode(), response.getRemark());
}
- public GetNextBrokerIdResponseHeader getNextBrokerId(final String clusterName, final String brokerName, final String controllerAddress) throws Exception {
+ public GetNextBrokerIdResponseHeader getNextBrokerId(final String clusterName, final String brokerName,
+ final String controllerAddress) throws Exception {
final GetNextBrokerIdRequestHeader requestHeader = new GetNextBrokerIdRequestHeader(clusterName, brokerName);
final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONTROLLER_GET_NEXT_BROKER_ID, requestHeader);
final RemotingCommand response = this.remotingClient.invokeSync(controllerAddress, request, 3000);
@@ -1247,7 +1271,8 @@ public GetNextBrokerIdResponseHeader getNextBrokerId(final String clusterName, f
throw new MQBrokerException(response.getCode(), response.getRemark());
}
- public ApplyBrokerIdResponseHeader applyBrokerId(final String clusterName, final String brokerName, final Long brokerId, final String registerCheckCode, final String controllerAddress) throws Exception {
+ public ApplyBrokerIdResponseHeader applyBrokerId(final String clusterName, final String brokerName,
+ final Long brokerId, final String registerCheckCode, final String controllerAddress) throws Exception {
final ApplyBrokerIdRequestHeader requestHeader = new ApplyBrokerIdRequestHeader(clusterName, brokerName, brokerId, registerCheckCode);
final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONTROLLER_APPLY_BROKER_ID, requestHeader);
final RemotingCommand response = this.remotingClient.invokeSync(controllerAddress, request, 3000);
@@ -1258,7 +1283,9 @@ public ApplyBrokerIdResponseHeader applyBrokerId(final String clusterName, final
throw new MQBrokerException(response.getCode(), response.getRemark());
}
- public Pair> registerBrokerToController(final String clusterName, final String brokerName, final Long brokerId, final String brokerAddress, final String controllerAddress) throws Exception {
+ public Pair> registerBrokerToController(
+ final String clusterName, final String brokerName, final Long brokerId, final String brokerAddress,
+ final String controllerAddress) throws Exception {
final RegisterBrokerToControllerRequestHeader requestHeader = new RegisterBrokerToControllerRequestHeader(clusterName, brokerName, brokerId, brokerAddress);
final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONTROLLER_REGISTER_BROKER, requestHeader);
final RemotingCommand response = this.remotingClient.invokeSync(controllerAddress, request, 3000);
@@ -1354,16 +1381,25 @@ public CompletableFuture pullMessageFromSpecificBrokerAsync(String b
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader);
CompletableFuture pullResultFuture = new CompletableFuture<>();
- this.remotingClient.invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- if (responseFuture.getCause() != null) {
- pullResultFuture.complete(new PullResult(PullStatus.NO_MATCHED_MSG, -1, -1, -1, new ArrayList<>()));
- return;
+ this.remotingClient.invokeAsync(brokerAddr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
}
- try {
- PullResultExt pullResultExt = this.processPullResponse(responseFuture.getResponseCommand(), brokerAddr);
- this.processPullResult(pullResultExt, brokerName, queueId);
- pullResultFuture.complete(pullResultExt);
- } catch (Exception e) {
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ try {
+ PullResultExt pullResultExt = processPullResponse(response, brokerAddr);
+ processPullResult(pullResultExt, brokerName, queueId);
+ pullResultFuture.complete(pullResultExt);
+ } catch (Exception e) {
+ pullResultFuture.complete(new PullResult(PullStatus.NO_MATCHED_MSG, -1, -1, -1, new ArrayList<>()));
+ }
+ }
+
+ @Override
+ public void operationFail(Throwable throwable) {
pullResultFuture.complete(new PullResult(PullStatus.NO_MATCHED_MSG, -1, -1, -1, new ArrayList<>()));
}
});
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
index 687811409e0..59a3e63b2ab 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
@@ -19,6 +19,7 @@
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
+import java.util.BitSet;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.metrics.PopMetricsManager;
import org.apache.rocketmq.common.KeyBuilder;
@@ -186,46 +187,7 @@ private void appendAck(final AckMessageRequestHeader requestHeader, final BatchA
invisibleTime = ExtraInfoUtil.getInvisibleTime(extraInfo);
if (rqId == KeyBuilder.POP_ORDER_REVIVE_QUEUE) {
- // order
- String lockKey = topic + PopAckConstants.SPLIT + consumeGroup + PopAckConstants.SPLIT + qId;
- long oldOffset = this.brokerController.getConsumerOffsetManager().queryOffset(consumeGroup, topic, qId);
- if (ackOffset < oldOffset) {
- return;
- }
- while (!this.brokerController.getPopMessageProcessor().getQueueLockManager().tryLock(lockKey)) {
- }
- try {
- oldOffset = this.brokerController.getConsumerOffsetManager().queryOffset(consumeGroup, topic, qId);
- if (ackOffset < oldOffset) {
- return;
- }
- long nextOffset = brokerController.getConsumerOrderInfoManager().commitAndNext(
- topic, consumeGroup,
- qId, ackOffset,
- popTime);
- if (nextOffset > -1) {
- if (!this.brokerController.getConsumerOffsetManager().hasOffsetReset(
- topic, consumeGroup, qId)) {
- this.brokerController.getConsumerOffsetManager().commitOffset(channel.remoteAddress().toString(),
- consumeGroup, topic, qId, nextOffset);
- }
- if (!this.brokerController.getConsumerOrderInfoManager().checkBlock(null, topic,
- consumeGroup, qId, invisibleTime)) {
- this.brokerController.getPopMessageProcessor().notifyMessageArriving(
- topic, consumeGroup, qId);
- }
- } else if (nextOffset == -1) {
- String errorInfo = String.format("offset is illegal, key:%s, old:%d, commit:%d, next:%d, %s",
- lockKey, oldOffset, ackOffset, nextOffset, channel.remoteAddress());
- POP_LOGGER.warn(errorInfo);
- response.setCode(ResponseCode.MESSAGE_ILLEGAL);
- response.setRemark(errorInfo);
- return;
- }
- } finally {
- this.brokerController.getPopMessageProcessor().getQueueLockManager().unLock(lockKey);
- }
- brokerController.getPopInflightMessageCounter().decrementInFlightMessageNum(topic, consumeGroup, popTime, qId, ackCount);
+ ackOrderly(topic, consumeGroup, qId, ackOffset, popTime, invisibleTime, channel, response);
return;
}
@@ -250,17 +212,22 @@ private void appendAck(final AckMessageRequestHeader requestHeader, final BatchA
}
BatchAckMsg batchAckMsg = new BatchAckMsg();
- for (int i = 0; batchAck.getBitSet() != null && i < batchAck.getBitSet().length(); i++) {
- if (!batchAck.getBitSet().get(i)) {
- continue;
+ BitSet bitSet = batchAck.getBitSet();
+ for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {
+ if (i == Integer.MAX_VALUE) {
+ break;
}
long offset = startOffset + i;
if (offset < minOffset || offset > maxOffset) {
continue;
}
- batchAckMsg.getAckOffsetList().add(offset);
+ if (rqId == KeyBuilder.POP_ORDER_REVIVE_QUEUE) {
+ ackOrderly(topic, consumeGroup, qId, offset, popTime, invisibleTime, channel, response);
+ } else {
+ batchAckMsg.getAckOffsetList().add(offset);
+ }
}
- if (batchAckMsg.getAckOffsetList().isEmpty()) {
+ if (rqId == KeyBuilder.POP_ORDER_REVIVE_QUEUE || batchAckMsg.getAckOffsetList().isEmpty()) {
return;
}
@@ -286,7 +253,7 @@ private void appendAck(final AckMessageRequestHeader requestHeader, final BatchA
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(reviveTopic);
- msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(rqId);
if (ackMsg instanceof BatchAckMsg) {
msgInner.setTags(PopAckConstants.BATCH_ACK_TAG);
@@ -311,4 +278,46 @@ private void appendAck(final AckMessageRequestHeader requestHeader, final BatchA
PopMetricsManager.incPopReviveAckPutCount(ackMsg, putMessageResult.getPutMessageStatus());
brokerController.getPopInflightMessageCounter().decrementInFlightMessageNum(topic, consumeGroup, popTime, qId, ackCount);
}
+
+ protected void ackOrderly(String topic, String consumeGroup, int qId, long ackOffset, long popTime, long invisibleTime, Channel channel, RemotingCommand response) {
+ String lockKey = topic + PopAckConstants.SPLIT + consumeGroup + PopAckConstants.SPLIT + qId;
+ long oldOffset = this.brokerController.getConsumerOffsetManager().queryOffset(consumeGroup, topic, qId);
+ if (ackOffset < oldOffset) {
+ return;
+ }
+ while (!this.brokerController.getPopMessageProcessor().getQueueLockManager().tryLock(lockKey)) {
+ }
+ try {
+ oldOffset = this.brokerController.getConsumerOffsetManager().queryOffset(consumeGroup, topic, qId);
+ if (ackOffset < oldOffset) {
+ return;
+ }
+ long nextOffset = brokerController.getConsumerOrderInfoManager().commitAndNext(
+ topic, consumeGroup,
+ qId, ackOffset,
+ popTime);
+ if (nextOffset > -1) {
+ if (!this.brokerController.getConsumerOffsetManager().hasOffsetReset(
+ topic, consumeGroup, qId)) {
+ this.brokerController.getConsumerOffsetManager().commitOffset(channel.remoteAddress().toString(),
+ consumeGroup, topic, qId, nextOffset);
+ }
+ if (!this.brokerController.getConsumerOrderInfoManager().checkBlock(null, topic,
+ consumeGroup, qId, invisibleTime)) {
+ this.brokerController.getPopMessageProcessor().notifyMessageArriving(
+ topic, consumeGroup, qId);
+ }
+ } else if (nextOffset == -1) {
+ String errorInfo = String.format("offset is illegal, key:%s, old:%d, commit:%d, next:%d, %s",
+ lockKey, oldOffset, ackOffset, nextOffset, channel.remoteAddress());
+ POP_LOGGER.warn(errorInfo);
+ response.setCode(ResponseCode.MESSAGE_ILLEGAL);
+ response.setRemark(errorInfo);
+ return;
+ }
+ } finally {
+ this.brokerController.getPopMessageProcessor().getQueueLockManager().unLock(lockKey);
+ }
+ brokerController.getPopInflightMessageCounter().decrementInFlightMessageNum(topic, consumeGroup, popTime, qId, 1);
+ }
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index bbddcec2d7f..dd4ec960fe5 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -51,6 +51,7 @@
import org.apache.rocketmq.broker.transaction.queue.TransactionalMessageUtil;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.LockCallback;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
@@ -405,9 +406,6 @@ public boolean rejectRequest() {
private synchronized RemotingCommand updateAndCreateTopic(ChannelHandlerContext ctx,
RemotingCommand request) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- if (validateSlave(response)) {
- return response;
- }
final CreateTopicRequestHeader requestHeader =
(CreateTopicRequestHeader) request.decodeCommandCustomHeader(CreateTopicRequestHeader.class);
@@ -518,9 +516,6 @@ private synchronized RemotingCommand updateAndCreateStaticTopic(ChannelHandlerCo
private synchronized RemotingCommand deleteTopic(ChannelHandlerContext ctx,
RemotingCommand request) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- if (validateSlave(response)) {
- return response;
- }
DeleteTopicRequestHeader requestHeader =
(DeleteTopicRequestHeader) request.decodeCommandCustomHeader(DeleteTopicRequestHeader.class);
@@ -542,16 +537,33 @@ private synchronized RemotingCommand deleteTopic(ChannelHandlerContext ctx,
}
}
- this.brokerController.getTopicConfigManager().deleteTopicConfig(requestHeader.getTopic());
- this.brokerController.getTopicQueueMappingManager().delete(requestHeader.getTopic());
- this.brokerController.getConsumerOffsetManager().cleanOffsetByTopic(requestHeader.getTopic());
- this.brokerController.getPopInflightMessageCounter().clearInFlightMessageNumByTopicName(requestHeader.getTopic());
- this.brokerController.getMessageStore().deleteTopics(Sets.newHashSet(requestHeader.getTopic()));
+ final Set groups = this.brokerController.getConsumerOffsetManager().whichGroupByTopic(topic);
+ // delete pop retry topics first
+ try {
+ for (String group : groups) {
+ final String popRetryTopic = KeyBuilder.buildPopRetryTopic(topic, group);
+ if (brokerController.getTopicConfigManager().selectTopicConfig(popRetryTopic) != null) {
+ deleteTopicInBroker(popRetryTopic);
+ }
+ }
+ // delete topic
+ deleteTopicInBroker(topic);
+ } catch (Throwable t) {
+ return buildErrorResponse(ResponseCode.SYSTEM_ERROR, t.getMessage());
+ }
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
return response;
}
+ private void deleteTopicInBroker(String topic) {
+ this.brokerController.getTopicConfigManager().deleteTopicConfig(topic);
+ this.brokerController.getTopicQueueMappingManager().delete(topic);
+ this.brokerController.getConsumerOffsetManager().cleanOffsetByTopic(topic);
+ this.brokerController.getPopInflightMessageCounter().clearInFlightMessageNumByTopicName(topic);
+ this.brokerController.getMessageStore().deleteTopics(Sets.newHashSet(topic));
+ }
+
private synchronized RemotingCommand updateAndCreateAccessConfig(ChannelHandlerContext ctx,
RemotingCommand request) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
@@ -1399,9 +1411,6 @@ public void onException(Throwable e) {
private RemotingCommand updateAndCreateSubscriptionGroup(ChannelHandlerContext ctx, RemotingCommand request)
throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- if (validateSlave(response)) {
- return response;
- }
LOGGER.info("AdminBrokerProcessor#updateAndCreateSubscriptionGroup called by {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
@@ -1466,9 +1475,6 @@ private RemotingCommand getAllSubscriptionGroup(ChannelHandlerContext ctx,
private RemotingCommand deleteSubscriptionGroup(ChannelHandlerContext ctx,
RemotingCommand request) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- if (validateSlave(response)) {
- return response;
- }
DeleteSubscriptionGroupRequestHeader requestHeader =
(DeleteSubscriptionGroupRequestHeader) request.decodeCommandCustomHeader(DeleteSubscriptionGroupRequestHeader.class);
@@ -2079,7 +2085,11 @@ private RemotingCommand getSystemTopicListFromBroker(ChannelHandlerContext ctx,
public RemotingCommand cleanExpiredConsumeQueue() {
LOGGER.info("AdminBrokerProcessor#cleanExpiredConsumeQueue: start.");
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- brokerController.getMessageStore().cleanExpiredConsumerQueue();
+ try {
+ brokerController.getMessageStore().cleanExpiredConsumerQueue();
+ } catch (Throwable t) {
+ return buildErrorResponse(ResponseCode.SYSTEM_ERROR, t.getMessage());
+ }
LOGGER.info("AdminBrokerProcessor#cleanExpiredConsumeQueue: end.");
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
@@ -2734,10 +2744,16 @@ private RemotingCommand getBrokerEpochCache(ChannelHandlerContext ctx, RemotingC
final ReplicasManager replicasManager = this.brokerController.getReplicasManager();
assert replicasManager != null;
final BrokerConfig brokerConfig = this.brokerController.getBrokerConfig();
+ final RemotingCommand response = RemotingCommand.createResponseCommand(null);
+
+ if (!brokerConfig.isEnableControllerMode()) {
+ response.setCode(ResponseCode.SYSTEM_ERROR);
+ response.setRemark("this request only for controllerMode ");
+ return response;
+ }
final EpochEntryCache entryCache = new EpochEntryCache(brokerConfig.getBrokerClusterName(),
- brokerConfig.getBrokerName(), brokerConfig.getBrokerId(), replicasManager.getEpochEntries(), this.brokerController.getMessageStore().getMaxPhyOffset());
+ brokerConfig.getBrokerName(), brokerConfig.getBrokerId(), replicasManager.getEpochEntries(), this.brokerController.getMessageStore().getMaxPhyOffset());
- final RemotingCommand response = RemotingCommand.createResponseCommand(null);
response.setBody(entryCache.encode());
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
@@ -2773,7 +2789,11 @@ private RemotingCommand notifyBrokerRoleChanged(ChannelHandlerContext ctx,
final ReplicasManager replicasManager = this.brokerController.getReplicasManager();
if (replicasManager != null) {
- replicasManager.changeBrokerRole(requestHeader.getMasterBrokerId(), requestHeader.getMasterAddress(), requestHeader.getMasterEpoch(), requestHeader.getSyncStateSetEpoch(), syncStateSetInfo.getSyncStateSet());
+ try {
+ replicasManager.changeBrokerRole(requestHeader.getMasterBrokerId(), requestHeader.getMasterAddress(), requestHeader.getMasterEpoch(), requestHeader.getSyncStateSetEpoch(), syncStateSetInfo.getSyncStateSet());
+ } catch (Exception e) {
+ throw new RemotingCommandException(e.getMessage());
+ }
}
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
index 2ccdf07f6aa..bdfffff096a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
@@ -180,7 +180,7 @@ private void ackOrigin(final ChangeInvisibleTimeRequestHeader requestHeader, Str
}
msgInner.setTopic(reviveTopic);
- msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(rqId);
msgInner.setTags(PopAckConstants.ACK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
@@ -216,7 +216,7 @@ private PutMessageResult appendCheckPoint(final ChangeInvisibleTimeRequestHeader
ck.addDiff(0);
ck.setBrokerName(brokerName);
- msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(reviveQid);
msgInner.setTags(PopAckConstants.CK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PeekMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PeekMessageProcessor.java
index a8358c4ffb0..e1e0e13e53b 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PeekMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PeekMessageProcessor.java
@@ -129,8 +129,7 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re
}
int randomQ = random.nextInt(100);
int reviveQid = randomQ % this.brokerController.getBrokerConfig().getReviveQueueNum();
- int commercialSizePerMsg = this.brokerController.getBrokerConfig().getCommercialSizePerMsg();
- GetMessageResult getMessageResult = new GetMessageResult(commercialSizePerMsg);
+ GetMessageResult getMessageResult = new GetMessageResult(requestHeader.getMaxMsgNums());
boolean needRetry = randomQ % 5 == 0;
long popTime = System.currentTimeMillis();
long restNum = 0;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
index b7ba8ad4a20..8a85dd8fec8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
@@ -633,7 +633,7 @@ private boolean putAckToStore(final PopCheckPointWrapper pointWrapper, byte msgI
ackMsg.setQueueId(point.getQueueId());
ackMsg.setPopTime(point.getPopTime());
msgInner.setTopic(popMessageProcessor.reviveTopic);
- msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(pointWrapper.getReviveQueueId());
msgInner.setTags(PopAckConstants.ACK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
@@ -673,7 +673,7 @@ private boolean putBatchAckToStore(final PopCheckPointWrapper pointWrapper, fina
batchAckMsg.setQueueId(point.getQueueId());
batchAckMsg.setPopTime(point.getPopTime());
msgInner.setTopic(popMessageProcessor.reviveTopic);
- msgInner.setBody(JSON.toJSONString(batchAckMsg).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(batchAckMsg).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(pointWrapper.getReviveQueueId());
msgInner.setTags(PopAckConstants.BATCH_ACK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
index 441f7de08a1..f5d07c5aae9 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
@@ -347,8 +347,7 @@ public RemotingCommand processRequest(final ChannelHandlerContext ctx, RemotingC
reviveQid = (int) Math.abs(ckMessageNumber.getAndIncrement() % this.brokerController.getBrokerConfig().getReviveQueueNum());
}
- int commercialSizePerMsg = this.brokerController.getBrokerConfig().getCommercialSizePerMsg();
- GetMessageResult getMessageResult = new GetMessageResult(commercialSizePerMsg);
+ GetMessageResult getMessageResult = new GetMessageResult(requestHeader.getMaxMsgNums());
ExpressionMessageFilter finalMessageFilter = messageFilter;
StringBuilder finalOrderCountInfo = orderCountInfo;
@@ -686,7 +685,7 @@ public final MessageExtBrokerInner buildCkMsg(final PopCheckPoint ck, final int
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(reviveTopic);
- msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(reviveQid);
msgInner.setTags(PopAckConstants.CK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
index 93167db373a..3fb689ed6a9 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
@@ -129,7 +129,7 @@ private boolean reviveRetry(PopCheckPoint popCheckPoint, MessageExt messageExt)
PutMessageResult putMessageResult = brokerController.getEscapeBridge().putMessageToSpecificQueue(msgInner);
PopMetricsManager.incPopReviveRetryMessageCount(popCheckPoint, putMessageResult.getPutMessageStatus());
if (brokerController.getBrokerConfig().isEnablePopLog()) {
- POP_LOGGER.info("reviveQueueId={},retry msg , ck={}, msg queueId {}, offset {}, reviveDelay={}, result is {} ",
+ POP_LOGGER.info("reviveQueueId={},retry msg, ck={}, msg queueId {}, offset {}, reviveDelay={}, result is {} ",
queueId, popCheckPoint, messageExt.getQueueId(), messageExt.getQueueOffset(),
(System.currentTimeMillis() - popCheckPoint.getReviveTime()) / 1000, putMessageResult);
}
@@ -319,7 +319,7 @@ protected void consumeReviveMessage(ConsumeReviveObj consumeReviveObj) {
// offset self amend
while (true) {
if (!shouldRunPopRevive) {
- POP_LOGGER.info("slave skip scan , revive topic={}, reviveQueueId={}", reviveTopic, queueId);
+ POP_LOGGER.info("slave skip scan, revive topic={}, reviveQueueId={}", reviveTopic, queueId);
break;
}
List messageExts = getReviveMessage(offset, queueId);
@@ -351,12 +351,12 @@ protected void consumeReviveMessage(ConsumeReviveObj consumeReviveObj) {
noMsgCount = 0;
}
if (System.currentTimeMillis() - startScanTime > brokerController.getBrokerConfig().getReviveScanTime()) {
- POP_LOGGER.info("reviveQueueId={}, scan timeout ", queueId);
+ POP_LOGGER.info("reviveQueueId={}, scan timeout ", queueId);
break;
}
for (MessageExt messageExt : messageExts) {
if (PopAckConstants.CK_TAG.equals(messageExt.getTags())) {
- String raw = new String(messageExt.getBody(), DataConverter.charset);
+ String raw = new String(messageExt.getBody(), DataConverter.CHARSET_UTF8);
if (brokerController.getBrokerConfig().isEnablePopLog()) {
POP_LOGGER.info("reviveQueueId={},find ck, offset:{}, raw : {}", messageExt.getQueueId(), messageExt.getQueueOffset(), raw);
}
@@ -371,9 +371,9 @@ protected void consumeReviveMessage(ConsumeReviveObj consumeReviveObj) {
firstRt = point.getReviveTime();
}
} else if (PopAckConstants.ACK_TAG.equals(messageExt.getTags())) {
- String raw = new String(messageExt.getBody(), DataConverter.charset);
+ String raw = new String(messageExt.getBody(), DataConverter.CHARSET_UTF8);
if (brokerController.getBrokerConfig().isEnablePopLog()) {
- POP_LOGGER.info("reviveQueueId={},find ack, offset:{}, raw : {}", messageExt.getQueueId(), messageExt.getQueueOffset(), raw);
+ POP_LOGGER.info("reviveQueueId={}, find ack, offset:{}, raw : {}", messageExt.getQueueId(), messageExt.getQueueOffset(), raw);
}
AckMsg ackMsg = JSON.parseObject(raw, AckMsg.class);
PopMetricsManager.incPopReviveAckGetCount(ackMsg, queueId);
@@ -395,7 +395,7 @@ protected void consumeReviveMessage(ConsumeReviveObj consumeReviveObj) {
}
}
} else if (PopAckConstants.BATCH_ACK_TAG.equals(messageExt.getTags())) {
- String raw = new String(messageExt.getBody(), DataConverter.charset);
+ String raw = new String(messageExt.getBody(), DataConverter.CHARSET_UTF8);
if (brokerController.getBrokerConfig().isEnablePopLog()) {
POP_LOGGER.info("reviveQueueId={}, find batch ack, offset:{}, raw : {}", messageExt.getQueueId(), messageExt.getQueueOffset(), raw);
}
@@ -465,15 +465,15 @@ private PopCheckPoint createMockCkForAck(AckMsg ackMsg, long reviveOffset) {
protected void mergeAndRevive(ConsumeReviveObj consumeReviveObj) throws Throwable {
ArrayList sortList = consumeReviveObj.genSortList();
- POP_LOGGER.info("reviveQueueId={},ck listSize={}", queueId, sortList.size());
+ POP_LOGGER.info("reviveQueueId={}, ck listSize={}", queueId, sortList.size());
if (sortList.size() != 0) {
- POP_LOGGER.info("reviveQueueId={}, 1st ck, startOffset={}, reviveOffset={} ; last ck, startOffset={}, reviveOffset={}", queueId, sortList.get(0).getStartOffset(),
+ POP_LOGGER.info("reviveQueueId={}, 1st ck, startOffset={}, reviveOffset={}; last ck, startOffset={}, reviveOffset={}", queueId, sortList.get(0).getStartOffset(),
sortList.get(0).getReviveOffset(), sortList.get(sortList.size() - 1).getStartOffset(), sortList.get(sortList.size() - 1).getReviveOffset());
}
long newOffset = consumeReviveObj.oldOffset;
for (PopCheckPoint popCheckPoint : sortList) {
if (!shouldRunPopRevive) {
- POP_LOGGER.info("slave skip ck process , revive topic={}, reviveQueueId={}", reviveTopic, queueId);
+ POP_LOGGER.info("slave skip ck process, revive topic={}, reviveQueueId={}", reviveTopic, queueId);
break;
}
if (consumeReviveObj.endTime - popCheckPoint.getReviveTime() <= (PopAckConstants.ackTimeInterval + PopAckConstants.SECOND)) {
@@ -483,12 +483,12 @@ protected void mergeAndRevive(ConsumeReviveObj consumeReviveObj) throws Throwabl
// check normal topic, skip ck , if normal topic is not exist
String normalTopic = KeyBuilder.parseNormalTopic(popCheckPoint.getTopic(), popCheckPoint.getCId());
if (brokerController.getTopicConfigManager().selectTopicConfig(normalTopic) == null) {
- POP_LOGGER.warn("reviveQueueId={},can not get normal topic {} , then continue ", queueId, popCheckPoint.getTopic());
+ POP_LOGGER.warn("reviveQueueId={}, can not get normal topic {}, then continue", queueId, popCheckPoint.getTopic());
newOffset = popCheckPoint.getReviveOffset();
continue;
}
if (null == brokerController.getSubscriptionGroupManager().findSubscriptionGroupConfig(popCheckPoint.getCId())) {
- POP_LOGGER.warn("reviveQueueId={},can not get cid {} , then continue ", queueId, popCheckPoint.getCId());
+ POP_LOGGER.warn("reviveQueueId={}, can not get cid {}, then continue", queueId, popCheckPoint.getCId());
newOffset = popCheckPoint.getReviveOffset();
continue;
}
@@ -520,7 +520,7 @@ protected void mergeAndRevive(ConsumeReviveObj consumeReviveObj) throws Throwabl
private void reviveMsgFromCk(PopCheckPoint popCheckPoint) {
if (!shouldRunPopRevive) {
- POP_LOGGER.info("slave skip retry , revive topic={}, reviveQueueId={}", reviveTopic, queueId);
+ POP_LOGGER.info("slave skip retry, revive topic={}, reviveQueueId={}", reviveTopic, queueId);
return;
}
inflightReviveRequestMap.put(popCheckPoint, new Pair<>(System.currentTimeMillis(), false));
@@ -595,6 +595,7 @@ private void rePutCK(PopCheckPoint oldCK, Pair pair) {
newCk.setCId(oldCK.getCId());
newCk.setTopic(oldCK.getTopic());
newCk.setQueueId(oldCK.getQueueId());
+ newCk.setBrokerName(oldCK.getBrokerName());
newCk.addDiff(0);
MessageExtBrokerInner ckMsg = brokerController.getPopMessageProcessor().buildCkMsg(newCk, queueId);
brokerController.getMessageStore().putMessage(ckMsg);
@@ -645,7 +646,7 @@ public void run() {
consumeReviveMessage(consumeReviveObj);
if (!shouldRunPopRevive) {
- POP_LOGGER.info("slave skip scan , revive topic={}, reviveQueueId={}", reviveTopic, queueId);
+ POP_LOGGER.info("slave skip scan, revive topic={}, reviveQueueId={}", reviveTopic, queueId);
continue;
}
@@ -661,7 +662,7 @@ public void run() {
currentReviveMessageTimestamp = System.currentTimeMillis();
}
- POP_LOGGER.info("reviveQueueId={},revive finish,old offset is {}, new offset is {}, ckDelay={} ",
+ POP_LOGGER.info("reviveQueueId={}, revive finish,old offset is {}, new offset is {}, ckDelay={} ",
queueId, consumeReviveObj.oldOffset, consumeReviveObj.newOffset, delay);
if (sortList == null || sortList.isEmpty()) {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ReplyMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ReplyMessageProcessor.java
index b2db356c8a4..d3bb048f75d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ReplyMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ReplyMessageProcessor.java
@@ -234,7 +234,7 @@ private void handlePushReplyResult(PushReplyResult pushReplyResult, final Remoti
} else {
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
- //set to zore to avoid client decoding exception
+ //set to zero to avoid client decoding exception
responseHeader.setMsgId("0");
responseHeader.setQueueId(queueIdInt);
responseHeader.setQueueOffset(0L);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/schedule/ScheduleMessageService.java b/broker/src/main/java/org/apache/rocketmq/broker/schedule/ScheduleMessageService.java
index aed0ee19fa5..0c2e6507bd9 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/schedule/ScheduleMessageService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/schedule/ScheduleMessageService.java
@@ -26,7 +26,6 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -91,7 +90,7 @@ public class ScheduleMessageService extends ConfigManager {
public ScheduleMessageService(final BrokerController brokerController) {
this.brokerController = brokerController;
this.enableAsyncDeliver = brokerController.getMessageStoreConfig().isEnableScheduleAsyncDeliver();
- scheduledPersistService = new ScheduledThreadPoolExecutor(1,
+ scheduledPersistService = ThreadUtils.newScheduledThreadPool(1,
new ThreadFactoryImpl("ScheduleMessageServicePersistThread", true, brokerController.getBrokerConfig()));
}
@@ -134,9 +133,9 @@ public long computeDeliverTimestamp(final int delayLevel, final long storeTimest
public void start() {
if (started.compareAndSet(false, true)) {
this.load();
- this.deliverExecutorService = new ScheduledThreadPoolExecutor(this.maxDelayLevel, new ThreadFactoryImpl("ScheduleMessageTimerThread_"));
+ this.deliverExecutorService = ThreadUtils.newScheduledThreadPool(this.maxDelayLevel, new ThreadFactoryImpl("ScheduleMessageTimerThread_"));
if (this.enableAsyncDeliver) {
- this.handleExecutorService = new ScheduledThreadPoolExecutor(this.maxDelayLevel, new ThreadFactoryImpl("ScheduleMessageExecutorHandleThread_"));
+ this.handleExecutorService = ThreadUtils.newScheduledThreadPool(this.maxDelayLevel, new ThreadFactoryImpl("ScheduleMessageExecutorHandleThread_"));
}
for (Map.Entry entry : this.delayLevelTable.entrySet()) {
Integer level = entry.getKey();
@@ -566,7 +565,8 @@ public void run() {
pendingQueue.remove();
break;
case RUNNING:
- break;
+ scheduleNextTask();
+ return;
case EXCEPTION:
if (!isStarted()) {
log.warn("HandlePutResultTask shutdown, info={}", putResultProcess.toString());
@@ -586,6 +586,10 @@ public void run() {
}
}
+ scheduleNextTask();
+ }
+
+ private void scheduleNextTask() {
if (isStarted()) {
ScheduleMessageService.this.handleExecutorService
.schedule(new HandlePutResultTask(this.delayLevel), DELAY_FOR_A_SLEEP, TimeUnit.MILLISECONDS);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/subscription/RocksDBSubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/subscription/RocksDBSubscriptionGroupManager.java
index 6503970af2e..e9a81a8d686 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/subscription/RocksDBSubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/subscription/RocksDBSubscriptionGroupManager.java
@@ -30,7 +30,7 @@ public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
public RocksDBSubscriptionGroupManager(BrokerController brokerController) {
super(brokerController, false);
- this.rocksDBConfigManager = new RocksDBConfigManager(this.brokerController.getMessageStoreConfig().getMemTableFlushInterval());
+ this.rocksDBConfigManager = new RocksDBConfigManager(brokerController.getMessageStoreConfig().getMemTableFlushIntervalMs());
}
@Override
@@ -53,7 +53,7 @@ protected SubscriptionGroupConfig putSubscriptionGroupConfig(SubscriptionGroupCo
SubscriptionGroupConfig oldConfig = this.subscriptionGroupTable.put(groupName, subscriptionGroupConfig);
try {
- byte[] keyBytes = groupName.getBytes(DataConverter.charset);
+ byte[] keyBytes = groupName.getBytes(DataConverter.CHARSET_UTF8);
byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, keyBytes.length, valueBytes);
} catch (Exception e) {
@@ -68,7 +68,7 @@ protected SubscriptionGroupConfig putSubscriptionGroupConfigIfAbsent(Subscriptio
SubscriptionGroupConfig oldConfig = this.subscriptionGroupTable.putIfAbsent(groupName, subscriptionGroupConfig);
if (oldConfig == null) {
try {
- byte[] keyBytes = groupName.getBytes(DataConverter.charset);
+ byte[] keyBytes = groupName.getBytes(DataConverter.CHARSET_UTF8);
byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, keyBytes.length, valueBytes);
} catch (Exception e) {
@@ -82,7 +82,7 @@ protected SubscriptionGroupConfig putSubscriptionGroupConfigIfAbsent(Subscriptio
protected SubscriptionGroupConfig removeSubscriptionGroupConfig(String groupName) {
SubscriptionGroupConfig subscriptionGroupConfig = this.subscriptionGroupTable.remove(groupName);
try {
- this.rocksDBConfigManager.delete(groupName.getBytes(DataConverter.charset));
+ this.rocksDBConfigManager.delete(groupName.getBytes(DataConverter.CHARSET_UTF8));
} catch (Exception e) {
log.error("kv delete sub Failed, {}", subscriptionGroupConfig.toString());
}
@@ -91,7 +91,7 @@ protected SubscriptionGroupConfig removeSubscriptionGroupConfig(String groupName
@Override
protected void decode0(byte[] key, byte[] body) {
- String groupName = new String(key, DataConverter.charset);
+ String groupName = new String(key, DataConverter.CHARSET_UTF8);
SubscriptionGroupConfig subscriptionGroupConfig = JSON.parseObject(body, SubscriptionGroupConfig.class);
this.subscriptionGroupTable.put(groupName, subscriptionGroupConfig);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
index 74e39c0fedb..e63b9305868 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
@@ -341,10 +341,7 @@ public void deleteSubscriptionGroupConfig(final String groupName) {
public void setSubscriptionGroupTable(ConcurrentMap subscriptionGroupTable) {
- this.subscriptionGroupTable.clear();
- for (String key : subscriptionGroupTable.keySet()) {
- putSubscriptionGroupConfig(subscriptionGroupTable.get(key));
- }
+ this.subscriptionGroupTable = subscriptionGroupTable;
}
public boolean containsSubscriptionGroup(String group) {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/RocksDBTopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/RocksDBTopicConfigManager.java
index 7da0d7c8ac6..fddecf2d92a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/RocksDBTopicConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/RocksDBTopicConfigManager.java
@@ -30,7 +30,7 @@ public class RocksDBTopicConfigManager extends TopicConfigManager {
public RocksDBTopicConfigManager(BrokerController brokerController) {
super(brokerController, false);
- this.rocksDBConfigManager = new RocksDBConfigManager(this.brokerController.getMessageStoreConfig().getMemTableFlushInterval());
+ this.rocksDBConfigManager = new RocksDBConfigManager(brokerController.getMessageStoreConfig().getMemTableFlushIntervalMs());
}
@Override
@@ -49,7 +49,7 @@ public boolean stop() {
@Override
protected void decode0(byte[] key, byte[] body) {
- String topicName = new String(key, DataConverter.charset);
+ String topicName = new String(key, DataConverter.CHARSET_UTF8);
TopicConfig topicConfig = JSON.parseObject(body, TopicConfig.class);
this.topicConfigTable.put(topicName, topicConfig);
@@ -66,7 +66,7 @@ protected TopicConfig putTopicConfig(TopicConfig topicConfig) {
String topicName = topicConfig.getTopicName();
TopicConfig oldTopicConfig = this.topicConfigTable.put(topicName, topicConfig);
try {
- byte[] keyBytes = topicName.getBytes(DataConverter.charset);
+ byte[] keyBytes = topicName.getBytes(DataConverter.CHARSET_UTF8);
byte[] valueBytes = JSON.toJSONBytes(topicConfig, SerializerFeature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, keyBytes.length, valueBytes);
} catch (Exception e) {
@@ -79,7 +79,7 @@ protected TopicConfig putTopicConfig(TopicConfig topicConfig) {
protected TopicConfig removeTopicConfig(String topicName) {
TopicConfig topicConfig = this.topicConfigTable.remove(topicName);
try {
- this.rocksDBConfigManager.delete(topicName.getBytes(DataConverter.charset));
+ this.rocksDBConfigManager.delete(topicName.getBytes(DataConverter.CHARSET_UTF8));
} catch (Exception e) {
log.error("kv remove topic Failed, {}", topicConfig.toString());
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
index 1c3b9711fda..511d29e12ad 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
@@ -29,6 +29,7 @@
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -47,7 +48,9 @@
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.body.KVTable;
+import org.apache.rocketmq.remoting.protocol.body.TopicConfigAndMappingSerializeWrapper;
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
+import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingInfo;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -290,7 +293,7 @@ public TopicConfig createTopicInSendMessageMethod(final String topic, final Stri
}
if (createNew) {
- this.brokerController.registerBrokerAll(false, true, true);
+ registerBrokerData(topicConfig);
}
return topicConfig;
@@ -330,7 +333,7 @@ public TopicConfig createTopicIfAbsent(TopicConfig topicConfig, boolean register
log.error("createTopicIfAbsent ", e);
}
if (createNew && register) {
- this.brokerController.registerIncrementBrokerData(topicConfig, dataVersion);
+ registerBrokerData(topicConfig);
}
return getTopicConfig(topicConfig.getTopicName());
}
@@ -390,7 +393,7 @@ public TopicConfig createTopicInSendMessageBackMethod(
}
if (createNew) {
- this.brokerController.registerBrokerAll(false, true, true);
+ registerBrokerData(topicConfig);
}
return topicConfig;
@@ -431,7 +434,7 @@ public TopicConfig createTopicOfTranCheckMaxTime(final int clientDefaultTopicQue
}
if (createNew) {
- this.brokerController.registerBrokerAll(false, true, true);
+ registerBrokerData(topicConfig);
}
return topicConfig;
@@ -457,7 +460,7 @@ public void updateTopicUnitFlag(final String topic, final boolean unit) {
dataVersion.nextVersion(stateMachineVersion);
this.persist();
- this.brokerController.registerBrokerAll(false, true, true);
+ registerBrokerData(topicConfig);
}
}
@@ -480,7 +483,7 @@ public void updateTopicUnitSubFlag(final String topic, final boolean hasUnitSub)
dataVersion.nextVersion(stateMachineVersion);
this.persist();
- this.brokerController.registerBrokerAll(false, true, true);
+ registerBrokerData(topicConfig);
}
}
@@ -585,6 +588,24 @@ public TopicConfigSerializeWrapper buildTopicConfigSerializeWrapper() {
return topicConfigSerializeWrapper;
}
+ public TopicConfigAndMappingSerializeWrapper buildSerializeWrapper(final ConcurrentMap topicConfigTable) {
+ return buildSerializeWrapper(topicConfigTable, Maps.newHashMap());
+ }
+
+ public TopicConfigAndMappingSerializeWrapper buildSerializeWrapper(
+ final ConcurrentMap topicConfigTable,
+ final Map topicQueueMappingInfoMap
+ ) {
+ TopicConfigAndMappingSerializeWrapper topicConfigWrapper = new TopicConfigAndMappingSerializeWrapper();
+ topicConfigWrapper.setTopicConfigTable(topicConfigTable);
+ topicConfigWrapper.setTopicQueueMappingInfoMap(topicQueueMappingInfoMap);
+ topicConfigWrapper.setDataVersion(this.getDataVersion());
+ if (this.brokerController.getBrokerConfig().isEnableSplitRegistration()) {
+ this.getDataVersion().nextVersion();
+ }
+ return topicConfigWrapper;
+ }
+
@Override
public String encode() {
return encode(false);
@@ -654,6 +675,14 @@ private Map current(String topic) {
}
}
+ private void registerBrokerData(TopicConfig topicConfig) {
+ if (brokerController.getBrokerConfig().isEnableSingleTopicRegister()) {
+ this.brokerController.registerSingleTopicAll(topicConfig);
+ } else {
+ this.brokerController.registerIncrementBrokerData(topicConfig, dataVersion);
+ }
+ }
+
public boolean containsTopic(String topic) {
return topicConfigTable.containsKey(topic);
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicRouteInfoManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicRouteInfoManager.java
index b3556472555..11bde5f5fe2 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicRouteInfoManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicRouteInfoManager.java
@@ -23,7 +23,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
@@ -36,6 +35,7 @@
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.exception.RemotingException;
@@ -66,7 +66,7 @@ public TopicRouteInfoManager(BrokerController brokerController) {
}
public void start() {
- this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("TopicRouteInfoManagerScheduledThread"));
+ this.scheduledExecutorService = ThreadUtils.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("TopicRouteInfoManagerScheduledThread"));
this.scheduledExecutorService.scheduleAtFixedRate(() -> {
try {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
index 771d8430060..982355d783f 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
@@ -19,7 +19,6 @@
import io.netty.channel.Channel;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
@@ -27,6 +26,7 @@
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.header.CheckTransactionStateRequestHeader;
@@ -97,7 +97,7 @@ public void shutDown() {
public synchronized void initExecutorService() {
if (executorService == null) {
- executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2000),
+ executorService = ThreadUtils.newThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2000),
new ThreadFactoryImpl("Transaction-msg-check-thread", brokerController.getBrokerIdentity()), new CallerRunsPolicy());
}
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java
index 93fa725a93c..48db828e0ae 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java
@@ -629,7 +629,9 @@ public boolean open() {
@Override
public void close() {
-
+ if (this.transactionalOpBatchService != null) {
+ this.transactionalOpBatchService.shutdown();
+ }
}
public Message getOpMessage(int queueId, String moreData) {
diff --git a/broker/src/main/resources/rmq.broker.logback.xml b/broker/src/main/resources/rmq.broker.logback.xml
index 3c51e59d4bc..32dc297360e 100644
--- a/broker/src/main/resources/rmq.broker.logback.xml
+++ b/broker/src/main/resources/rmq.broker.logback.xml
@@ -672,6 +672,11 @@
+
+
+
+
+
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
index 75ad961ce9f..6035a20acb2 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
@@ -23,9 +23,9 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import org.apache.rocketmq.broker.latency.FutureTaskExt;
import org.apache.rocketmq.common.BrokerConfig;
import org.apache.rocketmq.common.UtilAll;
+import org.apache.rocketmq.common.future.FutureTaskExt;
import org.apache.rocketmq.remoting.netty.NettyClientConfig;
import org.apache.rocketmq.remoting.netty.NettyServerConfig;
import org.apache.rocketmq.remoting.netty.RequestTask;
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/latency/BrokerFastFailureTest.java b/broker/src/test/java/org/apache/rocketmq/broker/latency/BrokerFastFailureTest.java
index 5d0f7f9d72b..31b547cf1be 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/latency/BrokerFastFailureTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/latency/BrokerFastFailureTest.java
@@ -19,6 +19,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.common.future.FutureTaskExt;
import org.apache.rocketmq.remoting.netty.RequestTask;
import org.junit.Test;
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
index d33a217f76d..ec252cecea6 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
@@ -29,6 +29,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.LongAdder;
import org.apache.rocketmq.broker.BrokerController;
@@ -41,6 +42,7 @@
import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.common.BoundaryType;
import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.TopicFilterType;
@@ -74,7 +76,6 @@
import org.apache.rocketmq.store.DefaultMessageStore;
import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.SelectMappedBufferResult;
-import org.apache.rocketmq.store.config.BrokerRole;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.logfile.DefaultMappedFile;
import org.apache.rocketmq.store.stats.BrokerStats;
@@ -90,8 +91,11 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@@ -245,32 +249,6 @@ public void testUpdateAndCreateTopic() throws Exception {
assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
}
- @Test
- public void testUpdateAndCreateTopicOnSlaveInRocksdb() throws Exception {
- if (notToBeExecuted()) {
- return;
- }
- initRocksdbTopicManager();
- testUpdateAndCreateTopicOnSlave();
- }
-
- @Test
- public void testUpdateAndCreateTopicOnSlave() throws Exception {
- // setup
- MessageStoreConfig messageStoreConfig = mock(MessageStoreConfig.class);
- when(messageStoreConfig.getBrokerRole()).thenReturn(BrokerRole.SLAVE);
- defaultMessageStore = mock(DefaultMessageStore.class);
- when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
-
- // test on slave
- String topic = "TEST_CREATE_TOPIC";
- RemotingCommand request = buildCreateTopicRequest(topic);
- RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
- assertThat(response.getCode()).isEqualTo(ResponseCode.SYSTEM_ERROR);
- assertThat(response.getRemark()).isEqualTo("Can't modify topic or subscription group from slave broker, " +
- "please execute it from master broker.");
- }
-
@Test
public void testDeleteTopicInRocksdb() throws Exception {
if (notToBeExecuted()) {
@@ -297,28 +275,34 @@ public void testDeleteTopic() throws Exception {
}
@Test
- public void testDeleteTopicOnSlaveInRocksdb() throws Exception {
- if (notToBeExecuted()) {
- return;
- }
- initRocksdbTopicManager();
- testDeleteTopicOnSlave();
- }
+ public void testDeleteWithPopRetryTopic() throws Exception {
+ String topic = "topicA";
+ String anotherTopic = "another_topicA";
- @Test
- public void testDeleteTopicOnSlave() throws Exception {
- // setup
- MessageStoreConfig messageStoreConfig = mock(MessageStoreConfig.class);
- when(messageStoreConfig.getBrokerRole()).thenReturn(BrokerRole.SLAVE);
- defaultMessageStore = mock(DefaultMessageStore.class);
- when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
+ topicConfigManager = mock(TopicConfigManager.class);
+ when(brokerController.getTopicConfigManager()).thenReturn(topicConfigManager);
+ final ConcurrentHashMap topicConfigTable = new ConcurrentHashMap<>();
+ topicConfigTable.put(topic, new TopicConfig());
+ topicConfigTable.put(KeyBuilder.buildPopRetryTopic(topic, "cid1"), new TopicConfig());
+
+ topicConfigTable.put(anotherTopic, new TopicConfig());
+ topicConfigTable.put(KeyBuilder.buildPopRetryTopic(anotherTopic, "cid2"), new TopicConfig());
+ when(topicConfigManager.getTopicConfigTable()).thenReturn(topicConfigTable);
+ when(topicConfigManager.selectTopicConfig(anyString())).thenAnswer(invocation -> {
+ final String selectTopic = invocation.getArgument(0);
+ return topicConfigManager.getTopicConfigTable().get(selectTopic);
+ });
+
+ when(brokerController.getConsumerOffsetManager()).thenReturn(consumerOffsetManager);
+ when(consumerOffsetManager.whichGroupByTopic(topic)).thenReturn(Sets.newHashSet("cid1"));
- String topic = "TEST_DELETE_TOPIC";
RemotingCommand request = buildDeleteTopicRequest(topic);
RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
- assertThat(response.getCode()).isEqualTo(ResponseCode.SYSTEM_ERROR);
- assertThat(response.getRemark()).isEqualTo("Can't modify topic or subscription group from slave broker, " +
- "please execute it from master broker.");
+ assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+
+ verify(topicConfigManager).deleteTopicConfig(topic);
+ verify(topicConfigManager).deleteTopicConfig(KeyBuilder.buildPopRetryTopic(topic, "cid1"));
+ verify(messageStore, times(2)).deleteTopics(anySet());
}
@Test
@@ -502,36 +486,6 @@ public void testUpdateAndCreateSubscriptionGroup() throws RemotingCommandExcepti
assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
}
- @Test
- public void testUpdateAndCreateSubscriptionGroupOnSlaveInRocksdb() throws Exception {
- initRocksdbSubscriptionManager();
- testUpdateAndCreateSubscriptionGroupOnSlave();
- }
-
- @Test
- public void testUpdateAndCreateSubscriptionGroupOnSlave() throws RemotingCommandException {
- // Setup
- MessageStoreConfig messageStoreConfig = mock(MessageStoreConfig.class);
- when(messageStoreConfig.getBrokerRole()).thenReturn(BrokerRole.SLAVE);
- defaultMessageStore = mock(DefaultMessageStore.class);
- when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
-
- // Test
- RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_SUBSCRIPTIONGROUP, null);
- SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
- subscriptionGroupConfig.setBrokerId(1);
- subscriptionGroupConfig.setGroupName("groupId");
- subscriptionGroupConfig.setConsumeEnable(Boolean.TRUE);
- subscriptionGroupConfig.setConsumeBroadcastEnable(Boolean.TRUE);
- subscriptionGroupConfig.setRetryMaxTimes(111);
- subscriptionGroupConfig.setConsumeFromMinEnable(Boolean.TRUE);
- request.setBody(JSON.toJSON(subscriptionGroupConfig).toString().getBytes());
- RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
- assertThat(response.getCode()).isEqualTo(ResponseCode.SYSTEM_ERROR);
- assertThat(response.getRemark()).isEqualTo("Can't modify topic or subscription group from slave broker, " +
- "please execute it from master broker.");
- }
-
@Test
public void testGetAllSubscriptionGroupInRocksdb() throws Exception {
initRocksdbSubscriptionManager();
@@ -560,30 +514,6 @@ public void testDeleteSubscriptionGroup() throws RemotingCommandException {
assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
}
- @Test
- public void testDeleteSubscriptionGroupOnSlaveInRocksdb() throws Exception {
- initRocksdbSubscriptionManager();
- testDeleteSubscriptionGroupOnSlave();
- }
-
- @Test
- public void testDeleteSubscriptionGroupOnSlave() throws RemotingCommandException {
- // Setup
- MessageStoreConfig messageStoreConfig = mock(MessageStoreConfig.class);
- when(messageStoreConfig.getBrokerRole()).thenReturn(BrokerRole.SLAVE);
- defaultMessageStore = mock(DefaultMessageStore.class);
- when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
-
- // Test
- RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.DELETE_SUBSCRIPTIONGROUP, null);
- request.addExtField("groupName", "GID-Group-Name");
- request.addExtField("removeOffset", "true");
- RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
- assertThat(response.getCode()).isEqualTo(ResponseCode.SYSTEM_ERROR);
- assertThat(response.getRemark()).isEqualTo("Can't modify topic or subscription group from slave broker, " +
- "please execute it from master broker.");
- }
-
@Test
public void testGetTopicStatsInfo() throws RemotingCommandException {
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_TOPIC_STATS_INFO, null);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
index 1c3a0cd459a..78b76264fef 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
@@ -234,7 +234,7 @@ public static MessageExtBrokerInner buildCkMsg(PopCheckPoint ck) {
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(REVIVE_TOPIC);
- msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(REVIVE_QUEUE_ID);
msgInner.setTags(PopAckConstants.CK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
@@ -269,7 +269,7 @@ public static MessageExtBrokerInner buildAckInnerMessage(String reviveTopic, Ack
SocketAddress host, long deliverMs, String ackUniqueId) {
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(reviveTopic);
- msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.charset));
+ msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
msgInner.setQueueId(reviveQid);
msgInner.setTags(PopAckConstants.ACK_TAG);
msgInner.setBornTimestamp(System.currentTimeMillis());
diff --git a/client/pom.xml b/client/pom.xml
index c59a4388994..d6fb3889b7a 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -19,7 +19,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
index f87450f66c3..f9843cc0231 100644
--- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
+++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
@@ -38,6 +38,8 @@ public class ClientConfig {
public static final String SOCKS_PROXY_CONFIG = "com.rocketmq.socks.proxy.config";
public static final String DECODE_READ_BODY = "com.rocketmq.read.body";
public static final String DECODE_DECOMPRESS_BODY = "com.rocketmq.decompress.body";
+ public static final String SEND_LATENCY_ENABLE = "com.rocketmq.sendLatencyEnable";
+ public static final String START_DETECTOR_ENABLE = "com.rocketmq.startDetectorEnable";
public static final String HEART_BEAT_V2 = "com.rocketmq.heartbeat.v2";
private String namesrvAddr = NameServerAddressUtils.getNameServerAddresses();
private String clientIP = NetworkUtil.getLocalAddress();
@@ -72,6 +74,8 @@ public class ClientConfig {
private String socksProxyConfig = System.getProperty(SOCKS_PROXY_CONFIG, "{}");
private int mqClientApiTimeout = 3 * 1000;
+ private int detectTimeout = 200;
+ private int detectInterval = 2 * 1000;
private LanguageCode language = LanguageCode.JAVA;
@@ -81,6 +85,17 @@ public class ClientConfig {
*/
protected boolean enableStreamRequestType = false;
+ /**
+ * Enable the fault tolerance mechanism of the client sending process.
+ * DO NOT OPEN when ORDER messages are required.
+ * Turning on will interfere with the queue selection functionality,
+ * possibly conflicting with the order message.
+ */
+ private boolean sendLatencyEnable = Boolean.parseBoolean(System.getProperty(SEND_LATENCY_ENABLE, "false"));
+ private boolean startDetectorEnable = Boolean.parseBoolean(System.getProperty(START_DETECTOR_ENABLE, "false"));
+
+ private boolean enableHeartbeatChannelEventListener = true;
+
public String buildMQClientId() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClientIP());
@@ -186,6 +201,11 @@ public void resetClientConfig(final ClientConfig cc) {
this.decodeDecompressBody = cc.decodeDecompressBody;
this.enableStreamRequestType = cc.enableStreamRequestType;
this.useHeartbeatV2 = cc.useHeartbeatV2;
+ this.startDetectorEnable = cc.startDetectorEnable;
+ this.sendLatencyEnable = cc.sendLatencyEnable;
+ this.enableHeartbeatChannelEventListener = cc.enableHeartbeatChannelEventListener;
+ this.detectInterval = cc.detectInterval;
+ this.detectTimeout = cc.detectTimeout;
}
public ClientConfig cloneClientConfig() {
@@ -210,6 +230,11 @@ public ClientConfig cloneClientConfig() {
cc.decodeDecompressBody = decodeDecompressBody;
cc.enableStreamRequestType = enableStreamRequestType;
cc.useHeartbeatV2 = useHeartbeatV2;
+ cc.startDetectorEnable = startDetectorEnable;
+ cc.enableHeartbeatChannelEventListener = enableHeartbeatChannelEventListener;
+ cc.sendLatencyEnable = sendLatencyEnable;
+ cc.detectInterval = detectInterval;
+ cc.detectTimeout = detectTimeout;
return cc;
}
@@ -381,6 +406,46 @@ public void setEnableStreamRequestType(boolean enableStreamRequestType) {
this.enableStreamRequestType = enableStreamRequestType;
}
+ public boolean isSendLatencyEnable() {
+ return sendLatencyEnable;
+ }
+
+ public void setSendLatencyEnable(boolean sendLatencyEnable) {
+ this.sendLatencyEnable = sendLatencyEnable;
+ }
+
+ public boolean isStartDetectorEnable() {
+ return startDetectorEnable;
+ }
+
+ public void setStartDetectorEnable(boolean startDetectorEnable) {
+ this.startDetectorEnable = startDetectorEnable;
+ }
+
+ public boolean isEnableHeartbeatChannelEventListener() {
+ return enableHeartbeatChannelEventListener;
+ }
+
+ public void setEnableHeartbeatChannelEventListener(boolean enableHeartbeatChannelEventListener) {
+ this.enableHeartbeatChannelEventListener = enableHeartbeatChannelEventListener;
+ }
+
+ public int getDetectTimeout() {
+ return this.detectTimeout;
+ }
+
+ public void setDetectTimeout(int detectTimeout) {
+ this.detectTimeout = detectTimeout;
+ }
+
+ public int getDetectInterval() {
+ return this.detectInterval;
+ }
+
+ public void setDetectInterval(int detectInterval) {
+ this.detectInterval = detectInterval;
+ }
+
public boolean isUseHeartbeatV2() {
return useHeartbeatV2;
}
@@ -391,18 +456,34 @@ public void setUseHeartbeatV2(boolean useHeartbeatV2) {
@Override
public String toString() {
- return "ClientConfig [namesrvAddr=" + namesrvAddr
- + ", clientIP=" + clientIP + ", instanceName=" + instanceName
- + ", clientCallbackExecutorThreads=" + clientCallbackExecutorThreads
- + ", pollNameServerInterval=" + pollNameServerInterval
- + ", heartbeatBrokerInterval=" + heartbeatBrokerInterval
- + ", persistConsumerOffsetInterval=" + persistConsumerOffsetInterval
- + ", pullTimeDelayMillsWhenException=" + pullTimeDelayMillsWhenException
- + ", unitMode=" + unitMode + ", unitName=" + unitName
- + ", vipChannelEnabled=" + vipChannelEnabled + ", useTLS=" + useTLS
- + ", socksProxyConfig=" + socksProxyConfig + ", language=" + language.name()
- + ", namespace=" + namespace + ", mqClientApiTimeout=" + mqClientApiTimeout
- + ", decodeReadBody=" + decodeReadBody + ", decodeDecompressBody=" + decodeDecompressBody
- + ", enableStreamRequestType=" + enableStreamRequestType + ", useHeartbeatV2=" + useHeartbeatV2 + "]";
+ return "ClientConfig{" +
+ "namesrvAddr='" + namesrvAddr + '\'' +
+ ", clientIP='" + clientIP + '\'' +
+ ", instanceName='" + instanceName + '\'' +
+ ", clientCallbackExecutorThreads=" + clientCallbackExecutorThreads +
+ ", namespace='" + namespace + '\'' +
+ ", namespaceInitialized=" + namespaceInitialized +
+ ", accessChannel=" + accessChannel +
+ ", pollNameServerInterval=" + pollNameServerInterval +
+ ", heartbeatBrokerInterval=" + heartbeatBrokerInterval +
+ ", persistConsumerOffsetInterval=" + persistConsumerOffsetInterval +
+ ", pullTimeDelayMillsWhenException=" + pullTimeDelayMillsWhenException +
+ ", unitMode=" + unitMode +
+ ", unitName='" + unitName + '\'' +
+ ", decodeReadBody=" + decodeReadBody +
+ ", decodeDecompressBody=" + decodeDecompressBody +
+ ", vipChannelEnabled=" + vipChannelEnabled +
+ ", useHeartbeatV2=" + useHeartbeatV2 +
+ ", useTLS=" + useTLS +
+ ", socksProxyConfig='" + socksProxyConfig + '\'' +
+ ", mqClientApiTimeout=" + mqClientApiTimeout +
+ ", detectTimeout=" + detectTimeout +
+ ", detectInterval=" + detectInterval +
+ ", language=" + language +
+ ", enableStreamRequestType=" + enableStreamRequestType +
+ ", sendLatencyEnable=" + sendLatencyEnable +
+ ", startDetectorEnable=" + startDetectorEnable +
+ ", enableHeartbeatChannelEventListener=" + enableHeartbeatChannelEventListener +
+ '}';
}
}
diff --git a/client/src/main/java/org/apache/rocketmq/client/common/ThreadLocalIndex.java b/client/src/main/java/org/apache/rocketmq/client/common/ThreadLocalIndex.java
index 4a3d90135b6..3a086c13dff 100644
--- a/client/src/main/java/org/apache/rocketmq/client/common/ThreadLocalIndex.java
+++ b/client/src/main/java/org/apache/rocketmq/client/common/ThreadLocalIndex.java
@@ -33,6 +33,14 @@ public int incrementAndGet() {
return index & POSITIVE_MASK;
}
+ public void reset() {
+ int index = Math.abs(random.nextInt(Integer.MAX_VALUE));
+ if (index < 0) {
+ index = 0;
+ }
+ this.threadLocalIndex.set(index);
+ }
+
@Override
public String toString() {
return "ThreadLocalIndex{" +
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java
index 1ef3a948357..83835bd3d3e 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java
@@ -44,6 +44,8 @@
import org.apache.rocketmq.common.message.MessageId;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.utils.NetworkUtil;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.InvokeCallback;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.exception.RemotingException;
@@ -55,8 +57,6 @@
import org.apache.rocketmq.remoting.protocol.header.QueryMessageResponseHeader;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
public class MQAdminImpl {
@@ -357,44 +357,51 @@ protected QueryResult queryMessage(String clusterName, String topic, String key,
new InvokeCallback() {
@Override
public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
try {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- switch (response.getCode()) {
- case ResponseCode.SUCCESS: {
- QueryMessageResponseHeader responseHeader = null;
- try {
- responseHeader =
- (QueryMessageResponseHeader) response
- .decodeCommandCustomHeader(QueryMessageResponseHeader.class);
- } catch (RemotingCommandException e) {
- log.error("decodeCommandCustomHeader exception", e);
- return;
- }
-
- List wrappers =
- MessageDecoder.decodes(ByteBuffer.wrap(response.getBody()), true);
-
- QueryResult qr = new QueryResult(responseHeader.getIndexLastUpdateTimestamp(), wrappers);
- try {
- lock.writeLock().lock();
- queryResultList.add(qr);
- } finally {
- lock.writeLock().unlock();
- }
- break;
+ switch (response.getCode()) {
+ case ResponseCode.SUCCESS: {
+ QueryMessageResponseHeader responseHeader = null;
+ try {
+ responseHeader =
+ (QueryMessageResponseHeader) response
+ .decodeCommandCustomHeader(QueryMessageResponseHeader.class);
+ } catch (RemotingCommandException e) {
+ log.error("decodeCommandCustomHeader exception", e);
+ return;
}
- default:
- log.warn("getResponseCommand failed, {} {}", response.getCode(), response.getRemark());
- break;
+
+ List wrappers =
+ MessageDecoder.decodes(ByteBuffer.wrap(response.getBody()), true);
+
+ QueryResult qr = new QueryResult(responseHeader.getIndexLastUpdateTimestamp(), wrappers);
+ try {
+ lock.writeLock().lock();
+ queryResultList.add(qr);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ break;
}
- } else {
- log.warn("getResponseCommand return null");
+ default:
+ log.warn("getResponseCommand failed, {} {}", response.getCode(), response.getRemark());
+ break;
}
+
} finally {
countDownLatch.countDown();
}
}
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ log.error("queryMessage error, requestHeader={}", requestHeader);
+ countDownLatch.countDown();
+ }
}, isUniqKey);
} catch (Exception e) {
log.warn("queryMessage exception", e);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 5101ffc8e42..e152be81193 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -21,6 +21,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -32,7 +33,6 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.Validators;
-import org.apache.rocketmq.client.common.ClientErrorCode;
import org.apache.rocketmq.client.consumer.AckCallback;
import org.apache.rocketmq.client.consumer.AckResult;
import org.apache.rocketmq.client.consumer.AckStatus;
@@ -54,6 +54,7 @@
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.AclConfig;
+import org.apache.rocketmq.common.BoundaryType;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.Pair;
@@ -76,7 +77,9 @@
import org.apache.rocketmq.common.namesrv.TopAddressing;
import org.apache.rocketmq.common.sysflag.PullSysFlag;
import org.apache.rocketmq.common.topic.TopicValidator;
-import org.apache.rocketmq.common.BoundaryType;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.InvokeCallback;
import org.apache.rocketmq.remoting.RPCHook;
@@ -101,7 +104,10 @@
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
+import org.apache.rocketmq.remoting.protocol.body.BatchAck;
+import org.apache.rocketmq.remoting.protocol.body.BatchAckMessageRequestBody;
import org.apache.rocketmq.remoting.protocol.body.BrokerMemberGroup;
+import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
import org.apache.rocketmq.remoting.protocol.body.CheckClientRequestBody;
import org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo;
@@ -114,7 +120,6 @@
import org.apache.rocketmq.remoting.protocol.body.GetConsumerStatusBody;
import org.apache.rocketmq.remoting.protocol.body.GroupList;
import org.apache.rocketmq.remoting.protocol.body.HARuntimeInfo;
-import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
import org.apache.rocketmq.remoting.protocol.body.KVTable;
import org.apache.rocketmq.remoting.protocol.body.LockBatchRequestBody;
import org.apache.rocketmq.remoting.protocol.body.LockBatchResponseBody;
@@ -196,6 +201,10 @@
import org.apache.rocketmq.remoting.protocol.header.UpdateGroupForbiddenRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ViewBrokerStatsDataRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ViewMessageRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.admin.CleanControllerBrokerDataRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.AddWritePermOfBrokerRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.AddWritePermOfBrokerResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.DeleteKVConfigRequestHeader;
@@ -207,10 +216,6 @@
import org.apache.rocketmq.remoting.protocol.header.namesrv.PutKVConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.WipeWritePermOfBrokerRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.namesrv.WipeWritePermOfBrokerResponseHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.admin.CleanControllerBrokerDataRequestHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterRequestHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.HeartbeatData;
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
@@ -221,8 +226,6 @@
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.remoting.rpchook.DynamicalExtFieldRPCHook;
import org.apache.rocketmq.remoting.rpchook.StreamTypeRPCHook;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import static org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode.SUCCESS;
@@ -244,10 +247,16 @@ public class MQClientAPIImpl implements NameServerUpdateCallback {
public MQClientAPIImpl(final NettyClientConfig nettyClientConfig,
final ClientRemotingProcessor clientRemotingProcessor,
RPCHook rpcHook, final ClientConfig clientConfig) {
+ this(nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig, null);
+ }
+
+ public MQClientAPIImpl(final NettyClientConfig nettyClientConfig,
+ final ClientRemotingProcessor clientRemotingProcessor,
+ RPCHook rpcHook, final ClientConfig clientConfig, final ChannelEventListener channelEventListener) {
this.clientConfig = clientConfig;
topAddressing = new DefaultTopAddressing(MixAll.getWSAddr(), clientConfig.getUnitName());
topAddressing.registerChangeCallBack(this);
- this.remotingClient = new NettyRemotingClient(nettyClientConfig, null);
+ this.remotingClient = new NettyRemotingClient(nettyClientConfig, channelEventListener);
this.clientRemotingProcessor = clientRemotingProcessor;
// Inject stream rpc hook first to make reserve field signature
@@ -650,10 +659,13 @@ private void sendMessageAsync(
this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
@Override
public void operationComplete(ResponseFuture responseFuture) {
- long cost = System.currentTimeMillis() - beginStartTime;
- RemotingCommand response = responseFuture.getResponseCommand();
- if (null == sendCallback && response != null) {
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ long cost = System.currentTimeMillis() - beginStartTime;
+ if (null == sendCallback) {
try {
SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response, addr);
if (context != null && sendResult != null) {
@@ -663,52 +675,53 @@ public void operationComplete(ResponseFuture responseFuture) {
} catch (Throwable e) {
}
- producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), false);
+ producer.updateFaultItem(brokerName, System.currentTimeMillis() - beginStartTime, false, true);
return;
}
- if (response != null) {
+ try {
+ SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response, addr);
+ assert sendResult != null;
+ if (context != null) {
+ context.setSendResult(sendResult);
+ context.getProducer().executeSendMessageHookAfter(context);
+ }
+
try {
- SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response, addr);
- assert sendResult != null;
- if (context != null) {
- context.setSendResult(sendResult);
- context.getProducer().executeSendMessageHookAfter(context);
- }
+ sendCallback.onSuccess(sendResult);
+ } catch (Throwable e) {
+ }
- try {
- sendCallback.onSuccess(sendResult);
- } catch (Throwable e) {
- }
+ producer.updateFaultItem(brokerName, System.currentTimeMillis() - beginStartTime, false, true);
+ } catch (Exception e) {
+ producer.updateFaultItem(brokerName, System.currentTimeMillis() - beginStartTime, true, true);
+ onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
+ retryTimesWhenSendFailed, times, e, context, false, producer);
+ }
+ }
- producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), false);
- } catch (Exception e) {
- producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), true);
- onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
- retryTimesWhenSendFailed, times, e, context, false, producer);
- }
+ @Override
+ public void operationFail(Throwable throwable) {
+ producer.updateFaultItem(brokerName, System.currentTimeMillis() - beginStartTime, true, true);
+ long cost = System.currentTimeMillis() - beginStartTime;
+ if (throwable instanceof RemotingSendRequestException) {
+ MQClientException ex = new MQClientException("send request failed", throwable);
+ onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
+ retryTimesWhenSendFailed, times, ex, context, true, producer);
+ } else if (throwable instanceof RemotingTimeoutException) {
+ MQClientException ex = new MQClientException("wait response timeout, cost=" + cost, throwable);
+ onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
+ retryTimesWhenSendFailed, times, ex, context, true, producer);
} else {
- producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), true);
- if (!responseFuture.isSendRequestOK()) {
- MQClientException ex = new MQClientException("send request failed", responseFuture.getCause());
- onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
- retryTimesWhenSendFailed, times, ex, context, true, producer);
- } else if (responseFuture.isTimeout()) {
- MQClientException ex = new MQClientException("wait response timeout " + responseFuture.getTimeoutMillis() + "ms",
- responseFuture.getCause());
- onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
- retryTimesWhenSendFailed, times, ex, context, true, producer);
- } else {
- MQClientException ex = new MQClientException("unknow reseaon", responseFuture.getCause());
- onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
- retryTimesWhenSendFailed, times, ex, context, true, producer);
- }
+ MQClientException ex = new MQClientException("unknow reseaon", throwable);
+ onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
+ retryTimesWhenSendFailed, times, ex, context, true, producer);
}
}
});
} catch (Exception ex) {
long cost = System.currentTimeMillis() - beginStartTime;
- producer.updateFaultItem(brokerName, cost, true);
+ producer.updateFaultItem(brokerName, cost, true, false);
onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
retryTimesWhenSendFailed, times, ex, context, true, producer);
}
@@ -732,7 +745,7 @@ private void onExceptionImpl(final String brokerName,
if (needRetry && tmp <= timesTotal) {
String retryBrokerName = brokerName;//by default, it will send to the same broker
if (topicPublishInfo != null) { //select one message queue accordingly, in order to determine which broker to send
- MessageQueue mqChosen = producer.selectOneMessageQueue(topicPublishInfo, brokerName);
+ MessageQueue mqChosen = producer.selectOneMessageQueue(topicPublishInfo, brokerName, false);
retryBrokerName = instance.getBrokerNameFromMessageQueue(mqChosen);
}
String addr = instance.findBrokerAddressInPublish(retryBrokerName);
@@ -854,30 +867,25 @@ public void popMessageAsync(
final long timeoutMillis, final PopCallback popCallback
) throws RemotingException, InterruptedException {
final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader);
- this.remotingClient.invokeAsync(addr, request, timeoutMillis, new BaseInvokeCallback(MQClientAPIImpl.this) {
+ this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
@Override
- public void onComplete(ResponseFuture responseFuture) {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- PopResult
- popResult = MQClientAPIImpl.this.processPopResponse(brokerName, response, requestHeader.getTopic(), requestHeader);
- assert popResult != null;
- popCallback.onSuccess(popResult);
- } catch (Exception e) {
- popCallback.onException(e);
- }
- } else {
- if (!responseFuture.isSendRequestOK()) {
- popCallback.onException(new MQClientException(ClientErrorCode.CONNECT_BROKER_EXCEPTION, "send request failed to " + addr + ". Request: " + request, responseFuture.getCause()));
- } else if (responseFuture.isTimeout()) {
- popCallback.onException(new MQClientException(ClientErrorCode.ACCESS_BROKER_TIMEOUT, "wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request,
- responseFuture.getCause()));
- } else {
- popCallback.onException(new MQClientException("unknown reason. addr: " + addr + ", timeoutMillis: " + timeoutMillis + ". Request: " + request, responseFuture.getCause()));
- }
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ try {
+ PopResult popResult = MQClientAPIImpl.this.processPopResponse(brokerName, response, requestHeader.getTopic(), requestHeader);
+ popCallback.onSuccess(popResult);
+ } catch (Exception e) {
+ popCallback.onException(e);
}
}
+ @Override
+ public void operationFail(Throwable throwable) {
+ popCallback.onException(throwable);
+ }
});
}
@@ -885,37 +893,97 @@ public void ackMessageAsync(
final String addr,
final long timeOut,
final AckCallback ackCallback,
- final AckMessageRequestHeader requestHeader //
+ final AckMessageRequestHeader requestHeader
+ ) throws RemotingException, MQBrokerException, InterruptedException {
+ ackMessageAsync(addr, timeOut, ackCallback, requestHeader, null);
+ }
+
+ public void batchAckMessageAsync(
+ final String addr,
+ final long timeOut,
+ final AckCallback ackCallback,
+ final String topic,
+ final String consumerGroup,
+ final List extraInfoList
+ ) throws RemotingException, MQBrokerException, InterruptedException {
+ String brokerName = null;
+ Map batchAckMap = new HashMap<>();
+ for (String extraInfo : extraInfoList) {
+ String[] extraInfoData = ExtraInfoUtil.split(extraInfo);
+ if (brokerName == null) {
+ brokerName = ExtraInfoUtil.getBrokerName(extraInfoData);
+ }
+ String mergeKey = ExtraInfoUtil.getRetry(extraInfoData) + "@" +
+ ExtraInfoUtil.getQueueId(extraInfoData) + "@" +
+ ExtraInfoUtil.getCkQueueOffset(extraInfoData) + "@" +
+ ExtraInfoUtil.getPopTime(extraInfoData);
+ BatchAck bAck = batchAckMap.computeIfAbsent(mergeKey, k -> {
+ BatchAck newBatchAck = new BatchAck();
+ newBatchAck.setConsumerGroup(consumerGroup);
+ newBatchAck.setTopic(topic);
+ newBatchAck.setRetry(ExtraInfoUtil.getRetry(extraInfoData));
+ newBatchAck.setStartOffset(ExtraInfoUtil.getCkQueueOffset(extraInfoData));
+ newBatchAck.setQueueId(ExtraInfoUtil.getQueueId(extraInfoData));
+ newBatchAck.setReviveQueueId(ExtraInfoUtil.getReviveQid(extraInfoData));
+ newBatchAck.setPopTime(ExtraInfoUtil.getPopTime(extraInfoData));
+ newBatchAck.setInvisibleTime(ExtraInfoUtil.getInvisibleTime(extraInfoData));
+ newBatchAck.setBitSet(new BitSet());
+ return newBatchAck;
+ });
+ bAck.getBitSet().set((int) (ExtraInfoUtil.getQueueOffset(extraInfoData) - ExtraInfoUtil.getCkQueueOffset(extraInfoData)));
+ }
+
+ BatchAckMessageRequestBody requestBody = new BatchAckMessageRequestBody();
+ requestBody.setBrokerName(brokerName);
+ requestBody.setAcks(new ArrayList<>(batchAckMap.values()));
+ batchAckMessageAsync(addr, timeOut, ackCallback, requestBody);
+ }
+
+ public void batchAckMessageAsync(
+ final String addr,
+ final long timeOut,
+ final AckCallback ackCallback,
+ final BatchAckMessageRequestBody requestBody
) throws RemotingException, MQBrokerException, InterruptedException {
- final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader);
- this.remotingClient.invokeAsync(addr, request, timeOut, new BaseInvokeCallback(MQClientAPIImpl.this) {
+ ackMessageAsync(addr, timeOut, ackCallback, null, requestBody);
+ }
+ protected void ackMessageAsync(
+ final String addr,
+ final long timeOut,
+ final AckCallback ackCallback,
+ final AckMessageRequestHeader requestHeader,
+ final BatchAckMessageRequestBody requestBody
+ ) throws RemotingException, MQBrokerException, InterruptedException {
+ RemotingCommand request;
+ if (requestHeader != null) {
+ request = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader);
+ } else {
+ request = RemotingCommand.createRequestCommand(RequestCode.BATCH_ACK_MESSAGE, null);
+ if (requestBody != null) {
+ request.setBody(requestBody.encode());
+ }
+ }
+ this.remotingClient.invokeAsync(addr, request, timeOut, new InvokeCallback() {
@Override
- public void onComplete(ResponseFuture responseFuture) {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- AckResult ackResult = new AckResult();
- if (ResponseCode.SUCCESS == response.getCode()) {
- ackResult.setStatus(AckStatus.OK);
- } else {
- ackResult.setStatus(AckStatus.NO_EXIST);
- }
- ackCallback.onSuccess(ackResult);
- } catch (Exception e) {
- ackCallback.onException(e);
- }
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ AckResult ackResult = new AckResult();
+ if (ResponseCode.SUCCESS == response.getCode()) {
+ ackResult.setStatus(AckStatus.OK);
} else {
- if (!responseFuture.isSendRequestOK()) {
- ackCallback.onException(new MQClientException(ClientErrorCode.CONNECT_BROKER_EXCEPTION, "send request failed to " + addr + ". Request: " + request, responseFuture.getCause()));
- } else if (responseFuture.isTimeout()) {
- ackCallback.onException(new MQClientException(ClientErrorCode.ACCESS_BROKER_TIMEOUT, "wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request,
- responseFuture.getCause()));
- } else {
- ackCallback.onException(new MQClientException("unknown reason. addr: " + addr + ", timeoutMillis: " + timeOut + ". Request: " + request, responseFuture.getCause()));
- }
+ ackResult.setStatus(AckStatus.NO_EXIST);
}
+ ackCallback.onSuccess(ackResult);
+ }
+ @Override
+ public void operationFail(Throwable throwable) {
+ ackCallback.onException(throwable);
}
});
}
@@ -928,39 +996,37 @@ public void changeInvisibleTimeAsync(//
final AckCallback ackCallback
) throws RemotingException, MQBrokerException, InterruptedException {
final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader);
- this.remotingClient.invokeAsync(addr, request, timeoutMillis, new BaseInvokeCallback(MQClientAPIImpl.this) {
+ this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
@Override
- public void onComplete(ResponseFuture responseFuture) {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) response.decodeCommandCustomHeader(ChangeInvisibleTimeResponseHeader.class);
- AckResult ackResult = new AckResult();
- if (ResponseCode.SUCCESS == response.getCode()) {
- ackResult.setStatus(AckStatus.OK);
- ackResult.setPopTime(responseHeader.getPopTime());
- ackResult.setExtraInfo(ExtraInfoUtil
- .buildExtraInfo(requestHeader.getOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(),
- responseHeader.getReviveQid(), requestHeader.getTopic(), brokerName, requestHeader.getQueueId()) + MessageConst.KEY_SEPARATOR
- + requestHeader.getOffset());
- } else {
- ackResult.setStatus(AckStatus.NO_EXIST);
- }
- ackCallback.onSuccess(ackResult);
- } catch (Exception e) {
- ackCallback.onException(e);
- }
- } else {
- if (!responseFuture.isSendRequestOK()) {
- ackCallback.onException(new MQClientException(ClientErrorCode.CONNECT_BROKER_EXCEPTION, "send request failed to " + addr + ". Request: " + request, responseFuture.getCause()));
- } else if (responseFuture.isTimeout()) {
- ackCallback.onException(new MQClientException(ClientErrorCode.ACCESS_BROKER_TIMEOUT, "wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request,
- responseFuture.getCause()));
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ try {
+ ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) response.decodeCommandCustomHeader(ChangeInvisibleTimeResponseHeader.class);
+ AckResult ackResult = new AckResult();
+ if (ResponseCode.SUCCESS == response.getCode()) {
+ ackResult.setStatus(AckStatus.OK);
+ ackResult.setPopTime(responseHeader.getPopTime());
+ ackResult.setExtraInfo(ExtraInfoUtil
+ .buildExtraInfo(requestHeader.getOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(),
+ responseHeader.getReviveQid(), requestHeader.getTopic(), brokerName, requestHeader.getQueueId()) + MessageConst.KEY_SEPARATOR
+ + requestHeader.getOffset());
} else {
- ackCallback.onException(new MQClientException("unknown reason. addr: " + addr + ", timeoutMillis: " + timeoutMillis + ". Request: " + request, responseFuture.getCause()));
+ ackResult.setStatus(AckStatus.NO_EXIST);
}
+ ackCallback.onSuccess(ackResult);
+ } catch (Exception e) {
+ ackCallback.onException(e);
}
}
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ ackCallback.onException(throwable);
+ }
});
}
@@ -973,26 +1039,23 @@ private void pullMessageAsync(
this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
@Override
public void operationComplete(ResponseFuture responseFuture) {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- PullResult pullResult = MQClientAPIImpl.this.processPullResponse(response, addr);
- assert pullResult != null;
- pullCallback.onSuccess(pullResult);
- } catch (Exception e) {
- pullCallback.onException(e);
- }
- } else {
- if (!responseFuture.isSendRequestOK()) {
- pullCallback.onException(new MQClientException(ClientErrorCode.CONNECT_BROKER_EXCEPTION, "send request failed to " + addr + ". Request: " + request, responseFuture.getCause()));
- } else if (responseFuture.isTimeout()) {
- pullCallback.onException(new MQClientException(ClientErrorCode.ACCESS_BROKER_TIMEOUT, "wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request,
- responseFuture.getCause()));
- } else {
- pullCallback.onException(new MQClientException("unknown reason. addr: " + addr + ", timeoutMillis: " + timeoutMillis + ". Request: " + request, responseFuture.getCause()));
- }
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ try {
+ PullResult pullResult = MQClientAPIImpl.this.processPullResponse(response, addr);
+ pullCallback.onSuccess(pullResult);
+ } catch (Exception e) {
+ pullCallback.onException(e);
}
}
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ pullCallback.onException(throwable);
+ }
});
}
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 8851bc81599..09534a1768b 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.client.impl.factory;
+import io.netty.channel.Channel;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -29,6 +30,7 @@
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
@@ -64,6 +66,7 @@
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.message.MessageQueueAssignment;
import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.remoting.ChannelEventListener;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.common.HeartbeatV2Result;
import org.apache.rocketmq.remoting.exception.RemotingException;
@@ -125,6 +128,12 @@ public class MQClientInstance {
private final Set brokerSupportV2HeartbeatSet = new HashSet();
private final ConcurrentMap brokerAddrHeartbeatFingerprintTable = new ConcurrentHashMap();
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "MQClientFactoryScheduledThread"));
+ private final ScheduledExecutorService fetchRemoteConfigExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "MQClientFactoryFetchRemoteConfigScheduledThread");
+ }
+ });
private final PullMessageService pullMessageService;
private final RebalanceService rebalanceService;
private final DefaultMQProducer defaultMQProducer;
@@ -144,7 +153,38 @@ public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String cli
this.nettyClientConfig.setUseTLS(clientConfig.isUseTLS());
this.nettyClientConfig.setSocksProxyConfig(clientConfig.getSocksProxyConfig());
ClientRemotingProcessor clientRemotingProcessor = new ClientRemotingProcessor(this);
- this.mQClientAPIImpl = new MQClientAPIImpl(this.nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig);
+ ChannelEventListener channelEventListener;
+ if (clientConfig.isEnableHeartbeatChannelEventListener()) {
+ channelEventListener = new ChannelEventListener() {
+ private final ConcurrentMap> brokerAddrTable = MQClientInstance.this.brokerAddrTable;
+ @Override
+ public void onChannelConnect(String remoteAddr, Channel channel) {
+ for (Map.Entry> addressEntry : brokerAddrTable.entrySet()) {
+ for (String address : addressEntry.getValue().values()) {
+ if (address.equals(remoteAddr)) {
+ sendHeartbeatToAllBrokerWithLockV2(false);
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onChannelClose(String remoteAddr, Channel channel) {
+ }
+
+ @Override
+ public void onChannelException(String remoteAddr, Channel channel) {
+ }
+
+ @Override
+ public void onChannelIdle(String remoteAddr, Channel channel) {
+ }
+ };
+ } else {
+ channelEventListener = null;
+ }
+ this.mQClientAPIImpl = new MQClientAPIImpl(this.nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig, channelEventListener);
if (this.clientConfig.getNamesrvAddr() != null) {
this.mQClientAPIImpl.updateNameServerAddressList(this.clientConfig.getNamesrvAddr());
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/mqclient/MQClientAPIExt.java b/client/src/main/java/org/apache/rocketmq/client/impl/mqclient/MQClientAPIExt.java
index fb8f8d11fd4..f3102e17597 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/mqclient/MQClientAPIExt.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/mqclient/MQClientAPIExt.java
@@ -30,7 +30,6 @@
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.client.exception.MQBrokerException;
-import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.exception.OffsetNotFoundException;
import org.apache.rocketmq.client.impl.ClientRemotingProcessor;
import org.apache.rocketmq.client.impl.CommunicationMode;
@@ -47,6 +46,7 @@
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.InvokeCallback;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.netty.NettyClientConfig;
@@ -106,19 +106,6 @@ public boolean updateNameServerAddressList() {
return false;
}
- protected static MQClientException processNullResponseErr(ResponseFuture responseFuture) {
- MQClientException ex;
- if (!responseFuture.isSendRequestOK()) {
- ex = new MQClientException("send request failed", responseFuture.getCause());
- } else if (responseFuture.isTimeout()) {
- ex = new MQClientException("wait response timeout " + responseFuture.getTimeoutMillis() + "ms",
- responseFuture.getCause());
- } else {
- ex = new MQClientException("unknown reason", responseFuture.getCause());
- }
- return ex;
- }
-
public CompletableFuture sendHeartbeatOneway(
String brokerAddr,
HeartbeatData heartbeatData,
@@ -146,24 +133,15 @@ public CompletableFuture sendHeartbeatAsync(
request.setLanguage(clientConfig.getLanguage());
request.setBody(heartbeatData.encode());
- CompletableFuture future = new CompletableFuture<>();
- try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- if (ResponseCode.SUCCESS == response.getCode()) {
- future.complete(response.getVersion());
- } else {
- future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark(), brokerAddr));
- }
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
- }
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ if (ResponseCode.SUCCESS == response.getCode()) {
+ future0.complete(response.getVersion());
+ } else {
+ future0.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark(), brokerAddr));
+ }
+ return future0;
+ });
}
public CompletableFuture sendMessageAsync(
@@ -177,24 +155,15 @@ public CompletableFuture sendMessageAsync(
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE_V2, requestHeaderV2);
request.setBody(msg.getBody());
- CompletableFuture future = new CompletableFuture<>();
- try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- future.complete(this.processSendResponse(brokerName, msg, response, brokerAddr));
- } catch (Exception e) {
- future.completeExceptionally(e);
- }
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
- }
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ try {
+ future0.complete(this.processSendResponse(brokerName, msg, response, brokerAddr));
+ } catch (Exception e) {
+ future0.completeExceptionally(e);
+ }
+ return future0;
+ });
}
public CompletableFuture sendMessageAsync(
@@ -216,17 +185,14 @@ public CompletableFuture sendMessageAsync(
msgBatch.setBody(body);
request.setBody(body);
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- try {
- future.complete(this.processSendResponse(brokerName, msgBatch, response, brokerAddr));
- } catch (Exception e) {
- future.completeExceptionally(e);
- }
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ try {
+ future0.complete(processSendResponse(brokerName, msgBatch, response, brokerAddr));
+ } catch (Exception e) {
+ future0.completeExceptionally(e);
}
+ return future0;
});
} catch (Throwable t) {
future.completeExceptionally(t);
@@ -240,21 +206,7 @@ public CompletableFuture sendMessageBackAsync(
long timeoutMillis
) {
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader);
-
- CompletableFuture future = new CompletableFuture<>();
- try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- future.complete(response);
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
- }
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis);
}
public CompletableFuture popMessageAsync(
@@ -306,6 +258,32 @@ public void onException(Throwable t) {
return future;
}
+ public CompletableFuture batchAckMessageAsync(
+ String brokerAddr,
+ String topic,
+ String consumerGroup,
+ List extraInfoList,
+ long timeoutMillis
+ ) {
+ CompletableFuture future = new CompletableFuture<>();
+ try {
+ this.batchAckMessageAsync(brokerAddr, timeoutMillis, new AckCallback() {
+ @Override
+ public void onSuccess(AckResult ackResult) {
+ future.complete(ackResult);
+ }
+
+ @Override
+ public void onException(Throwable t) {
+ future.completeExceptionally(t);
+ }
+ }, topic, consumerGroup, extraInfoList);
+ } catch (Throwable t) {
+ future.completeExceptionally(t);
+ }
+ return future;
+ }
+
public CompletableFuture changeInvisibleTimeAsync(
String brokerAddr,
String brokerName,
@@ -376,38 +354,31 @@ public CompletableFuture queryConsumerOffsetWithFuture(
QueryConsumerOffsetRequestHeader requestHeader,
long timeoutMillis
) {
- CompletableFuture future = new CompletableFuture<>();
- try {
- RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUMER_OFFSET, requestHeader);
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- switch (response.getCode()) {
- case ResponseCode.SUCCESS: {
- try {
- QueryConsumerOffsetResponseHeader responseHeader =
- (QueryConsumerOffsetResponseHeader) response.decodeCommandCustomHeader(QueryConsumerOffsetResponseHeader.class);
- future.complete(responseHeader.getOffset());
- } catch (RemotingCommandException e) {
- future.completeExceptionally(e);
- }
- break;
- }
- case ResponseCode.QUERY_NOT_FOUND: {
- future.completeExceptionally(new OffsetNotFoundException(response.getCode(), response.getRemark(), brokerAddr));
- break;
- }
- default:
- break;
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUMER_OFFSET, requestHeader);
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ switch (response.getCode()) {
+ case ResponseCode.SUCCESS: {
+ try {
+ QueryConsumerOffsetResponseHeader responseHeader =
+ (QueryConsumerOffsetResponseHeader) response.decodeCommandCustomHeader(QueryConsumerOffsetResponseHeader.class);
+ future0.complete(responseHeader.getOffset());
+ } catch (RemotingCommandException e) {
+ future0.completeExceptionally(e);
}
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ break;
}
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ case ResponseCode.QUERY_NOT_FOUND: {
+ future0.completeExceptionally(new OffsetNotFoundException(response.getCode(), response.getRemark(), brokerAddr));
+ break;
+ }
+ default: {
+ future0.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
+ break;
+ }
+ }
+ return future0;
+ });
}
public CompletableFuture updateConsumerOffsetOneWay(
@@ -435,9 +406,14 @@ public CompletableFuture> getConsumerListByGroupAsync(
CompletableFuture> future = new CompletableFuture<>();
try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
+ this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
if (response.getBody() != null) {
@@ -459,8 +435,11 @@ public CompletableFuture> getConsumerListByGroupAsync(
break;
}
future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ }
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ future.completeExceptionally(throwable);
}
});
} catch (Throwable t) {
@@ -475,9 +454,14 @@ public CompletableFuture getMaxOffset(String brokerAddr, GetMaxOffsetReque
CompletableFuture future = new CompletableFuture<>();
try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
+ this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
if (ResponseCode.SUCCESS == response.getCode()) {
try {
GetMaxOffsetResponseHeader responseHeader = (GetMaxOffsetResponseHeader) response.decodeCommandCustomHeader(GetMaxOffsetResponseHeader.class);
@@ -487,8 +471,11 @@ public CompletableFuture getMaxOffset(String brokerAddr, GetMaxOffsetReque
}
}
future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ }
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ future.completeExceptionally(throwable);
}
});
} catch (Throwable t) {
@@ -503,9 +490,14 @@ public CompletableFuture getMinOffset(String brokerAddr, GetMinOffsetReque
CompletableFuture future = new CompletableFuture<>();
try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
+ this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
if (ResponseCode.SUCCESS == response.getCode()) {
try {
GetMinOffsetResponseHeader responseHeader = (GetMinOffsetResponseHeader) response.decodeCommandCustomHeader(GetMinOffsetResponseHeader.class);
@@ -515,8 +507,11 @@ public CompletableFuture getMinOffset(String brokerAddr, GetMinOffsetReque
}
}
future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ }
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ future.completeExceptionally(throwable);
}
});
} catch (Throwable t) {
@@ -529,57 +524,41 @@ public CompletableFuture searchOffset(String brokerAddr, SearchOffsetReque
long timeoutMillis) {
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader);
- CompletableFuture future = new CompletableFuture<>();
- try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- if (response.getCode() == ResponseCode.SUCCESS) {
- try {
- SearchOffsetResponseHeader responseHeader = (SearchOffsetResponseHeader) response.decodeCommandCustomHeader(SearchOffsetResponseHeader.class);
- future.complete(responseHeader.getOffset());
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- }
- future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ if (response.getCode() == ResponseCode.SUCCESS) {
+ try {
+ SearchOffsetResponseHeader responseHeader = (SearchOffsetResponseHeader) response.decodeCommandCustomHeader(SearchOffsetResponseHeader.class);
+ future0.complete(responseHeader.getOffset());
+ } catch (Throwable t) {
+ future0.completeExceptionally(t);
}
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ } else {
+ future0.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
+ }
+ return future0;
+ });
}
public CompletableFuture> lockBatchMQWithFuture(String brokerAddr,
LockBatchRequestBody requestBody, long timeoutMillis) {
- CompletableFuture> future = new CompletableFuture<>();
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.LOCK_BATCH_MQ, null);
request.setBody(requestBody.encode());
- try {
- this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> {
- RemotingCommand response = responseFuture.getResponseCommand();
- if (response != null) {
- if (response.getCode() == ResponseCode.SUCCESS) {
- try {
- LockBatchResponseBody responseBody = LockBatchResponseBody.decode(response.getBody(), LockBatchResponseBody.class);
- Set messageQueues = responseBody.getLockOKMQSet();
- future.complete(messageQueues);
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- }
- future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
- } else {
- future.completeExceptionally(processNullResponseErr(responseFuture));
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture> future0 = new CompletableFuture<>();
+ if (response.getCode() == ResponseCode.SUCCESS) {
+ try {
+ LockBatchResponseBody responseBody = LockBatchResponseBody.decode(response.getBody(), LockBatchResponseBody.class);
+ Set messageQueues = responseBody.getLockOKMQSet();
+ future0.complete(messageQueues);
+ } catch (Throwable t) {
+ future0.completeExceptionally(t);
}
- });
- } catch (Exception e) {
- future.completeExceptionally(e);
- }
- return future;
+ } else {
+ future0.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
+ }
+ return future0;
+ });
}
public CompletableFuture unlockBatchMQOneway(String brokerAddr,
@@ -598,25 +577,21 @@ public CompletableFuture unlockBatchMQOneway(String brokerAddr,
public CompletableFuture notification(String brokerAddr, NotificationRequestHeader requestHeader,
long timeoutMillis) {
- CompletableFuture future = new CompletableFuture<>();
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.NOTIFICATION, requestHeader);
- try {
- this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenAccept(response -> {
- if (response.getCode() == ResponseCode.SUCCESS) {
- try {
- NotificationResponseHeader responseHeader = (NotificationResponseHeader) response.decodeCommandCustomHeader(NotificationResponseHeader.class);
- future.complete(responseHeader.isHasMsg());
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- } else {
- future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
+ return this.getRemotingClient().invoke(brokerAddr, request, timeoutMillis).thenCompose(response -> {
+ CompletableFuture future0 = new CompletableFuture<>();
+ if (response.getCode() == ResponseCode.SUCCESS) {
+ try {
+ NotificationResponseHeader responseHeader = (NotificationResponseHeader) response.decodeCommandCustomHeader(NotificationResponseHeader.class);
+ future0.complete(responseHeader.isHasMsg());
+ } catch (Throwable t) {
+ future0.completeExceptionally(t);
}
- });
- } catch (Throwable t) {
- future.completeExceptionally(t);
- }
- return future;
+ } else {
+ future0.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark()));
+ }
+ return future0;
+ });
}
public CompletableFuture invoke(String brokerAddr, RemotingCommand request, long timeoutMillis) {
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
index 3f4c6e5f7a4..b0c212e46b6 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
@@ -33,6 +33,8 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+
+import com.google.common.base.Optional;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.Validators;
import org.apache.rocketmq.client.common.ClientErrorCode;
@@ -49,6 +51,8 @@
import org.apache.rocketmq.client.impl.MQClientManager;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
import org.apache.rocketmq.client.latency.MQFaultStrategy;
+import org.apache.rocketmq.client.latency.Resolver;
+import org.apache.rocketmq.client.latency.ServiceDetector;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.LocalTransactionExecuter;
import org.apache.rocketmq.client.producer.LocalTransactionState;
@@ -112,7 +116,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
private ServiceState serviceState = ServiceState.CREATE_JUST;
private MQClientInstance mQClientFactory;
private ArrayList checkForbiddenHookList = new ArrayList<>();
- private MQFaultStrategy mqFaultStrategy = new MQFaultStrategy();
+ private MQFaultStrategy mqFaultStrategy;
private ExecutorService asyncSenderExecutor;
// compression related
@@ -153,8 +157,38 @@ public DefaultMQProducerImpl(final DefaultMQProducer defaultMQProducer, RPCHook
semaphoreAsyncSendSize = new Semaphore(1024 * 1024, true);
log.info("semaphoreAsyncSendSize can not be smaller than 1M.");
}
- }
+ ServiceDetector serviceDetector = new ServiceDetector() {
+ @Override
+ public boolean detect(String endpoint, long timeoutMillis) {
+ Optional candidateTopic = pickTopic();
+ if (!candidateTopic.isPresent()) {
+ return false;
+ }
+ try {
+ MessageQueue mq = new MessageQueue(candidateTopic.get(), null, 0);
+ mQClientFactory.getMQClientAPIImpl()
+ .getMaxOffset(endpoint, mq, timeoutMillis);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ };
+
+ this.mqFaultStrategy = new MQFaultStrategy(defaultMQProducer.cloneClientConfig(), new Resolver() {
+ @Override
+ public String resolve(String name) {
+ return DefaultMQProducerImpl.this.mQClientFactory.findBrokerAddressInPublish(name);
+ }
+ }, serviceDetector);
+ }
+ private Optional pickTopic() {
+ if (topicPublishInfoTable.isEmpty()) {
+ return Optional.absent();
+ }
+ return Optional.of(topicPublishInfoTable.keySet().iterator().next());
+ }
public void registerCheckForbiddenHook(CheckForbiddenHook checkForbiddenHook) {
this.checkForbiddenHookList.add(checkForbiddenHook);
log.info("register a new checkForbiddenHook. hookName={}, allHookSize={}", checkForbiddenHook.hookName(),
@@ -229,6 +263,8 @@ public void start(final boolean startFactory) throws MQClientException {
mQClientFactory.start();
}
+ this.mqFaultStrategy.startDetector();
+
log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(),
this.defaultMQProducer.isSendMessageWithVIPChannel());
this.serviceState = ServiceState.RUNNING;
@@ -273,6 +309,7 @@ public void shutdown(final boolean shutdownFactory) {
if (shutdownFactory) {
this.mQClientFactory.shutdown();
}
+ this.mqFaultStrategy.shutdown();
RequestFutureHolder.getInstance().shutdown(this);
log.info("the producer [{}] shutdown OK", this.defaultMQProducer.getProducerGroup());
this.serviceState = ServiceState.SHUTDOWN_ALREADY;
@@ -506,6 +543,8 @@ public void send(Message msg,
@Deprecated
public void send(final Message msg, final SendCallback sendCallback, final long timeout)
throws MQClientException, RemotingException, InterruptedException {
+ BackpressureSendCallBack newCallBack = new BackpressureSendCallBack(sendCallback);
+
final long beginStartTime = System.currentTimeMillis();
Runnable runnable = new Runnable() {
@Override
@@ -513,20 +552,53 @@ public void run() {
long costTime = System.currentTimeMillis() - beginStartTime;
if (timeout > costTime) {
try {
- sendDefaultImpl(msg, CommunicationMode.ASYNC, sendCallback, timeout - costTime);
+ sendDefaultImpl(msg, CommunicationMode.ASYNC, newCallBack, timeout - costTime);
} catch (Exception e) {
- sendCallback.onException(e);
+ newCallBack.onException(e);
}
} else {
- sendCallback.onException(
+ newCallBack.onException(
new RemotingTooMuchRequestException("DEFAULT ASYNC send call timeout"));
}
}
};
- executeAsyncMessageSend(runnable, msg, sendCallback, timeout, beginStartTime);
+ executeAsyncMessageSend(runnable, msg, newCallBack, timeout, beginStartTime);
}
- public void executeAsyncMessageSend(Runnable runnable, final Message msg, final SendCallback sendCallback,
+ class BackpressureSendCallBack implements SendCallback {
+ public boolean isSemaphoreAsyncSizeAquired = false;
+ public boolean isSemaphoreAsyncNumAquired = false;
+ public int msgLen;
+ private final SendCallback sendCallback;
+
+ public BackpressureSendCallBack(final SendCallback sendCallback) {
+ this.sendCallback = sendCallback;
+ }
+
+ @Override
+ public void onSuccess(SendResult sendResult) {
+ if (isSemaphoreAsyncSizeAquired) {
+ semaphoreAsyncSendSize.release(msgLen);
+ }
+ if (isSemaphoreAsyncNumAquired) {
+ semaphoreAsyncSendNum.release();
+ }
+ sendCallback.onSuccess(sendResult);
+ }
+
+ @Override
+ public void onException(Throwable e) {
+ if (isSemaphoreAsyncSizeAquired) {
+ semaphoreAsyncSendSize.release(msgLen);
+ }
+ if (isSemaphoreAsyncNumAquired) {
+ semaphoreAsyncSendNum.release();
+ }
+ sendCallback.onException(e);
+ }
+ }
+
+ public void executeAsyncMessageSend(Runnable runnable, final Message msg, final BackpressureSendCallBack sendCallback,
final long timeout, final long beginStartTime)
throws MQClientException, InterruptedException {
ExecutorService executor = this.getAsyncSenderExecutor();
@@ -554,7 +626,9 @@ public void executeAsyncMessageSend(Runnable runnable, final Message msg, final
return;
}
}
-
+ sendCallback.isSemaphoreAsyncSizeAquired = isSemaphoreAsyncSizeAquired;
+ sendCallback.isSemaphoreAsyncNumAquired = isSemaphoreAsyncNumAquired;
+ sendCallback.msgLen = msgLen;
executor.submit(runnable);
} catch (RejectedExecutionException e) {
if (isEnableBackpressureForAsyncMode) {
@@ -562,19 +636,11 @@ public void executeAsyncMessageSend(Runnable runnable, final Message msg, final
} else {
throw new MQClientException("executor rejected ", e);
}
- } finally {
- if (isSemaphoreAsyncSizeAquired) {
- semaphoreAsyncSendSize.release(msgLen);
- }
- if (isSemaphoreAsyncNumAquired) {
- semaphoreAsyncSendNum.release();
- }
}
-
}
public MessageQueue invokeMessageQueueSelector(Message msg, MessageQueueSelector selector, Object arg,
- final long timeout) throws MQClientException, RemotingTooMuchRequestException {
+ final long timeout) throws MQClientException, RemotingTooMuchRequestException {
long beginStartTime = System.currentTimeMillis();
this.makeSureStateOK();
Validators.checkMessage(msg, this.defaultMQProducer);
@@ -584,7 +650,7 @@ public MessageQueue invokeMessageQueueSelector(Message msg, MessageQueueSelector
MessageQueue mq = null;
try {
List messageQueueList =
- mQClientFactory.getMQAdminImpl().parsePublishMessageQueues(topicPublishInfo.getMessageQueueList());
+ mQClientFactory.getMQAdminImpl().parsePublishMessageQueues(topicPublishInfo.getMessageQueueList());
Message userMessage = MessageAccessor.cloneMessage(msg);
String userTopic = NamespaceUtil.withoutNamespace(userMessage.getTopic(), mQClientFactory.getClientConfig().getNamespace());
userMessage.setTopic(userTopic);
@@ -609,12 +675,13 @@ public MessageQueue invokeMessageQueueSelector(Message msg, MessageQueueSelector
throw new MQClientException("No route info for this topic, " + msg.getTopic(), null);
}
- public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
- return this.mqFaultStrategy.selectOneMessageQueue(tpInfo, lastBrokerName);
+ public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName, final boolean resetIndex) {
+ return this.mqFaultStrategy.selectOneMessageQueue(tpInfo, lastBrokerName, resetIndex);
}
- public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation) {
- this.mqFaultStrategy.updateFaultItem(brokerName, currentLatency, isolation);
+ public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation,
+ boolean reachable) {
+ this.mqFaultStrategy.updateFaultItem(brokerName, currentLatency, isolation, reachable);
}
private void validateNameServerSetting() throws MQClientException {
@@ -647,9 +714,13 @@ private SendResult sendDefaultImpl(
int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
int times = 0;
String[] brokersSent = new String[timesTotal];
+ boolean resetIndex = false;
for (; times < timesTotal; times++) {
String lastBrokerName = null == mq ? null : mq.getBrokerName();
- MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);
+ if (times > 0) {
+ resetIndex = true;
+ }
+ MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName, resetIndex);
if (mqSelected != null) {
mq = mqSelected;
brokersSent[times] = mq.getBrokerName();
@@ -667,7 +738,7 @@ private SendResult sendDefaultImpl(
sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
endTimestamp = System.currentTimeMillis();
- this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false, true);
switch (communicationMode) {
case ASYNC:
return null;
@@ -684,9 +755,22 @@ private SendResult sendDefaultImpl(
default:
break;
}
- } catch (RemotingException | MQClientException e) {
+ } catch (MQClientException e) {
+ endTimestamp = System.currentTimeMillis();
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false, true);
+ log.warn("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq, e);
+ log.warn(msg.toString());
+ exception = e;
+ continue;
+ } catch (RemotingException e) {
endTimestamp = System.currentTimeMillis();
- this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
+ if (this.mqFaultStrategy.isStartDetectorEnable()) {
+ // Set this broker unreachable when detecting schedule task is running for RemotingException.
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true, false);
+ } else {
+ // Otherwise, isolate this broker.
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true, true);
+ }
log.warn("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq, e);
if (log.isDebugEnabled()) {
log.debug(msg.toString());
@@ -695,7 +779,7 @@ private SendResult sendDefaultImpl(
continue;
} catch (MQBrokerException e) {
endTimestamp = System.currentTimeMillis();
- this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true, false);
log.warn("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq, e);
if (log.isDebugEnabled()) {
log.debug(msg.toString());
@@ -712,7 +796,7 @@ private SendResult sendDefaultImpl(
}
} catch (InterruptedException e) {
endTimestamp = System.currentTimeMillis();
- this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
+ this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false, true);
log.warn("sendKernelImpl exception, throw exception, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq, e);
if (log.isDebugEnabled()) {
log.debug(msg.toString());
@@ -1129,7 +1213,7 @@ public void send(Message msg, MessageQueue mq, SendCallback sendCallback)
@Deprecated
public void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback, final long timeout)
throws MQClientException, RemotingException, InterruptedException {
-
+ BackpressureSendCallBack newCallBack = new BackpressureSendCallBack(sendCallback);
final long beginStartTime = System.currentTimeMillis();
Runnable runnable = new Runnable() {
@Override
@@ -1144,22 +1228,22 @@ public void run() {
long costTime = System.currentTimeMillis() - beginStartTime;
if (timeout > costTime) {
try {
- sendKernelImpl(msg, mq, CommunicationMode.ASYNC, sendCallback, null,
+ sendKernelImpl(msg, mq, CommunicationMode.ASYNC, newCallBack, null,
timeout - costTime);
} catch (MQBrokerException e) {
throw new MQClientException("unknown exception", e);
}
} else {
- sendCallback.onException(new RemotingTooMuchRequestException("call timeout"));
+ newCallBack.onException(new RemotingTooMuchRequestException("call timeout"));
}
} catch (Exception e) {
- sendCallback.onException(e);
+ newCallBack.onException(e);
}
}
};
- executeAsyncMessageSend(runnable, msg, sendCallback, timeout, beginStartTime);
+ executeAsyncMessageSend(runnable, msg, newCallBack, timeout, beginStartTime);
}
/**
@@ -1256,7 +1340,7 @@ public void send(Message msg, MessageQueueSelector selector, Object arg, SendCal
public void send(final Message msg, final MessageQueueSelector selector, final Object arg,
final SendCallback sendCallback, final long timeout)
throws MQClientException, RemotingException, InterruptedException {
-
+ BackpressureSendCallBack newCallBack = new BackpressureSendCallBack(sendCallback);
final long beginStartTime = System.currentTimeMillis();
Runnable runnable = new Runnable() {
@Override
@@ -1265,21 +1349,21 @@ public void run() {
if (timeout > costTime) {
try {
try {
- sendSelectImpl(msg, selector, arg, CommunicationMode.ASYNC, sendCallback,
+ sendSelectImpl(msg, selector, arg, CommunicationMode.ASYNC, newCallBack,
timeout - costTime);
} catch (MQBrokerException e) {
throw new MQClientException("unknown exception", e);
}
} catch (Exception e) {
- sendCallback.onException(e);
+ newCallBack.onException(e);
}
} else {
- sendCallback.onException(new RemotingTooMuchRequestException("call timeout"));
+ newCallBack.onException(new RemotingTooMuchRequestException("call timeout"));
}
}
};
- executeAsyncMessageSend(runnable, msg, sendCallback, timeout, beginStartTime);
+ executeAsyncMessageSend(runnable, msg, newCallBack, timeout, beginStartTime);
}
/**
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java
index 275ada7ac34..37b1f3252f7 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java
@@ -18,6 +18,8 @@
import java.util.ArrayList;
import java.util.List;
+
+import com.google.common.base.Preconditions;
import org.apache.rocketmq.client.common.ThreadLocalIndex;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.protocol.route.QueueData;
@@ -30,6 +32,10 @@ public class TopicPublishInfo {
private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex();
private TopicRouteData topicRouteData;
+ public interface QueueFilter {
+ boolean filter(MessageQueue mq);
+ }
+
public boolean isOrderTopic() {
return orderTopic;
}
@@ -66,6 +72,40 @@ public void setHaveTopicRouterInfo(boolean haveTopicRouterInfo) {
this.haveTopicRouterInfo = haveTopicRouterInfo;
}
+ public MessageQueue selectOneMessageQueue(QueueFilter ...filter) {
+ return selectOneMessageQueue(this.messageQueueList, this.sendWhichQueue, filter);
+ }
+
+ private MessageQueue selectOneMessageQueue(List messageQueueList, ThreadLocalIndex sendQueue, QueueFilter ...filter) {
+ if (messageQueueList == null || messageQueueList.isEmpty()) {
+ return null;
+ }
+
+ if (filter != null && filter.length != 0) {
+ for (int i = 0; i < messageQueueList.size(); i++) {
+ int index = Math.abs(sendQueue.incrementAndGet() % messageQueueList.size());
+ MessageQueue mq = messageQueueList.get(index);
+ boolean filterResult = true;
+ for (QueueFilter f: filter) {
+ Preconditions.checkNotNull(f);
+ filterResult &= f.filter(mq);
+ }
+ if (filterResult) {
+ return mq;
+ }
+ }
+
+ return null;
+ }
+
+ int index = Math.abs(sendQueue.incrementAndGet() % messageQueueList.size());
+ return messageQueueList.get(index);
+ }
+
+ public void resetIndex() {
+ this.sendWhichQueue.reset();
+ }
+
public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
if (lastBrokerName == null) {
return selectOneMessageQueue();
diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java
index 09a8aa46189..17aaa266aae 100644
--- a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java
@@ -18,11 +18,89 @@
package org.apache.rocketmq.client.latency;
public interface LatencyFaultTolerance {
- void updateFaultItem(final T name, final long currentLatency, final long notAvailableDuration);
+ /**
+ * Update brokers' states, to decide if they are good or not.
+ *
+ * @param name Broker's name.
+ * @param currentLatency Current message sending process's latency.
+ * @param notAvailableDuration Corresponding not available time, ms. The broker will be not available until it
+ * spends such time.
+ * @param reachable To decide if this broker is reachable or not.
+ */
+ void updateFaultItem(final T name, final long currentLatency, final long notAvailableDuration,
+ final boolean reachable);
+ /**
+ * To check if this broker is available.
+ *
+ * @param name Broker's name.
+ * @return boolean variable, if this is true, then the broker is available.
+ */
boolean isAvailable(final T name);
+ /**
+ * To check if this broker is reachable.
+ *
+ * @param name Broker's name.
+ * @return boolean variable, if this is true, then the broker is reachable.
+ */
+ boolean isReachable(final T name);
+
+ /**
+ * Remove the broker in this fault item table.
+ *
+ * @param name broker's name.
+ */
void remove(final T name);
+ /**
+ * The worst situation, no broker can be available. Then choose random one.
+ *
+ * @return A random mq will be returned.
+ */
T pickOneAtLeast();
+
+ /**
+ * Start a new thread, to detect the broker's reachable tag.
+ */
+ void startDetector();
+
+ /**
+ * Shutdown threads that started by LatencyFaultTolerance.
+ */
+ void shutdown();
+
+ /**
+ * A function reserved, just detect by once, won't create a new thread.
+ */
+ void detectByOneRound();
+
+ /**
+ * Use it to set the detect timeout bound.
+ *
+ * @param detectTimeout timeout bound
+ */
+ void setDetectTimeout(final int detectTimeout);
+
+ /**
+ * Use it to set the detector's detector interval for each broker (each broker will be detected once during this
+ * time)
+ *
+ * @param detectInterval each broker's detecting interval
+ */
+ void setDetectInterval(final int detectInterval);
+
+ /**
+ * Use it to set the detector work or not.
+ *
+ * @param startDetectorEnable set the detector's work status
+ */
+ void setStartDetectorEnable(final boolean startDetectorEnable);
+
+ /**
+ * Use it to judge if the detector enabled.
+ *
+ * @return is the detector should be started.
+ */
+ boolean isStartDetectorEnable();
}
diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java
index 93795d95753..d3ff7eb45a1 100644
--- a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java
@@ -21,30 +21,101 @@
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.client.common.ThreadLocalIndex;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
public class LatencyFaultToleranceImpl implements LatencyFaultTolerance {
- private final ConcurrentHashMap faultItemTable = new ConcurrentHashMap<>(16);
+ private final static Logger log = LoggerFactory.getLogger(MQFaultStrategy.class);
+ private final ConcurrentHashMap faultItemTable = new ConcurrentHashMap(16);
+ private int detectTimeout = 200;
+ private int detectInterval = 2000;
+ private final ThreadLocalIndex whichItemWorst = new ThreadLocalIndex();
- private final ThreadLocalIndex randomItem = new ThreadLocalIndex();
+ private volatile boolean startDetectorEnable = false;
+ private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "LatencyFaultToleranceScheduledThread");
+ }
+ });
+
+ private final Resolver resolver;
+
+ private final ServiceDetector serviceDetector;
+
+ public LatencyFaultToleranceImpl(Resolver resolver, ServiceDetector serviceDetector) {
+ this.resolver = resolver;
+ this.serviceDetector = serviceDetector;
+ }
+
+ public void detectByOneRound() {
+ for (Map.Entry item : this.faultItemTable.entrySet()) {
+ FaultItem brokerItem = item.getValue();
+ if (System.currentTimeMillis() - brokerItem.checkStamp >= 0) {
+ brokerItem.checkStamp = System.currentTimeMillis() + this.detectInterval;
+ String brokerAddr = resolver.resolve(brokerItem.getName());
+ if (brokerAddr == null) {
+ faultItemTable.remove(item.getKey());
+ continue;
+ }
+ if (null == serviceDetector) {
+ continue;
+ }
+ boolean serviceOK = serviceDetector.detect(brokerAddr, detectTimeout);
+ if (serviceOK && !brokerItem.reachableFlag) {
+ log.info(brokerItem.name + " is reachable now, then it can be used.");
+ brokerItem.reachableFlag = true;
+ }
+ }
+ }
+ }
+
+ public void startDetector() {
+ this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (startDetectorEnable) {
+ detectByOneRound();
+ }
+ } catch (Exception e) {
+ log.warn("Unexpected exception raised while detecting service reachability", e);
+ }
+ }
+ }, 3, 3, TimeUnit.SECONDS);
+ }
+
+ public void shutdown() {
+ this.scheduledExecutorService.shutdown();
+ }
@Override
- public void updateFaultItem(final String name, final long currentLatency, final long notAvailableDuration) {
+ public void updateFaultItem(final String name, final long currentLatency, final long notAvailableDuration,
+ final boolean reachable) {
FaultItem old = this.faultItemTable.get(name);
if (null == old) {
final FaultItem faultItem = new FaultItem(name);
faultItem.setCurrentLatency(currentLatency);
- faultItem.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
-
+ faultItem.updateNotAvailableDuration(notAvailableDuration);
+ faultItem.setReachable(reachable);
old = this.faultItemTable.putIfAbsent(name, faultItem);
- if (old != null) {
- old.setCurrentLatency(currentLatency);
- old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
- }
- } else {
+ }
+
+ if (null != old) {
old.setCurrentLatency(currentLatency);
- old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
+ old.updateNotAvailableDuration(notAvailableDuration);
+ old.setReachable(reachable);
+ }
+
+ if (!reachable) {
+ log.info(name + " is unreachable, it will not be used until it's reachable");
}
}
@@ -57,76 +128,121 @@ public boolean isAvailable(final String name) {
return true;
}
+ public boolean isReachable(final String name) {
+ final FaultItem faultItem = this.faultItemTable.get(name);
+ if (faultItem != null) {
+ return faultItem.isReachable();
+ }
+ return true;
+ }
+
@Override
public void remove(final String name) {
this.faultItemTable.remove(name);
}
+ public boolean isStartDetectorEnable() {
+ return startDetectorEnable;
+ }
+
+ public void setStartDetectorEnable(boolean startDetectorEnable) {
+ this.startDetectorEnable = startDetectorEnable;
+ }
@Override
public String pickOneAtLeast() {
final Enumeration elements = this.faultItemTable.elements();
- List tmpList = new LinkedList<>();
+ List tmpList = new LinkedList();
while (elements.hasMoreElements()) {
final FaultItem faultItem = elements.nextElement();
tmpList.add(faultItem);
}
+
if (!tmpList.isEmpty()) {
- Collections.sort(tmpList);
- final int half = tmpList.size() / 2;
- if (half <= 0) {
- return tmpList.get(0).getName();
- } else {
- final int i = this.randomItem.incrementAndGet() % half;
- return tmpList.get(i).getName();
+ Collections.shuffle(tmpList);
+ for (FaultItem faultItem : tmpList) {
+ if (faultItem.reachableFlag) {
+ return faultItem.name;
+ }
}
}
+
return null;
}
@Override
public String toString() {
return "LatencyFaultToleranceImpl{" +
- "faultItemTable=" + faultItemTable +
- ", whichItemWorst=" + randomItem +
- '}';
+ "faultItemTable=" + faultItemTable +
+ ", whichItemWorst=" + whichItemWorst +
+ '}';
}
- class FaultItem implements Comparable {
+ public void setDetectTimeout(final int detectTimeout) {
+ this.detectTimeout = detectTimeout;
+ }
+
+ public void setDetectInterval(final int detectInterval) {
+ this.detectInterval = detectInterval;
+ }
+
+ public class FaultItem implements Comparable {
private final String name;
private volatile long currentLatency;
private volatile long startTimestamp;
+ private volatile long checkStamp;
+ private volatile boolean reachableFlag;
public FaultItem(final String name) {
this.name = name;
}
+ public void updateNotAvailableDuration(long notAvailableDuration) {
+ if (notAvailableDuration > 0 && System.currentTimeMillis() + notAvailableDuration > this.startTimestamp) {
+ this.startTimestamp = System.currentTimeMillis() + notAvailableDuration;
+ log.info(name + " will be isolated for " + notAvailableDuration + " ms.");
+ }
+ }
+
@Override
public int compareTo(final FaultItem other) {
if (this.isAvailable() != other.isAvailable()) {
- if (this.isAvailable())
+ if (this.isAvailable()) {
return -1;
+ }
- if (other.isAvailable())
+ if (other.isAvailable()) {
return 1;
+ }
}
- if (this.currentLatency < other.currentLatency)
+ if (this.currentLatency < other.currentLatency) {
return -1;
- else if (this.currentLatency > other.currentLatency) {
+ } else if (this.currentLatency > other.currentLatency) {
return 1;
}
- if (this.startTimestamp < other.startTimestamp)
+ if (this.startTimestamp < other.startTimestamp) {
return -1;
- else if (this.startTimestamp > other.startTimestamp) {
+ } else if (this.startTimestamp > other.startTimestamp) {
return 1;
}
-
return 0;
}
+ public void setReachable(boolean reachableFlag) {
+ this.reachableFlag = reachableFlag;
+ }
+
+ public void setCheckStamp(long checkStamp) {
+ this.checkStamp = checkStamp;
+ }
+
public boolean isAvailable() {
- return (System.currentTimeMillis() - startTimestamp) >= 0;
+ return reachableFlag && System.currentTimeMillis() >= startTimestamp;
+ }
+
+ public boolean isReachable() {
+ return reachableFlag;
}
@Override
@@ -139,28 +255,32 @@ public int hashCode() {
@Override
public boolean equals(final Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (!(o instanceof FaultItem))
+ }
+ if (!(o instanceof FaultItem)) {
return false;
+ }
final FaultItem faultItem = (FaultItem) o;
- if (getCurrentLatency() != faultItem.getCurrentLatency())
+ if (getCurrentLatency() != faultItem.getCurrentLatency()) {
return false;
- if (getStartTimestamp() != faultItem.getStartTimestamp())
+ }
+ if (getStartTimestamp() != faultItem.getStartTimestamp()) {
return false;
+ }
return getName() != null ? getName().equals(faultItem.getName()) : faultItem.getName() == null;
-
}
@Override
public String toString() {
return "FaultItem{" +
- "name='" + name + '\'' +
- ", currentLatency=" + currentLatency +
- ", startTimestamp=" + startTimestamp +
- '}';
+ "name='" + name + '\'' +
+ ", currentLatency=" + currentLatency +
+ ", startTimestamp=" + startTimestamp +
+ ", reachableFlag=" + reachableFlag +
+ '}';
}
public String getName() {
diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java
index 1e1953fad90..69fb533e5ad 100644
--- a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java
+++ b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java
@@ -17,25 +17,86 @@
package org.apache.rocketmq.client.latency;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.impl.producer.TopicPublishInfo;
+import org.apache.rocketmq.client.impl.producer.TopicPublishInfo.QueueFilter;
import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
public class MQFaultStrategy {
- private final static Logger log = LoggerFactory.getLogger(MQFaultStrategy.class);
- private final LatencyFaultTolerance latencyFaultTolerance = new LatencyFaultToleranceImpl();
+ private LatencyFaultTolerance latencyFaultTolerance;
+ private volatile boolean sendLatencyFaultEnable;
+ private volatile boolean startDetectorEnable;
+ private long[] latencyMax = {50L, 100L, 550L, 1800L, 3000L, 5000L, 15000L};
+ private long[] notAvailableDuration = {0L, 0L, 2000L, 5000L, 6000L, 10000L, 30000L};
- private boolean sendLatencyFaultEnable = false;
+ public static class BrokerFilter implements QueueFilter {
+ private String lastBrokerName;
+
+ public void setLastBrokerName(String lastBrokerName) {
+ this.lastBrokerName = lastBrokerName;
+ }
+
+ @Override public boolean filter(MessageQueue mq) {
+ if (lastBrokerName != null) {
+ return !mq.getBrokerName().equals(lastBrokerName);
+ }
+ return true;
+ }
+ }
+
+ private ThreadLocal threadBrokerFilter = new ThreadLocal() {
+ @Override protected BrokerFilter initialValue() {
+ return new BrokerFilter();
+ }
+ };
+
+ private QueueFilter reachableFilter = new QueueFilter() {
+ @Override public boolean filter(MessageQueue mq) {
+ return latencyFaultTolerance.isReachable(mq.getBrokerName());
+ }
+ };
+
+ private QueueFilter availableFilter = new QueueFilter() {
+ @Override public boolean filter(MessageQueue mq) {
+ return latencyFaultTolerance.isAvailable(mq.getBrokerName());
+ }
+ };
+
+
+ public MQFaultStrategy(ClientConfig cc, Resolver fetcher, ServiceDetector serviceDetector) {
+ this.latencyFaultTolerance = new LatencyFaultToleranceImpl(fetcher, serviceDetector);
+ this.latencyFaultTolerance.setDetectInterval(cc.getDetectInterval());
+ this.latencyFaultTolerance.setDetectTimeout(cc.getDetectTimeout());
+ this.setStartDetectorEnable(cc.isStartDetectorEnable());
+ this.setSendLatencyFaultEnable(cc.isSendLatencyEnable());
+ }
+
+ // For unit test.
+ public MQFaultStrategy(ClientConfig cc, LatencyFaultTolerance tolerance) {
+ this.setStartDetectorEnable(cc.isStartDetectorEnable());
+ this.setSendLatencyFaultEnable(cc.isSendLatencyEnable());
+ this.latencyFaultTolerance = tolerance;
+ this.latencyFaultTolerance.setDetectInterval(cc.getDetectInterval());
+ this.latencyFaultTolerance.setDetectTimeout(cc.getDetectTimeout());
+ }
- private long[] latencyMax = {50L, 100L, 550L, 1000L, 2000L, 3000L, 15000L};
- private long[] notAvailableDuration = {0L, 0L, 30000L, 60000L, 120000L, 180000L, 600000L};
public long[] getNotAvailableDuration() {
return notAvailableDuration;
}
+ public QueueFilter getAvailableFilter() {
+ return availableFilter;
+ }
+
+ public QueueFilter getReachableFilter() {
+ return reachableFilter;
+ }
+
+ public ThreadLocal getThreadBrokerFilter() {
+ return threadBrokerFilter;
+ }
+
public void setNotAvailableDuration(final long[] notAvailableDuration) {
this.notAvailableDuration = notAvailableDuration;
}
@@ -56,51 +117,63 @@ public void setSendLatencyFaultEnable(final boolean sendLatencyFaultEnable) {
this.sendLatencyFaultEnable = sendLatencyFaultEnable;
}
- public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
+ public boolean isStartDetectorEnable() {
+ return startDetectorEnable;
+ }
+
+ public void setStartDetectorEnable(boolean startDetectorEnable) {
+ this.startDetectorEnable = startDetectorEnable;
+ this.latencyFaultTolerance.setStartDetectorEnable(startDetectorEnable);
+ }
+
+ public void startDetector() {
+ this.latencyFaultTolerance.startDetector();
+ }
+
+ public void shutdown() {
+ this.latencyFaultTolerance.shutdown();
+ }
+
+ public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName, final boolean resetIndex) {
+ BrokerFilter brokerFilter = threadBrokerFilter.get();
+ brokerFilter.setLastBrokerName(lastBrokerName);
if (this.sendLatencyFaultEnable) {
- try {
- int index = tpInfo.getSendWhichQueue().incrementAndGet();
- for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) {
- int pos = index++ % tpInfo.getMessageQueueList().size();
- MessageQueue mq = tpInfo.getMessageQueueList().get(pos);
- if (!StringUtils.equals(lastBrokerName, mq.getBrokerName()) && latencyFaultTolerance.isAvailable(mq.getBrokerName())) {
- return mq;
- }
- }
-
- final String notBestBroker = latencyFaultTolerance.pickOneAtLeast();
- int writeQueueNums = tpInfo.getWriteQueueNumsByBroker(notBestBroker);
- if (writeQueueNums > 0) {
- final MessageQueue mq = tpInfo.selectOneMessageQueue();
- if (notBestBroker != null) {
- mq.setBrokerName(notBestBroker);
- mq.setQueueId(tpInfo.getSendWhichQueue().incrementAndGet() % writeQueueNums);
- }
- return mq;
- } else {
- latencyFaultTolerance.remove(notBestBroker);
- }
- } catch (Exception e) {
- log.error("Error occurred when selecting message queue", e);
+ if (resetIndex) {
+ tpInfo.resetIndex();
+ }
+ MessageQueue mq = tpInfo.selectOneMessageQueue(availableFilter, brokerFilter);
+ if (mq != null) {
+ return mq;
+ }
+
+ mq = tpInfo.selectOneMessageQueue(reachableFilter, brokerFilter);
+ if (mq != null) {
+ return mq;
}
return tpInfo.selectOneMessageQueue();
}
- return tpInfo.selectOneMessageQueue(lastBrokerName);
+ MessageQueue mq = tpInfo.selectOneMessageQueue(brokerFilter);
+ if (mq != null) {
+ return mq;
+ }
+ return tpInfo.selectOneMessageQueue();
}
- public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation) {
+ public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation,
+ final boolean reachable) {
if (this.sendLatencyFaultEnable) {
- long duration = computeNotAvailableDuration(isolation ? 30000 : currentLatency);
- this.latencyFaultTolerance.updateFaultItem(brokerName, currentLatency, duration);
+ long duration = computeNotAvailableDuration(isolation ? 10000 : currentLatency);
+ this.latencyFaultTolerance.updateFaultItem(brokerName, currentLatency, duration, reachable);
}
}
private long computeNotAvailableDuration(final long currentLatency) {
for (int i = latencyMax.length - 1; i >= 0; i--) {
- if (currentLatency >= latencyMax[i])
+ if (currentLatency >= latencyMax[i]) {
return this.notAvailableDuration[i];
+ }
}
return 0;
diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/Resolver.java b/client/src/main/java/org/apache/rocketmq/client/latency/Resolver.java
new file mode 100644
index 00000000000..1c29ba33469
--- /dev/null
+++ b/client/src/main/java/org/apache/rocketmq/client/latency/Resolver.java
@@ -0,0 +1,22 @@
+/*
+ * 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.client.latency;
+
+public interface Resolver {
+
+ String resolve(String name);
+}
diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/ServiceDetector.java b/client/src/main/java/org/apache/rocketmq/client/latency/ServiceDetector.java
new file mode 100644
index 00000000000..c6ffbad1cb6
--- /dev/null
+++ b/client/src/main/java/org/apache/rocketmq/client/latency/ServiceDetector.java
@@ -0,0 +1,30 @@
+/*
+ * 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.client.latency;
+
+/**
+ * Detect whether the remote service state is normal.
+ */
+public interface ServiceDetector {
+
+ /**
+ * Check if the remote service is normal.
+ * @param endpoint Service endpoint to check against
+ * @return true if the service is back to normal; false otherwise.
+ */
+ boolean detect(String endpoint, long timeoutMillis);
+}
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
index d13f2cfe43a..c152d38ea50 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
@@ -212,7 +212,7 @@ public Object answer(InvocationOnMock mock) throws Throwable {
RemotingCommand request = mock.getArgument(1);
ResponseFuture responseFuture = new ResponseFuture(null, request.getOpaque(), 3 * 1000, null, null);
responseFuture.setResponseCommand(createSendMessageSuccessResponse(request));
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));
@@ -386,7 +386,7 @@ public Object answer(InvocationOnMock mock) throws Throwable {
RemotingCommand request = mock.getArgument(1);
ResponseFuture responseFuture = new ResponseFuture(null, request.getOpaque(), 3 * 1000, null, null);
responseFuture.setResponseCommand(createSendMessageSuccessResponse(request));
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(Matchers.anyString(), Matchers.any(RemotingCommand.class), Matchers.anyLong(), Matchers.any(InvokeCallback.class));
@@ -472,7 +472,7 @@ public Void answer(InvocationOnMock mock) throws Throwable {
message.putUserProperty("key", "value");
response.setBody(MessageDecoder.encode(message, false));
responseFuture.setResponseCommand(response);
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));
@@ -543,7 +543,7 @@ public Void answer(InvocationOnMock mock) throws Throwable {
message.getProperties().put(MessageConst.PROPERTY_INNER_MULTI_QUEUE_OFFSET, String.valueOf(0));
response.setBody(MessageDecoder.encode(message, false));
responseFuture.setResponseCommand(response);
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));
@@ -585,7 +585,7 @@ public Void answer(InvocationOnMock mock) throws Throwable {
response.setOpaque(request.getOpaque());
response.setCode(ResponseCode.SUCCESS);
responseFuture.setResponseCommand(response);
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));
@@ -622,7 +622,7 @@ public Void answer(InvocationOnMock mock) throws Throwable {
responseHeader.setPopTime(System.currentTimeMillis());
responseHeader.setInvisibleTime(10 * 1000L);
responseFuture.setResponseCommand(response);
- callback.operationComplete(responseFuture);
+ callback.operationSucceed(responseFuture.getResponseCommand());
return null;
}
}).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));
diff --git a/client/src/test/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImplTest.java b/client/src/test/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImplTest.java
index 86690e40be6..42ccdae5a48 100644
--- a/client/src/test/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImplTest.java
@@ -16,11 +16,14 @@
*/
package org.apache.rocketmq.client.latency;
-import java.util.concurrent.TimeUnit;
+import org.awaitility.core.ThrowingRunnable;
import org.junit.Before;
import org.junit.Test;
+import java.util.concurrent.TimeUnit;
+
import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
public class LatencyFaultToleranceImplTest {
private LatencyFaultTolerance latencyFaultTolerance;
@@ -29,28 +32,31 @@ public class LatencyFaultToleranceImplTest {
@Before
public void init() {
- latencyFaultTolerance = new LatencyFaultToleranceImpl();
+ latencyFaultTolerance = new LatencyFaultToleranceImpl(null, null);
}
@Test
public void testUpdateFaultItem() throws Exception {
- latencyFaultTolerance.updateFaultItem(brokerName, 3000, 3000);
+ latencyFaultTolerance.updateFaultItem(brokerName, 3000, 3000, true);
assertThat(latencyFaultTolerance.isAvailable(brokerName)).isFalse();
assertThat(latencyFaultTolerance.isAvailable(anotherBrokerName)).isTrue();
}
@Test
public void testIsAvailable() throws Exception {
- latencyFaultTolerance.updateFaultItem(brokerName, 3000, 50);
+ latencyFaultTolerance.updateFaultItem(brokerName, 3000, 50, true);
assertThat(latencyFaultTolerance.isAvailable(brokerName)).isFalse();
- TimeUnit.MILLISECONDS.sleep(70);
- assertThat(latencyFaultTolerance.isAvailable(brokerName)).isTrue();
+ await().atMost(500, TimeUnit.MILLISECONDS).untilAsserted(new ThrowingRunnable() {
+ @Override public void run() throws Throwable {
+ assertThat(latencyFaultTolerance.isAvailable(brokerName)).isTrue();
+ }
+ });
}
@Test
public void testRemove() throws Exception {
- latencyFaultTolerance.updateFaultItem(brokerName, 3000, 3000);
+ latencyFaultTolerance.updateFaultItem(brokerName, 3000, 3000, true);
assertThat(latencyFaultTolerance.isAvailable(brokerName)).isFalse();
latencyFaultTolerance.remove(brokerName);
assertThat(latencyFaultTolerance.isAvailable(brokerName)).isTrue();
@@ -58,10 +64,20 @@ public void testRemove() throws Exception {
@Test
public void testPickOneAtLeast() throws Exception {
- latencyFaultTolerance.updateFaultItem(brokerName, 1000, 3000);
+ latencyFaultTolerance.updateFaultItem(brokerName, 1000, 3000, true);
assertThat(latencyFaultTolerance.pickOneAtLeast()).isEqualTo(brokerName);
- latencyFaultTolerance.updateFaultItem(anotherBrokerName, 1001, 3000);
- assertThat(latencyFaultTolerance.pickOneAtLeast()).isEqualTo(brokerName);
+ // Bad case, since pickOneAtLeast's behavior becomes random
+ // latencyFaultTolerance.updateFaultItem(anotherBrokerName, 1001, 3000, "127.0.0.1:12011", true);
+ // assertThat(latencyFaultTolerance.pickOneAtLeast()).isEqualTo(brokerName);
+ }
+
+ @Test
+ public void testIsReachable() throws Exception {
+ latencyFaultTolerance.updateFaultItem(brokerName, 1000, 3000, true);
+ assertThat(latencyFaultTolerance.isReachable(brokerName)).isEqualTo(true);
+
+ latencyFaultTolerance.updateFaultItem(anotherBrokerName, 1001, 3000, false);
+ assertThat(latencyFaultTolerance.isReachable(anotherBrokerName)).isEqualTo(false);
}
}
\ No newline at end of file
diff --git a/common/BUILD.bazel b/common/BUILD.bazel
index a95a19ccd42..9a0c31e772f 100644
--- a/common/BUILD.bazel
+++ b/common/BUILD.bazel
@@ -35,11 +35,12 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_sdk",
"@maven//:io_opentelemetry_opentelemetry_sdk_common",
"@maven//:io_opentelemetry_opentelemetry_sdk_metrics",
+ "@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:org_lz4_lz4_java",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
"@maven//:io_github_aliyunmq_rocketmq_logback_classic",
- "@maven//:io_github_aliyunmq_rocketmq_rocksdb",
+ "@maven//:org_apache_rocketmq_rocketmq_rocksdb",
],
)
diff --git a/common/pom.xml b/common/pom.xml
index 31eb0f087da..a28ed228fd4 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -19,7 +19,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
@@ -80,6 +80,10 @@
io.opentelemetry
opentelemetry-sdk
+
+ io.opentelemetry
+ opentelemetry-exporter-logging-otlp
+
io.grpc
grpc-stub
@@ -105,7 +109,7 @@
rocketmq-logback-classic
- io.github.aliyunmq
+ org.apache.rocketmq
rocketmq-rocksdb
diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
index 45d26b29cba..0d248c4e170 100644
--- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
@@ -396,6 +396,14 @@ public class BrokerConfig extends BrokerIdentity {
private boolean enableMixedMessageType = false;
+ /**
+ * This flag and deleteTopicWithBrokerRegistration flag in the NameServer cannot be set to true at the same time,
+ * otherwise there will be a loss of routing
+ */
+ private boolean enableSplitRegistration = false;
+
+ private int splitRegistrationSize = 800;
+
public long getMaxPopPollingSize() {
return maxPopPollingSize;
}
@@ -1731,4 +1739,20 @@ public boolean isEnableMixedMessageType() {
public void setEnableMixedMessageType(boolean enableMixedMessageType) {
this.enableMixedMessageType = enableMixedMessageType;
}
+
+ public boolean isEnableSplitRegistration() {
+ return enableSplitRegistration;
+ }
+
+ public void setEnableSplitRegistration(boolean enableSplitRegistration) {
+ this.enableSplitRegistration = enableSplitRegistration;
+ }
+
+ public int getSplitRegistrationSize() {
+ return splitRegistrationSize;
+ }
+
+ public void setSplitRegistrationSize(int splitRegistrationSize) {
+ this.splitRegistrationSize = splitRegistrationSize;
+ }
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/MQVersion.java b/common/src/main/java/org/apache/rocketmq/common/MQVersion.java
index bfd07a8959c..4f1990ff828 100644
--- a/common/src/main/java/org/apache/rocketmq/common/MQVersion.java
+++ b/common/src/main/java/org/apache/rocketmq/common/MQVersion.java
@@ -18,7 +18,7 @@
public class MQVersion {
- public static final int CURRENT_VERSION = Version.V5_1_3.ordinal();
+ public static final int CURRENT_VERSION = Version.V5_1_4.ordinal();
public static String getVersionDesc(int value) {
int length = Version.values().length;
diff --git a/common/src/main/java/org/apache/rocketmq/common/MixAll.java b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
index 1233a54223b..407ef2842ca 100644
--- a/common/src/main/java/org/apache/rocketmq/common/MixAll.java
+++ b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
@@ -492,6 +492,7 @@ public static int compareInteger(int x, int y) {
public static int compareLong(long x, long y) {
return Long.compare(x, y);
}
+
public static boolean isLmq(String lmqMetaData) {
return lmqMetaData != null && lmqMetaData.startsWith(LMQ_PREFIX);
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/CQType.java b/common/src/main/java/org/apache/rocketmq/common/attribute/CQType.java
index 73ef2188009..9148d5a18aa 100644
--- a/common/src/main/java/org/apache/rocketmq/common/attribute/CQType.java
+++ b/common/src/main/java/org/apache/rocketmq/common/attribute/CQType.java
@@ -19,5 +19,6 @@
public enum CQType {
SimpleCQ,
- BatchCQ
+ BatchCQ,
+ RocksDBCQ
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/config/AbstractRocksDBStorage.java b/common/src/main/java/org/apache/rocketmq/common/config/AbstractRocksDBStorage.java
index e3673baad05..20319abba3d 100644
--- a/common/src/main/java/org/apache/rocketmq/common/config/AbstractRocksDBStorage.java
+++ b/common/src/main/java/org/apache/rocketmq/common/config/AbstractRocksDBStorage.java
@@ -17,22 +17,21 @@
package org.apache.rocketmq.common.config;
import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.DataConverter;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.rocksdb.ColumnFamilyDescriptor;
@@ -47,7 +46,6 @@
import org.rocksdb.ReadOptions;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
-import org.rocksdb.RocksIterator;
import org.rocksdb.Statistics;
import org.rocksdb.Status;
import org.rocksdb.WriteBatch;
@@ -58,7 +56,6 @@
public abstract class AbstractRocksDBStorage {
protected static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.ROCKSDB_LOGGER_NAME);
- private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
private static final String SPACE = " | ";
protected String dbPath;
@@ -82,8 +79,8 @@ public abstract class AbstractRocksDBStorage {
private volatile boolean closed;
private final Semaphore reloadPermit = new Semaphore(1);
- private final ScheduledExecutorService reloadScheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactoryImpl("RocksDBStorageReloadService_"));
- private final ThreadPoolExecutor manualCompactionThread = new ThreadPoolExecutor(
+ private final ScheduledExecutorService reloadScheduler = ThreadUtils.newScheduledThreadPool(1, new ThreadFactoryImpl("RocksDBStorageReloadService_"));
+ private final ThreadPoolExecutor manualCompactionThread = (ThreadPoolExecutor) ThreadUtils.newThreadPoolExecutor(
1, 1, 1000 * 60, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue(1),
new ThreadFactoryImpl("RocksDBManualCompactionService_"),
@@ -223,10 +220,6 @@ protected void delete(ColumnFamilyHandle cfHandle, WriteOptions writeOptions, By
}
}
- protected WrappedRocksIterator newIterator(ColumnFamilyHandle cfHandle, ReadOptions readOptions) {
- return new WrappedRocksIterator(this.db.newIterator(cfHandle, readOptions));
- }
-
protected void rangeDelete(ColumnFamilyHandle cfHandle, WriteOptions writeOptions,
final byte[] startKey, final byte[] endKey) throws RocksDBException {
if (!hold()) {
@@ -243,46 +236,6 @@ protected void rangeDelete(ColumnFamilyHandle cfHandle, WriteOptions writeOption
}
}
- protected void manualCompactionDefaultCfMaxLevel(final CompactionOptions compactionOptions) throws Exception {
- final ColumnFamilyHandle defaultCFHandle = this.defaultCFHandle;
- final byte[] defaultCFName = defaultCFHandle.getName();
- List fileMetaDataList = this.db.getLiveFilesMetaData();
- if (fileMetaDataList == null || fileMetaDataList.isEmpty()) {
- return;
- }
-
- List defaultLiveFileDataList = Lists.newArrayList();
- List inputFileNames = Lists.newArrayList();
- int maxLevel = 0;
- for (LiveFileMetaData fileMetaData : fileMetaDataList) {
- if (compareTo(fileMetaData.columnFamilyName(), defaultCFName) != 0) {
- continue;
- }
- defaultLiveFileDataList.add(fileMetaData);
- if (fileMetaData.level() > maxLevel) {
- maxLevel = fileMetaData.level();
- }
- }
- if (maxLevel == 0) {
- LOGGER.info("manualCompactionDefaultCfFiles skip level 0.");
- return;
- }
-
- for (LiveFileMetaData fileMetaData : defaultLiveFileDataList) {
- if (fileMetaData.level() != maxLevel || fileMetaData.beingCompacted()) {
- continue;
- }
- inputFileNames.add(fileMetaData.path() + fileMetaData.fileName());
- }
- if (!inputFileNames.isEmpty()) {
- List outputLists = this.db.compactFiles(compactionOptions, defaultCFHandle,
- inputFileNames, maxLevel, -1, null);
- LOGGER.info("manualCompactionDefaultCfFiles OK. src: {}, dst: {}", inputFileNames, outputLists);
- } else {
- LOGGER.info("manualCompactionDefaultCfFiles Empty.");
- }
- }
-
protected void manualCompactionDefaultCfRange(CompactRangeOptions compactRangeOptions) {
if (!hold()) {
return;
@@ -385,8 +338,10 @@ public synchronized boolean shutdown() {
this.options.close();
}
//4. close db.
- if (db != null) {
+ if (db != null && !this.readOnly) {
this.db.syncWal();
+ }
+ if (db != null) {
this.db.closeE();
}
//5. help gc.
@@ -492,50 +447,6 @@ public void flushWAL() throws RocksDBException {
this.db.flushWal(true);
}
- protected class WrappedRocksIterator {
- private final RocksIterator iterator;
-
- public WrappedRocksIterator(final RocksIterator iterator) {
- this.iterator = iterator;
- }
-
- public byte[] key() {
- return iterator.key();
- }
-
- public byte[] value() {
- return iterator.value();
- }
-
- public void next() {
- iterator.next();
- }
-
- public void prev() {
- iterator.prev();
- }
-
- public void seek(byte[] target) {
- iterator.seek(target);
- }
-
- public void seekForPrev(byte[] target) {
- iterator.seekForPrev(target);
- }
-
- public void seekToFirst() {
- iterator.seekToFirst();
- }
-
- public boolean isValid() {
- return iterator.isValid();
- }
-
- public void close() {
- iterator.close();
- }
- }
-
private String getStatusError(RocksDBException e) {
if (e == null || e.getStatus() == null) {
return "null";
@@ -572,7 +483,7 @@ public void statRocksdb(Logger logger) {
sb = new StringBuilder(256);
map.put(metaData.level(), sb);
}
- sb.append(new String(metaData.columnFamilyName(), CHARSET_UTF8)).append(SPACE).
+ sb.append(new String(metaData.columnFamilyName(), DataConverter.CHARSET_UTF8)).append(SPACE).
append(metaData.fileName()).append(SPACE).
append("s: ").append(metaData.size()).append(SPACE).
append("a: ").append(metaData.numEntries()).append(SPACE).
@@ -593,21 +504,4 @@ public void statRocksdb(Logger logger) {
} catch (Exception ignored) {
}
}
-
- public int compareTo(byte[] v1, byte[] v2) {
- int len1 = v1.length;
- int len2 = v2.length;
- int lim = Math.min(len1, len2);
-
- int k = 0;
- while (k < lim) {
- byte c1 = v1[k];
- byte c2 = v2[k];
- if (c1 != c2) {
- return c1 - c2;
- }
- k++;
- }
- return len1 - len2;
- }
}
\ No newline at end of file
diff --git a/common/src/main/java/org/apache/rocketmq/common/config/ConfigRocksDBStorage.java b/common/src/main/java/org/apache/rocketmq/common/config/ConfigRocksDBStorage.java
index 9d05ed28289..b40f8046e84 100644
--- a/common/src/main/java/org/apache/rocketmq/common/config/ConfigRocksDBStorage.java
+++ b/common/src/main/java/org/apache/rocketmq/common/config/ConfigRocksDBStorage.java
@@ -60,6 +60,12 @@ public ConfigRocksDBStorage(final String dbPath) {
this.readOnly = false;
}
+ public ConfigRocksDBStorage(final String dbPath, boolean readOnly) {
+ super();
+ this.dbPath = dbPath;
+ this.readOnly = readOnly;
+ }
+
private void initOptions() {
this.options = createConfigDBOptions();
@@ -197,7 +203,7 @@ private DBOptions createConfigDBOptions() {
setUseDirectReads(true);
}
- private static String getDBLogDir() {
+ public static String getDBLogDir() {
String rootPath = System.getProperty("user.home");
if (StringUtils.isEmpty(rootPath)) {
return "";
diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
index cb04b00b3ec..61310893f43 100644
--- a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
+++ b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
@@ -21,6 +21,7 @@ public class LoggerName {
public static final String NAMESRV_LOGGER_NAME = "RocketmqNamesrv";
public static final String NAMESRV_CONSOLE_LOGGER_NAME = "RocketmqNamesrvConsole";
public static final String CONTROLLER_LOGGER_NAME = "RocketmqController";
+ public static final String CONTROLLER_CONSOLE_NAME = "RocketmqControllerConsole";
public static final String NAMESRV_WATER_MARK_LOGGER_NAME = "RocketmqNamesrvWaterMark";
public static final String BROKER_LOGGER_NAME = "RocketmqBroker";
public static final String BROKER_CONSOLE_NAME = "RocketmqConsole";
diff --git a/common/src/main/java/org/apache/rocketmq/common/message/Message.java b/common/src/main/java/org/apache/rocketmq/common/message/Message.java
index e02b526a184..c7997c47318 100644
--- a/common/src/main/java/org/apache/rocketmq/common/message/Message.java
+++ b/common/src/main/java/org/apache/rocketmq/common/message/Message.java
@@ -218,14 +218,36 @@ public String toString() {
public void setDelayTimeSec(long sec) {
this.putProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC, String.valueOf(sec));
}
+
+ public long getDelayTimeSec() {
+ String t = this.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC);
+ if (t != null) {
+ return Long.parseLong(t);
+ }
+ return 0;
+ }
+
public void setDelayTimeMs(long timeMs) {
this.putProperty(MessageConst.PROPERTY_TIMER_DELAY_MS, String.valueOf(timeMs));
}
+
+ public long getDelayTimeMs() {
+ String t = this.getProperty(MessageConst.PROPERTY_TIMER_DELAY_MS);
+ if (t != null) {
+ return Long.parseLong(t);
+ }
+ return 0;
+ }
+
public void setDeliverTimeMs(long timeMs) {
this.putProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS, String.valueOf(timeMs));
}
public long getDeliverTimeMs() {
- return Long.parseLong(this.getUserProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS));
+ String t = this.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS);
+ if (t != null) {
+ return Long.parseLong(t);
+ }
+ return 0;
}
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageExtBrokerInner.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageExtBrokerInner.java
index 0c72ebb7bbd..91599653c5f 100644
--- a/common/src/main/java/org/apache/rocketmq/common/message/MessageExtBrokerInner.java
+++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageExtBrokerInner.java
@@ -70,4 +70,17 @@ public MessageVersion getVersion() {
public void setVersion(MessageVersion version) {
this.version = version;
}
+
+ public void removeWaitStorePropertyString() {
+ if (this.getProperties().containsKey(MessageConst.PROPERTY_WAIT_STORE_MSG_OK)) {
+ // There is no need to store "WAIT=true", remove it from propertiesString to save 9 bytes for each message.
+ // It works for most case. In some cases msgInner.setPropertiesString invoked later and replace it.
+ String waitStoreMsgOKValue = this.getProperties().remove(MessageConst.PROPERTY_WAIT_STORE_MSG_OK);
+ this.setPropertiesString(MessageDecoder.messageProperties2String(this.getProperties()));
+ // Reput to properties, since msgInner.isWaitStoreMsgOK() will be invoked later
+ this.getProperties().put(MessageConst.PROPERTY_WAIT_STORE_MSG_OK, waitStoreMsgOKValue);
+ } else {
+ this.setPropertiesString(MessageDecoder.messageProperties2String(this.getProperties()));
+ }
+ }
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/FutureTaskExtThreadPoolExecutor.java b/common/src/main/java/org/apache/rocketmq/common/thread/FutureTaskExtThreadPoolExecutor.java
index 411da922192..7b68873a99f 100644
--- a/common/src/main/java/org/apache/rocketmq/common/thread/FutureTaskExtThreadPoolExecutor.java
+++ b/common/src/main/java/org/apache/rocketmq/common/thread/FutureTaskExtThreadPoolExecutor.java
@@ -29,7 +29,8 @@ public class FutureTaskExtThreadPoolExecutor extends ThreadPoolExecutor {
public FutureTaskExtThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,
- BlockingQueue workQueue, ThreadFactory threadFactory,
+ BlockingQueue workQueue,
+ ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java
index 49d97a5d723..1bfabbffedd 100644
--- a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java
+++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java
@@ -22,12 +22,12 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.UtilAll;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
@@ -36,7 +36,7 @@ public class ThreadPoolMonitor {
private static Logger waterMarkLogger = LoggerFactory.getLogger(ThreadPoolMonitor.class);
private static final List MONITOR_EXECUTOR = new CopyOnWriteArrayList<>();
- private static final ScheduledExecutorService MONITOR_SCHEDULED = Executors.newSingleThreadScheduledExecutor(
+ private static final ScheduledExecutorService MONITOR_SCHEDULED = ThreadUtils.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder().setNameFormat("ThreadPoolMonitor-%d").build()
);
@@ -81,7 +81,7 @@ public static ThreadPoolExecutor createAndMonitor(int corePoolSize,
String name,
int queueCapacity,
List threadPoolStatusMonitors) {
- ThreadPoolExecutor executor = new FutureTaskExtThreadPoolExecutor(
+ ThreadPoolExecutor executor = (ThreadPoolExecutor) ThreadUtils.newThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
diff --git a/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java b/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java
index 61265c05d7c..c19592a44c3 100644
--- a/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java
+++ b/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java
@@ -31,6 +31,7 @@ public class TopicValidator {
public static final String RMQ_SYS_TRANS_CHECK_MAX_TIME_TOPIC = "TRANS_CHECK_MAX_TIME_TOPIC";
public static final String RMQ_SYS_SELF_TEST_TOPIC = "SELF_TEST_TOPIC";
public static final String RMQ_SYS_OFFSET_MOVED_EVENT = "OFFSET_MOVED_EVENT";
+ public static final String RMQ_SYS_ROCKSDB_OFFSET_TOPIC = "CHECKPOINT_TOPIC";
public static final String SYSTEM_TOPIC_PREFIX = "rmq_sys_";
public static final String SYNC_BROKER_MEMBER_GROUP_PREFIX = SYSTEM_TOPIC_PREFIX + "SYNC_BROKER_MEMBER_";
@@ -55,6 +56,7 @@ public class TopicValidator {
SYSTEM_TOPIC_SET.add(RMQ_SYS_TRANS_CHECK_MAX_TIME_TOPIC);
SYSTEM_TOPIC_SET.add(RMQ_SYS_SELF_TEST_TOPIC);
SYSTEM_TOPIC_SET.add(RMQ_SYS_OFFSET_MOVED_EVENT);
+ SYSTEM_TOPIC_SET.add(RMQ_SYS_ROCKSDB_OFFSET_TOPIC);
NOT_ALLOWED_SEND_TOPIC_SET.add(RMQ_SYS_SCHEDULE_TOPIC);
NOT_ALLOWED_SEND_TOPIC_SET.add(RMQ_SYS_TRANS_HALF_TOPIC);
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java b/common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java
index 421adaca4da..7b4b24819c6 100644
--- a/common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java
@@ -43,4 +43,21 @@ public static String generateMd5(byte[] content) {
byte[] bytes = calculateMd5(content);
return Hex.encodeHexString(bytes, false);
}
+
+ /**
+ * Returns true if subject contains only bytes that are spec-compliant ASCII characters.
+ * @param subject
+ * @return
+ */
+ public static boolean isAscii(byte[] subject) {
+ if (subject == null) {
+ return false;
+ }
+ for (byte b : subject) {
+ if ((b & 0x80) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
}
\ No newline at end of file
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/DataConverter.java b/common/src/main/java/org/apache/rocketmq/common/utils/DataConverter.java
index 8b50de12be8..cc96770b22a 100644
--- a/common/src/main/java/org/apache/rocketmq/common/utils/DataConverter.java
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/DataConverter.java
@@ -20,7 +20,7 @@
import java.nio.charset.Charset;
public class DataConverter {
- public static Charset charset = Charset.forName("UTF-8");
+ public static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
public static byte[] Long2Byte(Long v) {
ByteBuffer tmp = ByteBuffer.allocate(8);
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/ThreadUtils.java b/common/src/main/java/org/apache/rocketmq/common/utils/ThreadUtils.java
index 4b366d4e39b..1644c6360ec 100644
--- a/common/src/main/java/org/apache/rocketmq/common/utils/ThreadUtils.java
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/ThreadUtils.java
@@ -20,38 +20,94 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.thread.FutureTaskExtThreadPoolExecutor;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
public final class ThreadUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.TOOLS_LOGGER_NAME);
- public static ExecutorService newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
- TimeUnit unit, BlockingQueue workQueue, String processName, boolean isDaemon) {
- return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, newThreadFactory(processName, isDaemon));
+ public static ExecutorService newSingleThreadExecutor(String processName, boolean isDaemon) {
+ return ThreadUtils.newSingleThreadExecutor(newThreadFactory(processName, isDaemon));
}
- public static ExecutorService newSingleThreadExecutor(String processName, boolean isDaemon) {
- return Executors.newSingleThreadExecutor(newThreadFactory(processName, isDaemon));
+ public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
+ return ThreadUtils.newThreadPoolExecutor(1, threadFactory);
+ }
+
+ public static ExecutorService newThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
+ return ThreadUtils.newThreadPoolExecutor(corePoolSize, corePoolSize,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ threadFactory);
+ }
+
+ public static ExecutorService newThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit, BlockingQueue workQueue,
+ String processName,
+ boolean isDaemon) {
+ return ThreadUtils.newThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, newThreadFactory(processName, isDaemon));
+ }
+
+ public static ExecutorService newThreadPoolExecutor(final int corePoolSize,
+ final int maximumPoolSize,
+ final long keepAliveTime,
+ final TimeUnit unit,
+ final BlockingQueue workQueue,
+ final ThreadFactory threadFactory) {
+ return ThreadUtils.newThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, new ThreadPoolExecutor.AbortPolicy());
+ }
+
+ public static ExecutorService newThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue workQueue,
+ ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
+ return new FutureTaskExtThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(String processName, boolean isDaemon) {
- return Executors.newSingleThreadScheduledExecutor(newThreadFactory(processName, isDaemon));
+ return ThreadUtils.newScheduledThreadPool(1, processName, isDaemon);
+ }
+
+ public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
+ return ThreadUtils.newScheduledThreadPool(1, threadFactory);
+ }
+
+ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
+ return ThreadUtils.newScheduledThreadPool(corePoolSize, Executors.defaultThreadFactory());
}
- public static ScheduledExecutorService newFixedThreadScheduledPool(int nThreads, String processName,
+ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, String processName,
boolean isDaemon) {
- return Executors.newScheduledThreadPool(nThreads, newThreadFactory(processName, isDaemon));
+ return ThreadUtils.newScheduledThreadPool(corePoolSize, newThreadFactory(processName, isDaemon));
+ }
+
+ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
+ return ThreadUtils.newScheduledThreadPool(corePoolSize, threadFactory, new ThreadPoolExecutor.AbortPolicy());
+ }
+
+ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,
+ ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
+ return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory, handler);
}
public static ThreadFactory newThreadFactory(String processName, boolean isDaemon) {
- return newGenericThreadFactory("Remoting-" + processName, isDaemon);
+ return newGenericThreadFactory("ThreadUtils-" + processName, isDaemon);
}
public static ThreadFactory newGenericThreadFactory(String processName) {
diff --git a/common/src/test/java/org/apache/rocketmq/common/UtilAllTest.java b/common/src/test/java/org/apache/rocketmq/common/UtilAllTest.java
index f568a65f4d5..a0653d7fc43 100644
--- a/common/src/test/java/org/apache/rocketmq/common/UtilAllTest.java
+++ b/common/src/test/java/org/apache/rocketmq/common/UtilAllTest.java
@@ -238,41 +238,54 @@ public void testCalculateFileSizeInPath() throws Exception {
*/
String basePath = System.getProperty("java.io.tmpdir") + File.separator + "testCalculateFileSizeInPath";
File baseFile = new File(basePath);
- // test empty path
- assertEquals(0, UtilAll.calculateFileSizeInPath(baseFile));
-
- // create baseDir
- assertTrue(baseFile.mkdirs());
-
- File file0 = new File(baseFile, "file_0");
- assertTrue(file0.createNewFile());
- writeFixedBytesToFile(file0, 1313);
-
- assertEquals(1313, UtilAll.calculateFileSizeInPath(baseFile));
-
- // build a file tree like above
- File dir1 = new File(baseFile, "dir_1");
- dir1.mkdirs();
- File file10 = new File(dir1, "file_1_0");
- File file11 = new File(dir1, "file_1_1");
- File dir12 = new File(dir1, "dir_1_2");
- dir12.mkdirs();
- File file120 = new File(dir12, "file_1_2_0");
- File dir2 = new File(baseFile, "dir_2");
- dir2.mkdirs();
-
- // write all file with 1313 bytes data
- assertTrue(file10.createNewFile());
- writeFixedBytesToFile(file10, 1313);
- assertTrue(file11.createNewFile());
- writeFixedBytesToFile(file11, 1313);
- assertTrue(file120.createNewFile());
- writeFixedBytesToFile(file120, 1313);
-
- assertEquals(1313 * 4, UtilAll.calculateFileSizeInPath(baseFile));
-
- // clear all file
- baseFile.deleteOnExit();
+ try {
+ // test empty path
+ assertEquals(0, UtilAll.calculateFileSizeInPath(baseFile));
+
+ // create baseDir
+ assertTrue(baseFile.mkdirs());
+
+ File file0 = new File(baseFile, "file_0");
+ assertTrue(file0.createNewFile());
+ writeFixedBytesToFile(file0, 1313);
+
+ assertEquals(1313, UtilAll.calculateFileSizeInPath(baseFile));
+
+ // build a file tree like above
+ File dir1 = new File(baseFile, "dir_1");
+ dir1.mkdirs();
+ File file10 = new File(dir1, "file_1_0");
+ File file11 = new File(dir1, "file_1_1");
+ File dir12 = new File(dir1, "dir_1_2");
+ dir12.mkdirs();
+ File file120 = new File(dir12, "file_1_2_0");
+ File dir2 = new File(baseFile, "dir_2");
+ dir2.mkdirs();
+
+ // write all file with 1313 bytes data
+ assertTrue(file10.createNewFile());
+ writeFixedBytesToFile(file10, 1313);
+ assertTrue(file11.createNewFile());
+ writeFixedBytesToFile(file11, 1313);
+ assertTrue(file120.createNewFile());
+ writeFixedBytesToFile(file120, 1313);
+
+ assertEquals(1313 * 4, UtilAll.calculateFileSizeInPath(baseFile));
+ } finally {
+ deleteFolder(baseFile);
+ }
+ }
+
+ public static void deleteFolder(File folder) {
+ if (folder.isDirectory()) {
+ File[] files = folder.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ deleteFolder(file);
+ }
+ }
+ }
+ folder.delete();
}
private void writeFixedBytesToFile(File file, int size) throws Exception {
diff --git a/container/pom.xml b/container/pom.xml
index c8499f12730..8af231e013e 100644
--- a/container/pom.xml
+++ b/container/pom.xml
@@ -18,7 +18,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/container/src/main/java/org/apache/rocketmq/container/BrokerContainer.java b/container/src/main/java/org/apache/rocketmq/container/BrokerContainer.java
index c6446f058fa..5b712bc30db 100644
--- a/container/src/main/java/org/apache/rocketmq/container/BrokerContainer.java
+++ b/container/src/main/java/org/apache/rocketmq/container/BrokerContainer.java
@@ -47,14 +47,12 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class BrokerContainer implements IBrokerContainer {
private static final Logger LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
- private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ private final ScheduledExecutorService scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
new BasicThreadFactory.Builder()
.namingPattern("BrokerContainerScheduledThread")
.daemon(true)
@@ -143,7 +141,7 @@ public boolean initialize() {
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.containerClientHouseKeepingService);
this.fastRemotingServer = this.remotingServer.newRemotingServer(this.nettyServerConfig.getListenPort() - 2);
- this.brokerContainerExecutor = new ThreadPoolExecutor(
+ this.brokerContainerExecutor = ThreadUtils.newThreadPoolExecutor(
1,
1,
1000 * 60,
diff --git a/container/src/main/java/org/apache/rocketmq/container/BrokerContainerProcessor.java b/container/src/main/java/org/apache/rocketmq/container/BrokerContainerProcessor.java
index 2ac69112d76..5b825fe811c 100644
--- a/container/src/main/java/org/apache/rocketmq/container/BrokerContainerProcessor.java
+++ b/container/src/main/java/org/apache/rocketmq/container/BrokerContainerProcessor.java
@@ -91,11 +91,10 @@ private synchronized RemotingCommand addBroker(ChannelHandlerContext ctx,
LOGGER.error("addBroker load config from {} failed, {}", configPath, e);
}
} else {
- byte[] body = request.getBody();
- if (body != null) {
- String bodyStr = new String(body, MixAll.DEFAULT_CHARSET);
- brokerProperties = MixAll.string2Properties(bodyStr);
- }
+ LOGGER.error("addBroker config path is empty");
+ response.setCode(ResponseCode.SYSTEM_ERROR);
+ response.setRemark("addBroker config path is empty");
+ return response;
}
if (brokerProperties == null) {
diff --git a/controller/BUILD.bazel b/controller/BUILD.bazel
index 843d9dc7766..b2b743eb2d3 100644
--- a/controller/BUILD.bazel
+++ b/controller/BUILD.bazel
@@ -49,6 +49,7 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_sdk_common",
"@maven//:io_opentelemetry_opentelemetry_sdk_metrics",
"@maven//:io_opentelemetry_opentelemetry_exporter_logging",
+ "@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
"@maven//:org_slf4j_jul_to_slf4j",
],
)
diff --git a/controller/pom.xml b/controller/pom.xml
index 3346c7c8254..8432b220bee 100644
--- a/controller/pom.xml
+++ b/controller/pom.xml
@@ -19,7 +19,7 @@
rocketmq-all
org.apache.rocketmq
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
jar
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/ControllerManager.java b/controller/src/main/java/org/apache/rocketmq/controller/ControllerManager.java
index 7c91e70da50..3e6b0eba517 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/ControllerManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/ControllerManager.java
@@ -25,8 +25,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RunnableFuture;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
@@ -34,8 +32,8 @@
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.future.FutureTaskExt;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.controller.elect.impl.DefaultElectPolicy;
import org.apache.rocketmq.controller.impl.DLedgerController;
import org.apache.rocketmq.controller.impl.heartbeat.DefaultBrokerHeartbeatManager;
@@ -93,18 +91,14 @@ public ControllerManager(ControllerConfig controllerConfig, NettyServerConfig ne
public boolean initialize() {
this.controllerRequestThreadPoolQueue = new LinkedBlockingQueue<>(this.controllerConfig.getControllerRequestThreadPoolQueueCapacity());
- this.controllerRequestExecutor = new ThreadPoolExecutor(
+ this.controllerRequestExecutor = ThreadUtils.newThreadPoolExecutor(
this.controllerConfig.getControllerThreadPoolNums(),
this.controllerConfig.getControllerThreadPoolNums(),
1000 * 60,
TimeUnit.MILLISECONDS,
this.controllerRequestThreadPoolQueue,
- new ThreadFactoryImpl("ControllerRequestExecutorThread_")) {
- @Override
- protected RunnableFuture newTaskFor(final Runnable runnable, final T value) {
- return new FutureTaskExt(runnable, value);
- }
- };
+ new ThreadFactoryImpl("ControllerRequestExecutorThread_"));
+
this.notifyService.initialize();
if (StringUtils.isEmpty(this.controllerConfig.getControllerDLegerPeers())) {
throw new IllegalArgumentException("Attribute value controllerDLegerPeers of ControllerConfig is null or empty");
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/ControllerStartup.java b/controller/src/main/java/org/apache/rocketmq/controller/ControllerStartup.java
index 401720d0507..9e96a704de1 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/ControllerStartup.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/ControllerStartup.java
@@ -94,9 +94,10 @@ public static ControllerManager createControllerManager(String[] args) throws IO
}
if (commandLine.hasOption('p')) {
- MixAll.printObjectProperties(null, controllerConfig);
- MixAll.printObjectProperties(null, nettyServerConfig);
- MixAll.printObjectProperties(null, nettyClientConfig);
+ Logger console = LoggerFactory.getLogger(LoggerName.CONTROLLER_CONSOLE_NAME);
+ MixAll.printObjectProperties(console, controllerConfig);
+ MixAll.printObjectProperties(console, nettyServerConfig);
+ MixAll.printObjectProperties(console, nettyClientConfig);
System.exit(0);
}
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/DLedgerController.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/DLedgerController.java
index fa91f288e2d..33e4406e402 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/DLedgerController.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/DLedgerController.java
@@ -32,7 +32,6 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -44,6 +43,7 @@
import org.apache.rocketmq.common.ServiceThread;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.controller.Controller;
import org.apache.rocketmq.controller.elect.ElectPolicy;
import org.apache.rocketmq.controller.elect.impl.DefaultElectPolicy;
@@ -66,11 +66,11 @@
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.body.SyncStateSet;
import org.apache.rocketmq.remoting.protocol.header.controller.AlterSyncStateSetRequestHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
-import org.apache.rocketmq.remoting.protocol.header.controller.admin.CleanControllerBrokerDataRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetReplicaInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.controller.admin.CleanControllerBrokerDataRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.register.ApplyBrokerIdRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.register.GetNextBrokerIdRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.register.RegisterBrokerToControllerRequestHeader;
@@ -136,7 +136,7 @@ public DLedgerController(final ControllerConfig controllerConfig,
this.dLedgerServer = new DLedgerServer(dLedgerConfig, nettyServerConfig, nettyClientConfig, channelEventListener);
this.dLedgerServer.registerStateMachine(this.statemachine);
this.dLedgerServer.getDLedgerLeaderElector().addRoleChangeHandler(this.roleHandler);
- this.scanInactiveMasterService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("DLedgerController_scanInactiveService_"));
+ this.scanInactiveMasterService = ThreadUtils.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("DLedgerController_scanInactiveService_"));
this.brokerLifecycleListeners = new ArrayList<>();
}
@@ -513,7 +513,7 @@ public void handleException(final Throwable t) {
class RoleChangeHandler implements DLedgerLeaderElector.RoleChangeHandler {
private final String selfId;
- private final ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactoryImpl("DLedgerControllerRoleChangeHandler_"));
+ private final ExecutorService executorService = ThreadUtils.newSingleThreadExecutor(new ThreadFactoryImpl("DLedgerControllerRoleChangeHandler_"));
private volatile MemberState.Role currentRole = MemberState.Role.FOLLOWER;
public RoleChangeHandler(final String selfId) {
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/DefaultBrokerHeartbeatManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/DefaultBrokerHeartbeatManager.java
index 2fbddb9cdf9..6ebb2c99420 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/DefaultBrokerHeartbeatManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/DefaultBrokerHeartbeatManager.java
@@ -31,6 +31,7 @@
import org.apache.rocketmq.common.ControllerConfig;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.controller.BrokerHeartbeatManager;
import org.apache.rocketmq.controller.helper.BrokerLifecycleListener;
import org.apache.rocketmq.logging.org.slf4j.Logger;
@@ -66,7 +67,7 @@ public void shutdown() {
@Override
public void initialize() {
- this.scheduledService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("DefaultBrokerHeartbeatManager_scheduledService_"));
+ this.scheduledService = ThreadUtils.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("DefaultBrokerHeartbeatManager_scheduledService_"));
this.executor = Executors.newFixedThreadPool(2, new ThreadFactoryImpl("DefaultBrokerHeartbeatManager_executorService_"));
}
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/ReplicasInfoManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/ReplicasInfoManager.java
index b0a67531da2..d83a690f908 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/ReplicasInfoManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/ReplicasInfoManager.java
@@ -104,7 +104,7 @@ public ControllerResult alterSyncStateSet(
}
// Check master
- if (!syncStateInfo.getMasterBrokerId().equals(request.getMasterBrokerId())) {
+ if (syncStateInfo.getMasterBrokerId() == null || !syncStateInfo.getMasterBrokerId().equals(request.getMasterBrokerId())) {
String err = String.format("Rejecting alter syncStateSet request because the current leader is:{%s}, not {%s}",
syncStateInfo.getMasterBrokerId(), request.getMasterBrokerId());
LOGGER.error("{}", err);
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/metrics/ControllerMetricsManager.java b/controller/src/main/java/org/apache/rocketmq/controller/metrics/ControllerMetricsManager.java
index 650740bcc6e..be9e77eeaeb 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/metrics/ControllerMetricsManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/metrics/ControllerMetricsManager.java
@@ -26,7 +26,7 @@
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableLongGauge;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
+import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
@@ -38,6 +38,7 @@
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.View;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import java.io.File;
@@ -121,7 +122,7 @@ public class ControllerMetricsManager {
private PrometheusHttpServer prometheusHttpServer;
- private LoggingMetricExporter loggingMetricExporter;
+ private MetricExporter loggingMetricExporter;
public static ControllerMetricsManager getInstance(ControllerManager controllerManager) {
if (instance == null) {
@@ -364,8 +365,8 @@ public void init() {
if (type == MetricsExporterType.LOG) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
- loggingMetricExporter = LoggingMetricExporter.create(config.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
- java.util.logging.Logger.getLogger(LoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
+ loggingMetricExporter = OtlpJsonLoggingMetricExporter.create(config.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
+ java.util.logging.Logger.getLogger(OtlpJsonLoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
periodicMetricReader = PeriodicMetricReader.builder(loggingMetricExporter)
.setInterval(config.getMetricLoggingExporterIntervalInMills(), TimeUnit.MILLISECONDS)
.build();
diff --git a/controller/src/main/resources/rmq.controller.logback.xml b/controller/src/main/resources/rmq.controller.logback.xml
index bb158213af6..18083e8f987 100644
--- a/controller/src/main/resources/rmq.controller.logback.xml
+++ b/controller/src/main/resources/rmq.controller.logback.xml
@@ -116,6 +116,10 @@
+
+
+
+
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/DLedgerControllerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/DLedgerControllerTest.java
index 595a5cb6536..d6e5449c51b 100644
--- a/controller/src/test/java/org/apache/rocketmq/controller/impl/DLedgerControllerTest.java
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/DLedgerControllerTest.java
@@ -63,7 +63,8 @@ public class DLedgerControllerTest {
private List baseDirs;
private List controllers;
- public DLedgerController launchController(final String group, final String peers, final String selfId, final boolean isEnableElectUncleanMaster) {
+ public DLedgerController launchController(final String group, final String peers, final String selfId,
+ final boolean isEnableElectUncleanMaster) {
String tmpdir = System.getProperty("java.io.tmpdir");
final String path = (StringUtils.endsWith(tmpdir, File.separator) ? tmpdir : tmpdir + File.separator) + group + File.separator + selfId;
baseDirs.add(path);
@@ -121,11 +122,11 @@ public void registerNewBroker(Controller leader, String clusterName, String brok
final RegisterBrokerToControllerRequestHeader registerBrokerToControllerRequestHeader = new RegisterBrokerToControllerRequestHeader(clusterName, brokerName, nextBrokerId, brokerAddress);
RemotingCommand remotingCommand2 = leader.registerBroker(registerBrokerToControllerRequestHeader).get(2, TimeUnit.SECONDS);
-
assertEquals(ResponseCode.SUCCESS, remotingCommand2.getCode());
}
- public void brokerTryElectMaster(Controller leader, String clusterName, String brokerName, String brokerAddress, Long brokerId,
+ public void brokerTryElectMaster(Controller leader, String clusterName, String brokerName, String brokerAddress,
+ Long brokerId,
boolean exceptSuccess) throws Exception {
final ElectMasterRequestHeader electMasterRequestHeader = ElectMasterRequestHeader.ofBrokerTrigger(clusterName, brokerName, brokerId);
RemotingCommand command = leader.electMaster(electMasterRequestHeader).get(2, TimeUnit.SECONDS);
@@ -186,9 +187,9 @@ public DLedgerController mockMetaData(boolean enableElectUncleanMaster) throws E
registerNewBroker(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[1], 2L);
registerNewBroker(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[2], 3L);
// try elect
- brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[0], 1L,true);
- brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[1], 2L, false);
- brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[2], 3L,false);
+ brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[0], 1L, true);
+ brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[1], 2L, false);
+ brokerTryElectMaster(leader, DEFAULT_CLUSTER_NAME, DEFAULT_BROKER_NAME, DEFAULT_IP[2], 3L, false);
final RemotingCommand getInfoResponse = leader.getReplicaInfo(new GetReplicaInfoRequestHeader(DEFAULT_BROKER_NAME)).get(10, TimeUnit.SECONDS);
final GetReplicaInfoResponseHeader replicaInfo = (GetReplicaInfoResponseHeader) getInfoResponse.readCustomHeader();
assertEquals(1, replicaInfo.getMasterEpoch().intValue());
@@ -239,6 +240,8 @@ public void testElectMaster() throws Exception {
@Test
public void testBrokerLifecycleListener() throws Exception {
final DLedgerController leader = mockMetaData(false);
+
+ assertTrue(leader.isLeaderState());
// Mock that master broker has been inactive, and try to elect a new master from sync-state-set
// But we shut down two controller, so the ElectMasterEvent will be appended to DLedger failed.
// So the statemachine still keep the stale master's information
@@ -247,15 +250,20 @@ public void testBrokerLifecycleListener() throws Exception {
dLedgerController.shutdown();
controllers.remove(dLedgerController);
}
+
final ElectMasterRequestHeader request = ElectMasterRequestHeader.ofControllerTrigger(DEFAULT_BROKER_NAME);
setBrokerElectPolicy(leader, 1L);
Exception exception = null;
+ RemotingCommand remotingCommand = null;
try {
- leader.electMaster(request).get(5, TimeUnit.SECONDS);
+ remotingCommand = leader.electMaster(request).get(5, TimeUnit.SECONDS);
} catch (Exception e) {
exception = e;
}
- assertNotNull(exception);
+
+ assertTrue(exception != null ||
+ remotingCommand != null && remotingCommand.getCode() == ResponseCode.CONTROLLER_NOT_LEADER);
+
// Shut down leader controller
leader.shutdown();
controllers.remove(leader);
@@ -272,7 +280,7 @@ public void testBrokerLifecycleListener() throws Exception {
setBrokerAlivePredicate(newLeader, 1L);
// Check if the statemachine is stale
final RemotingCommand resp = newLeader.getReplicaInfo(new GetReplicaInfoRequestHeader(DEFAULT_BROKER_NAME)).
- get(10, TimeUnit.SECONDS);
+ get(10, TimeUnit.SECONDS);
final GetReplicaInfoResponseHeader replicaInfo = (GetReplicaInfoResponseHeader) resp.readCustomHeader();
assertEquals(1, replicaInfo.getMasterBrokerId().longValue());
assertEquals(1, replicaInfo.getMasterEpoch().intValue());
diff --git a/distribution/bin/mqbroker b/distribution/bin/mqbroker
index 3758ed597c0..35eb93c4461 100644
--- a/distribution/bin/mqbroker
+++ b/distribution/bin/mqbroker
@@ -68,11 +68,11 @@ if [ "$enable_proxy" = true ]; then
if [ "$broker_config" != "" ]; then
args_for_proxy=${args_for_proxy}" -bc "${broker_config}
fi
- sh ${ROCKETMQ_HOME}/bin/runserver.sh -Drmq.logback.configurationFile=$ROCKETMQ_HOME/conf/rmq.proxy.logback.xml org.apache.rocketmq.proxy.ProxyStartup ${args_for_proxy}
+ sh ${ROCKETMQ_HOME}/bin/runbroker.sh -Drmq.logback.configurationFile=$ROCKETMQ_HOME/conf/rmq.proxy.logback.xml org.apache.rocketmq.proxy.ProxyStartup ${args_for_proxy}
else
args_for_broker=$other_args
if [ "$broker_config" != "" ]; then
args_for_broker=${args_for_broker}" -c "${broker_config}
fi
sh ${ROCKETMQ_HOME}/bin/runbroker.sh -Drmq.logback.configurationFile=$ROCKETMQ_HOME/conf/rmq.broker.logback.xml org.apache.rocketmq.broker.BrokerStartup ${args_for_broker}
-fi
\ No newline at end of file
+fi
diff --git a/distribution/pom.xml b/distribution/pom.xml
index dbde2d9d4a7..73474d34a9e 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,7 +20,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
rocketmq-distribution
rocketmq-distribution ${project.version}
diff --git a/docs/cn/Debug_In_Idea.md b/docs/cn/Debug_In_Idea.md
new file mode 100644
index 00000000000..fd01751ee99
--- /dev/null
+++ b/docs/cn/Debug_In_Idea.md
@@ -0,0 +1,55 @@
+## 本地调试RocketMQ
+
+### Step0: 解决依赖问题
+1. 运行前下载RocketMQ需要的maven依赖,可以使用`mvn clean install -Dmaven.test.skip=true`
+2. 确保本地能够编译通过
+
+### Step1: 启动NameServer
+1. NamerServer的启动类在`org.apache.rocketmq.namesrv.NamesrvStartup`
+2. `Idea-Edit Configurations`中添加运行参数 `ROCKETMQ_HOME=`
+![Idea_config_nameserver.png](image/Idea_config_nameserver.png)
+3. 运行NameServer,观察到如下日志输出则启动成功
+```shell
+The Name Server boot success. serializeType=JSON, address 0.0.0.0:9876
+```
+
+### Step2: 启动Broker
+1. Broker的启动类在`org.apache.rocketmq.broker.BrokerStartup`
+2. 创建`/rocketmq/conf/broker.conf`文件或直接在官方release发布包中拷贝即可
+```shell
+# broker.conf
+
+brokerClusterName = DefaultCluster
+brokerName = broker-a
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+namesrvAddr = 127.0.0.1:9876 # name server地址
+```
+3. `Idea-Edit Configurations`中添加运行参数 `ROCKETMQ_HOME=` 以及环境变量`-c /Users/xxx/rocketmq/conf/broker.conf`
+![Idea_config_broker.png](image/Idea_config_broker.png)
+4. 运行Broker,观察到如下日志则启动成功
+```shell
+The broker[broker-a,192.169.1.2:10911] boot success...
+```
+
+### Step3: 发送或消费消息
+至此已经完成了RocketMQ的启动,可以使用`/example`里的示例进行收发消息
+
+### 补充:本地启动Proxy
+1. RocketMQ5.x支持了Proxy模式,使用`LOCAL`模式可以免去`Step2`,启动类在`org.apache.rocketmq.proxy.ProxyStartup`
+2. `Idea-Edit Configurations`中添加运行参数 `ROCKETMQ_HOME=`
+3. 在`/conf/`下新建配置文件`rmq-proxy.json`
+```json
+{
+ "rocketMQClusterName": "DefaultCluster",
+ "nameSrvAddr": "127.0.0.1:9876",
+ "proxyMode": "local"
+}
+```
+4. 运行Proxy,观察到如下日志则启动成功
+```shell
+Sat Aug 26 15:29:33 CST 2023 rocketmq-proxy startup successfully
+```
\ No newline at end of file
diff --git a/docs/cn/image/Idea_config_broker.png b/docs/cn/image/Idea_config_broker.png
new file mode 100644
index 00000000000..6fbedcfb627
Binary files /dev/null and b/docs/cn/image/Idea_config_broker.png differ
diff --git a/docs/cn/image/Idea_config_nameserver.png b/docs/cn/image/Idea_config_nameserver.png
new file mode 100644
index 00000000000..65edd991135
Binary files /dev/null and b/docs/cn/image/Idea_config_nameserver.png differ
diff --git a/docs/en/Debug_In_Idea.md b/docs/en/Debug_In_Idea.md
new file mode 100644
index 00000000000..9967980671f
--- /dev/null
+++ b/docs/en/Debug_In_Idea.md
@@ -0,0 +1,55 @@
+## How to Debug RocketMQ in Idea
+
+### Step0: Resolve dependencies
+1. To download the Maven dependencies required for running RocketMQ, you can use the following command:`mvn clean install -Dmaven.test.skip=true`
+2. Ensure successful local compilation.
+
+### Step1: Start NameServer
+1. The startup class for NameServer is located in `org.apache.rocketmq.namesrv.NamesrvStartup`.
+2. Add runtime `ROCKETMQ_HOME=` parameters in `Idea-Edit Configurations`.
+![Idea_config_nameserver.png](../cn/image/Idea_config_nameserver.png)
+3. Run NameServer and if the following log output is observed, it indicates successful startup.
+```shell
+The Name Server boot success. serializeType=JSON, address 0.0.0.0:9876
+```
+
+### Step2: Start Broker
+1. The startup class for Broker is located in`org.apache.rocketmq.broker.BrokerStartup`
+2. Create the `/rocketmq/conf/broker.conf` file or simply copy it from the official release package.
+```shell
+# broker.conf
+
+brokerClusterName = DefaultCluster
+brokerName = broker-a
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+namesrvAddr = 127.0.0.1:9876 # name server地址
+```
+3. Add the runtime parameter `ROCKETMQ_HOME=` and the environment variable `-c /Users/xxx/rocketmq/conf/broker.conf` in `Idea-Edit Configurations`.
+![Idea_config_broker.png](../cn/image/Idea_config_broker.png)
+4. Run the Broker and if the following log is observed, it indicates successful startup.
+```shell
+The broker[broker-a,192.169.1.2:10911] boot success...
+```
+
+### Step3: Send or Consume Messages
+RocketMQ startup is now complete. You can use the examples provided in `/example` to send and consume messages.
+
+### Additional: Start the Proxy locally.
+1. RocketMQ 5.x introduced the Proxy mode. Using the `LOCAL` mode eliminates the need for `Step2`. The startup class is located at `org.apache.rocketmq.proxy.ProxyStartup`.
+2. Add the runtime parameter `ROCKETMQ_HOME=` in `Idea-Edit Configurations`.
+3. Create a new configuration file named `rmq-proxy.json` in the `/conf/` directory.
+```json
+{
+ "rocketMQClusterName": "DefaultCluster",
+ "nameSrvAddr": "127.0.0.1:9876",
+ "proxyMode": "local"
+}
+```
+4. Run the Proxy, and if the following log is observed, it indicates successful startup.
+```shell
+Sat Aug 26 15:29:33 CST 2023 rocketmq-proxy startup successfully
+```
\ No newline at end of file
diff --git a/example/pom.xml b/example/pom.xml
index 862fc316919..a8c7f538224 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -19,7 +19,7 @@
rocketmq-all
org.apache.rocketmq
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/filter/pom.xml b/filter/pom.xml
index 3fe51ceae72..892f46e9d16 100644
--- a/filter/pom.xml
+++ b/filter/pom.xml
@@ -20,7 +20,7 @@
rocketmq-all
org.apache.rocketmq
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/namesrv/pom.xml b/namesrv/pom.xml
index 684b2683c38..e320ed5732f 100644
--- a/namesrv/pom.xml
+++ b/namesrv/pom.xml
@@ -19,7 +19,7 @@
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
index 15c65ebec9d..be327cffa51 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
@@ -20,10 +20,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.rocketmq.common.ThreadFactoryImpl;
@@ -31,6 +28,7 @@
import org.apache.rocketmq.common.future.FutureTaskExt;
import org.apache.rocketmq.common.namesrv.NamesrvConfig;
import org.apache.rocketmq.common.utils.NetworkUtil;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.namesrv.kvconfig.KVConfigManager;
@@ -62,10 +60,10 @@ public class NamesrvController {
private final NettyServerConfig nettyServerConfig;
private final NettyClientConfig nettyClientConfig;
- private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
+ private final ScheduledExecutorService scheduledExecutorService = ThreadUtils.newScheduledThreadPool(1,
new BasicThreadFactory.Builder().namingPattern("NSScheduledThread").daemon(true).build());
- private final ScheduledExecutorService scanExecutorService = new ScheduledThreadPoolExecutor(1,
+ private final ScheduledExecutorService scanExecutorService = ThreadUtils.newScheduledThreadPool(1,
new BasicThreadFactory.Builder().namingPattern("NSScanScheduledThread").daemon(true).build());
private final KVConfigManager kvConfigManager;
@@ -138,20 +136,10 @@ private void initiateNetworkComponents() {
private void initiateThreadExecutors() {
this.defaultThreadPoolQueue = new LinkedBlockingQueue<>(this.namesrvConfig.getDefaultThreadPoolQueueCapacity());
- this.defaultExecutor = new ThreadPoolExecutor(this.namesrvConfig.getDefaultThreadPoolNums(), this.namesrvConfig.getDefaultThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, this.defaultThreadPoolQueue, new ThreadFactoryImpl("RemotingExecutorThread_")) {
- @Override
- protected RunnableFuture newTaskFor(final Runnable runnable, final T value) {
- return new FutureTaskExt<>(runnable, value);
- }
- };
+ this.defaultExecutor = ThreadUtils.newThreadPoolExecutor(this.namesrvConfig.getDefaultThreadPoolNums(), this.namesrvConfig.getDefaultThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, this.defaultThreadPoolQueue, new ThreadFactoryImpl("RemotingExecutorThread_"));
this.clientRequestThreadPoolQueue = new LinkedBlockingQueue<>(this.namesrvConfig.getClientRequestThreadPoolQueueCapacity());
- this.clientRequestExecutor = new ThreadPoolExecutor(this.namesrvConfig.getClientRequestThreadPoolNums(), this.namesrvConfig.getClientRequestThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, this.clientRequestThreadPoolQueue, new ThreadFactoryImpl("ClientRequestExecutorThread_")) {
- @Override
- protected RunnableFuture newTaskFor(final Runnable runnable, final T value) {
- return new FutureTaskExt<>(runnable, value);
- }
- };
+ this.clientRequestExecutor = ThreadUtils.newThreadPoolExecutor(this.namesrvConfig.getClientRequestThreadPoolNums(), this.namesrvConfig.getClientRequestThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, this.clientRequestThreadPoolQueue, new ThreadFactoryImpl("ClientRequestExecutorThread_"));
}
private void initiateSslContext() {
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
index fada0efd774..485b95c42d7 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
@@ -41,7 +41,6 @@
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.body.BrokerMemberGroup;
import org.apache.rocketmq.remoting.protocol.body.GetBrokerMemberGroupResponseBody;
-import org.apache.rocketmq.remoting.protocol.body.GetRemoteClientConfigBody;
import org.apache.rocketmq.remoting.protocol.body.RegisterBrokerBody;
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
import org.apache.rocketmq.remoting.protocol.body.TopicList;
@@ -132,8 +131,6 @@ public RemotingCommand processRequest(ChannelHandlerContext ctx,
return this.updateConfig(ctx, request);
case RequestCode.GET_NAMESRV_CONFIG:
return this.getConfig(ctx, request);
- case RequestCode.GET_CLIENT_CONFIG:
- return this.getClientConfigs(ctx, request);
default:
String error = " request type " + request.getCode() + " not supported";
return RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error);
@@ -661,25 +658,4 @@ private RemotingCommand getConfig(ChannelHandlerContext ctx, RemotingCommand req
return response;
}
- private RemotingCommand getClientConfigs(ChannelHandlerContext ctx, RemotingCommand request) {
- final RemotingCommand response = RemotingCommand.createResponseCommand(null);
- final GetRemoteClientConfigBody body = GetRemoteClientConfigBody.decode(request.getBody(), GetRemoteClientConfigBody.class);
-
- String content = this.namesrvController.getConfiguration().getClientConfigsFormatString(body.getKeys());
- if (StringUtils.isNotBlank(content)) {
- try {
- response.setBody(content.getBytes(MixAll.DEFAULT_CHARSET));
- } catch (UnsupportedEncodingException e) {
- log.error("getConfig error, ", e);
- response.setCode(ResponseCode.SYSTEM_ERROR);
- response.setRemark("UnsupportedEncodingException " + e);
- return response;
- }
- }
-
- response.setCode(ResponseCode.SUCCESS);
- response.setRemark(null);
- return response;
- }
-
}
diff --git a/openmessaging/pom.xml b/openmessaging/pom.xml
index aaa4c896cd8..f10c8af6f0e 100644
--- a/openmessaging/pom.xml
+++ b/openmessaging/pom.xml
@@ -20,7 +20,7 @@
rocketmq-all
org.apache.rocketmq
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/pom.xml b/pom.xml
index 9f0b3eb96ba..a3f7c227050 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
2012
org.apache.rocketmq
rocketmq-all
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
pom
Apache RocketMQ ${project.version}
http://rocketmq.apache.org/
@@ -137,7 +137,7 @@
1.29.0-alpha
2.0.6
2.20.29
- 1.0.3
+ 1.0.2
2.13.4.2
@@ -713,7 +713,7 @@
${slf4j-api.version}
- io.github.aliyunmq
+ org.apache.rocketmq
rocketmq-rocksdb
${rocksdb.version}
@@ -974,6 +974,11 @@
opentelemetry-sdk
${opentelemetry.version}
+
+ io.opentelemetry
+ opentelemetry-exporter-logging-otlp
+ ${opentelemetry.version}
+
org.slf4j
jul-to-slf4j
diff --git a/proxy/BUILD.bazel b/proxy/BUILD.bazel
index b4f3c16e22d..cb7af925499 100644
--- a/proxy/BUILD.bazel
+++ b/proxy/BUILD.bazel
@@ -52,6 +52,7 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_exporter_otlp",
"@maven//:io_opentelemetry_opentelemetry_exporter_prometheus",
"@maven//:io_opentelemetry_opentelemetry_exporter_logging",
+ "@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
"@maven//:io_opentelemetry_opentelemetry_sdk",
"@maven//:io_opentelemetry_opentelemetry_sdk_common",
"@maven//:io_opentelemetry_opentelemetry_sdk_metrics",
diff --git a/proxy/pom.xml b/proxy/pom.xml
index 3fbea107abe..5c5349a8c13 100644
--- a/proxy/pom.xml
+++ b/proxy/pom.xml
@@ -20,7 +20,7 @@
rocketmq-all
org.apache.rocketmq
- 5.1.4-SNAPSHOT
+ 5.1.5-SNAPSHOT
4.0.0
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java
index 06d5f4525f0..3b2ca99bfd0 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java
@@ -85,6 +85,7 @@ public static void main(String[] args) {
.addService(ChannelzService.newInstance(100))
.addService(ProtoReflectionService.newInstance())
.configInterceptor(accessValidators)
+ .shutdownTime(ConfigurationManager.getProxyConfig().getGrpcShutdownTimeSeconds(), TimeUnit.SECONDS)
.build();
PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer);
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java
index 39caaa0d91d..c0d00d86409 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java
@@ -87,6 +87,7 @@ public class ProxyConfig implements ConfigFile {
*/
private String proxyMode = ProxyMode.CLUSTER.name();
private Integer grpcServerPort = 8081;
+ private long grpcShutdownTimeSeconds = 30;
private int grpcBossLoopNum = 1;
private int grpcWorkerLoopNum = PROCESSOR_NUMBER * 2;
private boolean enableGrpcEpoll = false;
@@ -155,14 +156,17 @@ public class ProxyConfig implements ConfigFile {
private int consumerProcessorThreadPoolQueueCapacity = 10000;
private boolean useEndpointPortFromRequest = false;
- private int topicRouteServiceCacheExpiredInSeconds = 20;
+
+ private int topicRouteServiceCacheExpiredSeconds = 300;
+ private int topicRouteServiceCacheRefreshSeconds = 20;
private int topicRouteServiceCacheMaxNum = 20000;
private int topicRouteServiceThreadPoolNums = PROCESSOR_NUMBER;
private int topicRouteServiceThreadPoolQueueCapacity = 5000;
-
- private int topicConfigCacheExpiredInSeconds = 20;
+ private int topicConfigCacheExpiredSeconds = 300;
+ private int topicConfigCacheRefreshSeconds = 20;
private int topicConfigCacheMaxNum = 20000;
- private int subscriptionGroupConfigCacheExpiredInSeconds = 20;
+ private int subscriptionGroupConfigCacheExpiredSeconds = 300;
+ private int subscriptionGroupConfigCacheRefreshSeconds = 20;
private int subscriptionGroupConfigCacheMaxNum = 20000;
private int metadataThreadPoolNums = 3;
private int metadataThreadPoolQueueCapacity = 100000;
@@ -229,6 +233,12 @@ public class ProxyConfig implements ConfigFile {
private String remotingAccessAddr = "";
private int remotingListenPort = 8080;
+ // related to proxy's send strategy in cluster mode.
+ private boolean sendLatencyEnable = false;
+ private boolean startDetectorEnable = false;
+ private int detectTimeout = 200;
+ private int detectInterval = 2 * 1000;
+
private int remotingHeartbeatThreadPoolNums = 2 * PROCESSOR_NUMBER;
private int remotingTopicRouteThreadPoolNums = 2 * PROCESSOR_NUMBER;
private int remotingSendMessageThreadPoolNums = 4 * PROCESSOR_NUMBER;
@@ -250,6 +260,8 @@ public class ProxyConfig implements ConfigFile {
private long remotingWaitTimeMillsInTopicRouteQueue = 3 * 1000;
private long remotingWaitTimeMillsInDefaultQueue = 3 * 1000;
+ private boolean enableBatchAck = false;
+
@Override
public void initData() {
parseDelayLevel();
@@ -432,6 +444,14 @@ public void setGrpcServerPort(Integer grpcServerPort) {
this.grpcServerPort = grpcServerPort;
}
+ public long getGrpcShutdownTimeSeconds() {
+ return grpcShutdownTimeSeconds;
+ }
+
+ public void setGrpcShutdownTimeSeconds(long grpcShutdownTimeSeconds) {
+ this.grpcShutdownTimeSeconds = grpcShutdownTimeSeconds;
+ }
+
public boolean isUseEndpointPortFromRequest() {
return useEndpointPortFromRequest;
}
@@ -792,12 +812,20 @@ public void setConsumerProcessorThreadPoolQueueCapacity(int consumerProcessorThr
this.consumerProcessorThreadPoolQueueCapacity = consumerProcessorThreadPoolQueueCapacity;
}
- public int getTopicRouteServiceCacheExpiredInSeconds() {
- return topicRouteServiceCacheExpiredInSeconds;
+ public int getTopicRouteServiceCacheExpiredSeconds() {
+ return topicRouteServiceCacheExpiredSeconds;
+ }
+
+ public void setTopicRouteServiceCacheExpiredSeconds(int topicRouteServiceCacheExpiredSeconds) {
+ this.topicRouteServiceCacheExpiredSeconds = topicRouteServiceCacheExpiredSeconds;
+ }
+
+ public int getTopicRouteServiceCacheRefreshSeconds() {
+ return topicRouteServiceCacheRefreshSeconds;
}
- public void setTopicRouteServiceCacheExpiredInSeconds(int topicRouteServiceCacheExpiredInSeconds) {
- this.topicRouteServiceCacheExpiredInSeconds = topicRouteServiceCacheExpiredInSeconds;
+ public void setTopicRouteServiceCacheRefreshSeconds(int topicRouteServiceCacheRefreshSeconds) {
+ this.topicRouteServiceCacheRefreshSeconds = topicRouteServiceCacheRefreshSeconds;
}
public int getTopicRouteServiceCacheMaxNum() {
@@ -824,12 +852,20 @@ public void setTopicRouteServiceThreadPoolQueueCapacity(int topicRouteServiceThr
this.topicRouteServiceThreadPoolQueueCapacity = topicRouteServiceThreadPoolQueueCapacity;
}
- public int getTopicConfigCacheExpiredInSeconds() {
- return topicConfigCacheExpiredInSeconds;
+ public int getTopicConfigCacheRefreshSeconds() {
+ return topicConfigCacheRefreshSeconds;
+ }
+
+ public void setTopicConfigCacheRefreshSeconds(int topicConfigCacheRefreshSeconds) {
+ this.topicConfigCacheRefreshSeconds = topicConfigCacheRefreshSeconds;
}
- public void setTopicConfigCacheExpiredInSeconds(int topicConfigCacheExpiredInSeconds) {
- this.topicConfigCacheExpiredInSeconds = topicConfigCacheExpiredInSeconds;
+ public int getTopicConfigCacheExpiredSeconds() {
+ return topicConfigCacheExpiredSeconds;
+ }
+
+ public void setTopicConfigCacheExpiredSeconds(int topicConfigCacheExpiredSeconds) {
+ this.topicConfigCacheExpiredSeconds = topicConfigCacheExpiredSeconds;
}
public int getTopicConfigCacheMaxNum() {
@@ -840,12 +876,20 @@ public void setTopicConfigCacheMaxNum(int topicConfigCacheMaxNum) {
this.topicConfigCacheMaxNum = topicConfigCacheMaxNum;
}
- public int getSubscriptionGroupConfigCacheExpiredInSeconds() {
- return subscriptionGroupConfigCacheExpiredInSeconds;
+ public int getSubscriptionGroupConfigCacheRefreshSeconds() {
+ return subscriptionGroupConfigCacheRefreshSeconds;
}
- public void setSubscriptionGroupConfigCacheExpiredInSeconds(int subscriptionGroupConfigCacheExpiredInSeconds) {
- this.subscriptionGroupConfigCacheExpiredInSeconds = subscriptionGroupConfigCacheExpiredInSeconds;
+ public void setSubscriptionGroupConfigCacheRefreshSeconds(int subscriptionGroupConfigCacheRefreshSeconds) {
+ this.subscriptionGroupConfigCacheRefreshSeconds = subscriptionGroupConfigCacheRefreshSeconds;
+ }
+
+ public int getSubscriptionGroupConfigCacheExpiredSeconds() {
+ return subscriptionGroupConfigCacheExpiredSeconds;
+ }
+
+ public void setSubscriptionGroupConfigCacheExpiredSeconds(int subscriptionGroupConfigCacheExpiredSeconds) {
+ this.subscriptionGroupConfigCacheExpiredSeconds = subscriptionGroupConfigCacheExpiredSeconds;
}
public int getSubscriptionGroupConfigCacheMaxNum() {
@@ -1379,4 +1423,52 @@ public long getRemotingWaitTimeMillsInDefaultQueue() {
public void setRemotingWaitTimeMillsInDefaultQueue(long remotingWaitTimeMillsInDefaultQueue) {
this.remotingWaitTimeMillsInDefaultQueue = remotingWaitTimeMillsInDefaultQueue;
}
+
+ public boolean isSendLatencyEnable() {
+ return sendLatencyEnable;
+ }
+
+ public boolean isStartDetectorEnable() {
+ return startDetectorEnable;
+ }
+
+ public void setStartDetectorEnable(boolean startDetectorEnable) {
+ this.startDetectorEnable = startDetectorEnable;
+ }
+
+ public void setSendLatencyEnable(boolean sendLatencyEnable) {
+ this.sendLatencyEnable = sendLatencyEnable;
+ }
+
+ public boolean getStartDetectorEnable() {
+ return this.startDetectorEnable;
+ }
+
+ public boolean getSendLatencyEnable() {
+ return this.sendLatencyEnable;
+ }
+
+ public int getDetectTimeout() {
+ return detectTimeout;
+ }
+
+ public void setDetectTimeout(int detectTimeout) {
+ this.detectTimeout = detectTimeout;
+ }
+
+ public int getDetectInterval() {
+ return detectInterval;
+ }
+
+ public void setDetectInterval(int detectInterval) {
+ this.detectInterval = detectInterval;
+ }
+
+ public boolean isEnableBatchAck() {
+ return enableBatchAck;
+ }
+
+ public void setEnableBatchAck(boolean enableBatchAck) {
+ this.enableBatchAck = enableBatchAck;
+ }
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java
index 1bffa3c0be1..d5b896fe144 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java
@@ -29,8 +29,14 @@ public class GrpcServer implements StartAndShutdown {
private final Server server;
- protected GrpcServer(Server server) {
+ private final long timeout;
+
+ private final TimeUnit unit;
+
+ protected GrpcServer(Server server, long timeout, TimeUnit unit) {
this.server = server;
+ this.timeout = timeout;
+ this.unit = unit;
}
public void start() throws Exception {
@@ -40,7 +46,7 @@ public void start() throws Exception {
public void shutdown() {
try {
- this.server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
+ this.server.shutdown().awaitTermination(timeout, unit);
log.info("grpc server shutdown successfully.");
} catch (Exception e) {
e.printStackTrace();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java
index 9cddd301373..0e79006f6b3 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java
@@ -41,6 +41,10 @@ public class GrpcServerBuilder {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
protected NettyServerBuilder serverBuilder;
+ protected long time = 30;
+
+ protected TimeUnit unit = TimeUnit.SECONDS;
+
public static GrpcServerBuilder newBuilder(ThreadPoolExecutor executor, int port) {
return new GrpcServerBuilder(executor, port);
}
@@ -77,6 +81,12 @@ protected GrpcServerBuilder(ThreadPoolExecutor executor, int port) {
port, bossLoopNum, workerLoopNum, maxInboundMessageSize);
}
+ public GrpcServerBuilder shutdownTime(long time, TimeUnit unit) {
+ this.time = time;
+ this.unit = unit;
+ return this;
+ }
+
public GrpcServerBuilder addService(BindableService service) {
this.serverBuilder.addService(service);
return this;
@@ -93,7 +103,7 @@ public GrpcServerBuilder appendInterceptor(ServerInterceptor interceptor) {
}
public GrpcServer build() {
- return new GrpcServer(this.serverBuilder.build());
+ return new GrpcServer(this.serverBuilder.build(), time, unit);
}
public GrpcServerBuilder configInterceptor(List accessValidators) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/ProxyAndTlsProtocolNegotiator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/ProxyAndTlsProtocolNegotiator.java
index ee167bd7bee..b584ddfbdc6 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/ProxyAndTlsProtocolNegotiator.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/ProxyAndTlsProtocolNegotiator.java
@@ -24,6 +24,7 @@
import io.grpc.netty.shaded.io.grpc.netty.InternalProtocolNegotiators;
import io.grpc.netty.shaded.io.grpc.netty.ProtocolNegotiationEvent;
import io.grpc.netty.shaded.io.netty.buffer.ByteBuf;
+import io.grpc.netty.shaded.io.netty.buffer.ByteBufUtil;
import io.grpc.netty.shaded.io.netty.channel.ChannelHandler;
import io.grpc.netty.shaded.io.netty.channel.ChannelHandlerContext;
import io.grpc.netty.shaded.io.netty.channel.ChannelInboundHandlerAdapter;
@@ -44,6 +45,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.constant.HAProxyConstants;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.BinaryUtil;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
@@ -191,9 +193,13 @@ private void handleWithMessage(HAProxyMessage msg) {
}
if (CollectionUtils.isNotEmpty(msg.tlvs())) {
msg.tlvs().forEach(tlv -> {
+ byte[] valueBytes = ByteBufUtil.getBytes(tlv.content());
+ if (!BinaryUtil.isAscii(valueBytes)) {
+ return;
+ }
Attributes.Key key = AttributeKeys.valueOf(
HAProxyConstants.PROXY_PROTOCOL_TLV_PREFIX + String.format("%02x", tlv.typeByteValue()));
- String value = StringUtils.trim(tlv.content().toString(CharsetUtil.UTF_8));
+ String value = StringUtils.trim(new String(valueBytes, CharsetUtil.UTF_8));
builder.set(key, value);
});
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java
index 14330dd8d48..a18cf7600c1 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java
@@ -21,13 +21,13 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.common.ThreadFactoryImpl;
-import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.common.utils.StartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
+import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager;
@@ -43,7 +43,7 @@ public class GrpcChannelManager implements StartAndShutdown {
protected final AtomicLong nonceIdGenerator = new AtomicLong(0);
protected final ConcurrentMap resultNonceFutureMap = new ConcurrentHashMap<>();
- protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
+ protected final ScheduledExecutorService scheduledExecutorService = ThreadUtils.newSingleThreadScheduledExecutor(
new ThreadFactoryImpl("GrpcChannelManager_")
);
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java
index 9a3a772017e..97c716c8ff3 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java
@@ -31,12 +31,15 @@
import org.apache.rocketmq.common.consumer.ReceiptHandle;
import org.apache.rocketmq.proxy.common.MessageReceiptHandle;
import org.apache.rocketmq.proxy.common.ProxyContext;
+import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity;
import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager;
import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager;
import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter;
import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder;
+import org.apache.rocketmq.proxy.processor.BatchAckResult;
import org.apache.rocketmq.proxy.processor.MessagingProcessor;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
public class AckMessageActivity extends AbstractMessingActivity {
@@ -50,60 +53,98 @@ public CompletableFuture ackMessage(ProxyContext ctx, AckMes
try {
validateTopicAndConsumerGroup(request.getTopic(), request.getGroup());
-
- CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()];
- for (int i = 0; i < request.getEntriesCount(); i++) {
- futures[i] = processAckMessage(ctx, request, request.getEntries(i));
+ String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup());
+ String topic = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic());
+ if (ConfigurationManager.getProxyConfig().isEnableBatchAck()) {
+ future = ackMessageInBatch(ctx, group, topic, request);
+ } else {
+ future = ackMessageOneByOne(ctx, group, topic, request);
}
- CompletableFuture.allOf(futures).whenComplete((val, throwable) -> {
- if (throwable != null) {
- future.completeExceptionally(throwable);
- return;
- }
+ } catch (Throwable t) {
+ future.completeExceptionally(t);
+ }
+ return future;
+ }
+
+ protected CompletableFuture ackMessageInBatch(ProxyContext ctx, String group, String topic, AckMessageRequest request) {
+ List handleMessageList = new ArrayList<>(request.getEntriesCount());
+ for (AckMessageEntry ackMessageEntry : request.getEntriesList()) {
+ String handleString = getHandleString(ctx, group, request, ackMessageEntry);
+ handleMessageList.add(new ReceiptHandleMessage(ReceiptHandle.decode(handleString), ackMessageEntry.getMessageId()));
+ }
+ return this.messagingProcessor.batchAckMessage(ctx, handleMessageList, group, topic)
+ .thenApply(batchAckResultList -> {
+ AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder();
Set responseCodes = new HashSet<>();
- List entryList = new ArrayList<>();
- for (CompletableFuture entryFuture : futures) {
- AckMessageResultEntry entryResult = entryFuture.join();
- responseCodes.add(entryResult.getStatus().getCode());
- entryList.add(entryResult);
- }
- AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder()
- .addAllEntries(entryList);
- if (responseCodes.size() > 1) {
- responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name()));
- } else if (responseCodes.size() == 1) {
- Code code = responseCodes.stream().findAny().get();
- responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(code, code.name()));
- } else {
- responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message result is empty"));
+ for (BatchAckResult batchAckResult : batchAckResultList) {
+ AckMessageResultEntry entry = convertToAckMessageResultEntry(batchAckResult);
+ responseBuilder.addEntries(entry);
+ responseCodes.add(entry.getStatus().getCode());
}
- future.complete(responseBuilder.build());
+ setAckResponseStatus(responseBuilder, responseCodes);
+ return responseBuilder.build();
});
- } catch (Throwable t) {
- future.completeExceptionally(t);
+ }
+
+ protected AckMessageResultEntry convertToAckMessageResultEntry(BatchAckResult batchAckResult) {
+ ReceiptHandleMessage handleMessage = batchAckResult.getReceiptHandleMessage();
+ AckMessageResultEntry.Builder resultBuilder = AckMessageResultEntry.newBuilder()
+ .setMessageId(handleMessage.getMessageId())
+ .setReceiptHandle(handleMessage.getReceiptHandle().getReceiptHandle());
+ if (batchAckResult.getProxyException() != null) {
+ resultBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(batchAckResult.getProxyException()));
+ } else {
+ AckResult ackResult = batchAckResult.getAckResult();
+ if (AckStatus.OK.equals(ackResult.getStatus())) {
+ resultBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name()));
+ } else {
+ resultBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal"));
+ }
}
- return future;
+ return resultBuilder.build();
}
- protected CompletableFuture processAckMessage(ProxyContext ctx, AckMessageRequest request,
+ protected CompletableFuture ackMessageOneByOne(ProxyContext ctx, String group, String topic, AckMessageRequest request) {
+ CompletableFuture resultFuture = new CompletableFuture<>();
+ CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()];
+ for (int i = 0; i < request.getEntriesCount(); i++) {
+ futures[i] = processAckMessage(ctx, group, topic, request, request.getEntries(i));
+ }
+ CompletableFuture.allOf(futures).whenComplete((val, throwable) -> {
+ if (throwable != null) {
+ resultFuture.completeExceptionally(throwable);
+ return;
+ }
+
+ Set responseCodes = new HashSet<>();
+ List entryList = new ArrayList<>();
+ for (CompletableFuture entryFuture : futures) {
+ AckMessageResultEntry entryResult = entryFuture.join();
+ responseCodes.add(entryResult.getStatus().getCode());
+ entryList.add(entryResult);
+ }
+ AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder()
+ .addAllEntries(entryList);
+ setAckResponseStatus(responseBuilder, responseCodes);
+ resultFuture.complete(responseBuilder.build());
+ });
+ return resultFuture;
+ }
+
+ protected CompletableFuture processAckMessage(ProxyContext ctx, String group, String topic, AckMessageRequest request,
AckMessageEntry ackMessageEntry) {
CompletableFuture future = new CompletableFuture<>();
try {
- String handleString = ackMessageEntry.getReceiptHandle();
-
- String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup());
- MessageReceiptHandle messageReceiptHandle = messagingProcessor.removeReceiptHandle(ctx, grpcChannelManager.getChannel(ctx.getClientID()), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle());
- if (messageReceiptHandle != null) {
- handleString = messageReceiptHandle.getReceiptHandleStr();
- }
+ String handleString = this.getHandleString(ctx, group, request, ackMessageEntry);
CompletableFuture ackResultFuture = this.messagingProcessor.ackMessage(
ctx,
ReceiptHandle.decode(handleString),
ackMessageEntry.getMessageId(),
group,
- GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic()));
+ topic
+ );
ackResultFuture.thenAccept(result -> {
future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result));
}).exceptionally(t -> {
@@ -139,4 +180,25 @@ protected AckMessageResultEntry convertToAckMessageResultEntry(ProxyContext ctx,
.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal"))
.build();
}
+
+ protected void setAckResponseStatus(AckMessageResponse.Builder responseBuilder, Set responseCodes) {
+ if (responseCodes.size() > 1) {
+ responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name()));
+ } else if (responseCodes.size() == 1) {
+ Code code = responseCodes.stream().findAny().get();
+ responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(code, code.name()));
+ } else {
+ responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message result is empty"));
+ }
+ }
+
+ protected String getHandleString(ProxyContext ctx, String group, AckMessageRequest request, AckMessageEntry ackMessageEntry) {
+ String handleString = ackMessageEntry.getReceiptHandle();
+
+ MessageReceiptHandle messageReceiptHandle = messagingProcessor.removeReceiptHandle(ctx, grpcChannelManager.getChannel(ctx.getClientID()), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle());
+ if (messageReceiptHandle != null) {
+ handleString = messageReceiptHandle.getReceiptHandleStr();
+ }
+ return handleString;
+ }
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java
index 6146c80cd0f..f670df2050e 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java
@@ -382,7 +382,7 @@ public AddressableMessageQueue select(ProxyContext ctx, MessageQueueView message
int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size());
targetMessageQueue = writeQueues.get(bucket);
} else {
- targetMessageQueue = messageQueueView.getWriteSelector().selectOne(false);
+ targetMessageQueue = messageQueueView.getWriteSelector().selectOneByPipeline(false);
}
return targetMessageQueue;
} catch (Exception e) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/metrics/ProxyMetricsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/metrics/ProxyMetricsManager.java
index f5050858f61..2b8dac5d8be 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/metrics/ProxyMetricsManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/metrics/ProxyMetricsManager.java
@@ -21,15 +21,16 @@
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableLongGauge;
+import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
@@ -42,9 +43,9 @@
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.metrics.MetricsExporterType;
import org.apache.rocketmq.common.utils.StartAndShutdown;
-import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.slf4j.bridge.SLF4JBridgeHandler;
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.AGGREGATION_DELTA;
@@ -67,7 +68,7 @@ public class ProxyMetricsManager implements StartAndShutdown {
private OtlpGrpcMetricExporter metricExporter;
private PeriodicMetricReader periodicMetricReader;
private PrometheusHttpServer prometheusHttpServer;
- private LoggingMetricExporter loggingMetricExporter;
+ private MetricExporter loggingMetricExporter;
public static ObservableLongGauge proxyUp = null;
@@ -221,8 +222,8 @@ public void start() throws Exception {
if (metricsExporterType == MetricsExporterType.LOG) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
- loggingMetricExporter = LoggingMetricExporter.create(proxyConfig.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
- java.util.logging.Logger.getLogger(LoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
+ loggingMetricExporter = OtlpJsonLoggingMetricExporter.create(proxyConfig.isMetricsInDelta() ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE);
+ java.util.logging.Logger.getLogger(OtlpJsonLoggingMetricExporter.class.getName()).setLevel(java.util.logging.Level.FINEST);
periodicMetricReader = PeriodicMetricReader.builder(loggingMetricExporter)
.setInterval(proxyConfig.getMetricLoggingExporterIntervalInMills(), TimeUnit.MILLISECONDS)
.build();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java
index b61c3df9e52..c63212c2314 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java
@@ -27,6 +27,8 @@ public abstract class AbstractProcessor extends AbstractStartAndShutdown {
protected MessagingProcessor messagingProcessor;
protected ServiceManager serviceManager;
+ protected static final ProxyException EXPIRED_HANDLE_PROXY_EXCEPTION = new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "receipt handle is expired");
+
public AbstractProcessor(MessagingProcessor messagingProcessor,
ServiceManager serviceManager) {
this.messagingProcessor = messagingProcessor;
@@ -35,7 +37,7 @@ public AbstractProcessor(MessagingProcessor messagingProcessor,
protected void validateReceiptHandle(ReceiptHandle handle) {
if (handle.isExpired()) {
- throw new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "receipt handle is expired");
+ throw EXPIRED_HANDLE_PROXY_EXCEPTION;
}
}
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/BatchAckResult.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/BatchAckResult.java
new file mode 100644
index 00000000000..dfb9c9b9e02
--- /dev/null
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/BatchAckResult.java
@@ -0,0 +1,53 @@
+/*
+ * 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.proxy.processor;
+
+import org.apache.rocketmq.client.consumer.AckResult;
+import org.apache.rocketmq.proxy.common.ProxyException;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
+
+public class BatchAckResult {
+
+ private final ReceiptHandleMessage receiptHandleMessage;
+ private AckResult ackResult;
+ private ProxyException proxyException;
+
+ public BatchAckResult(ReceiptHandleMessage receiptHandleMessage,
+ AckResult ackResult) {
+ this.receiptHandleMessage = receiptHandleMessage;
+ this.ackResult = ackResult;
+ }
+
+ public BatchAckResult(ReceiptHandleMessage receiptHandleMessage,
+ ProxyException proxyException) {
+ this.receiptHandleMessage = receiptHandleMessage;
+ this.proxyException = proxyException;
+ }
+
+ public ReceiptHandleMessage getReceiptHandleMessage() {
+ return receiptHandleMessage;
+ }
+
+ public AckResult getAckResult() {
+ return ackResult;
+ }
+
+ public ProxyException getProxyException() {
+ return proxyException;
+ }
+}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java
index 656a6339dc3..f3522b37401 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java
@@ -48,6 +48,7 @@
import org.apache.rocketmq.proxy.common.utils.FutureUtils;
import org.apache.rocketmq.proxy.common.utils.ProxyUtils;
import org.apache.rocketmq.proxy.service.ServiceManager;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
import org.apache.rocketmq.remoting.protocol.body.LockBatchRequestBody;
import org.apache.rocketmq.remoting.protocol.body.UnlockBatchRequestBody;
@@ -241,6 +242,69 @@ public CompletableFuture ackMessage(
return FutureUtils.addExecutor(future, this.executor);
}
+ public CompletableFuture> batchAckMessage(
+ ProxyContext ctx,
+ List handleMessageList,
+ String consumerGroup,
+ String topic,
+ long timeoutMillis
+ ) {
+ CompletableFuture> future = new CompletableFuture<>();
+ try {
+ List batchAckResultList = new ArrayList<>(handleMessageList.size());
+ Map> brokerHandleListMap = new HashMap<>();
+
+ for (ReceiptHandleMessage handleMessage : handleMessageList) {
+ if (handleMessage.getReceiptHandle().isExpired()) {
+ batchAckResultList.add(new BatchAckResult(handleMessage, EXPIRED_HANDLE_PROXY_EXCEPTION));
+ continue;
+ }
+ List brokerHandleList = brokerHandleListMap.computeIfAbsent(handleMessage.getReceiptHandle().getBrokerName(), key -> new ArrayList<>());
+ brokerHandleList.add(handleMessage);
+ }
+
+ if (brokerHandleListMap.isEmpty()) {
+ return FutureUtils.addExecutor(CompletableFuture.completedFuture(batchAckResultList), this.executor);
+ }
+ Set>> brokerHandleListMapEntrySet = brokerHandleListMap.entrySet();
+ CompletableFuture>[] futures = new CompletableFuture[brokerHandleListMapEntrySet.size()];
+ int futureIndex = 0;
+ for (Map.Entry> entry : brokerHandleListMapEntrySet) {
+ futures[futureIndex++] = processBrokerHandle(ctx, consumerGroup, topic, entry.getValue(), timeoutMillis);
+ }
+ CompletableFuture.allOf(futures).whenComplete((val, throwable) -> {
+ if (throwable != null) {
+ future.completeExceptionally(throwable);
+ }
+ for (CompletableFuture> resultFuture : futures) {
+ batchAckResultList.addAll(resultFuture.join());
+ }
+ future.complete(batchAckResultList);
+ });
+ } catch (Throwable t) {
+ future.completeExceptionally(t);
+ }
+ return FutureUtils.addExecutor(future, this.executor);
+ }
+
+ protected CompletableFuture> processBrokerHandle(ProxyContext ctx, String consumerGroup, String topic, List handleMessageList, long timeoutMillis) {
+ return this.serviceManager.getMessageService().batchAckMessage(ctx, handleMessageList, consumerGroup, topic, timeoutMillis)
+ .thenApply(result -> {
+ List results = new ArrayList<>();
+ for (ReceiptHandleMessage handleMessage : handleMessageList) {
+ results.add(new BatchAckResult(handleMessage, result));
+ }
+ return results;
+ })
+ .exceptionally(throwable -> {
+ List results = new ArrayList<>();
+ for (ReceiptHandleMessage handleMessage : handleMessageList) {
+ results.add(new BatchAckResult(handleMessage, new ProxyException(ProxyExceptionCode.INTERNAL_SERVER_ERROR, throwable.getMessage(), throwable)));
+ }
+ return results;
+ });
+ }
+
public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle,
String messageId, String groupName, String topicName, long invisibleTime, long timeoutMillis) {
CompletableFuture future = new CompletableFuture<>();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java
index 188cb7b9bd3..ba150051bc0 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java
@@ -46,6 +46,7 @@
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.service.ServiceManager;
import org.apache.rocketmq.proxy.service.ServiceManagerFactory;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
import org.apache.rocketmq.proxy.service.metadata.MetadataService;
import org.apache.rocketmq.proxy.service.relay.ProxyRelayService;
import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
@@ -183,6 +184,12 @@ public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle h
return this.consumerProcessor.ackMessage(ctx, handle, messageId, consumerGroup, topic, timeoutMillis);
}
+ @Override
+ public CompletableFuture> batchAckMessage(ProxyContext ctx,
+ List handleMessageList, String consumerGroup, String topic, long timeoutMillis) {
+ return this.consumerProcessor.batchAckMessage(ctx, handleMessageList, consumerGroup, topic, timeoutMillis);
+ }
+
@Override
public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, String messageId,
String groupName, String topicName, long invisibleTime, long timeoutMillis) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java
index d86be0bd887..2ae7418ba72 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java
@@ -37,6 +37,7 @@
import org.apache.rocketmq.proxy.common.MessageReceiptHandle;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.common.utils.StartAndShutdown;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
import org.apache.rocketmq.proxy.service.metadata.MetadataService;
import org.apache.rocketmq.proxy.service.relay.ProxyRelayService;
import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
@@ -155,6 +156,23 @@ CompletableFuture ackMessage(
long timeoutMillis
);
+ default CompletableFuture> batchAckMessage(
+ ProxyContext ctx,
+ List handleMessageList,
+ String consumerGroup,
+ String topic
+ ) {
+ return batchAckMessage(ctx, handleMessageList, consumerGroup, topic, DEFAULT_TIMEOUT_MILLS);
+ }
+
+ CompletableFuture> batchAckMessage(
+ ProxyContext ctx,
+ List handleMessageList,
+ String consumerGroup,
+ String topic,
+ long timeoutMillis
+ );
+
default CompletableFuture changeInvisibleTime(
ProxyContext ctx,
ReceiptHandle handle,
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java
index 0d0c6216862..a80f6df0b07 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java
@@ -19,6 +19,7 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
@@ -66,6 +67,8 @@ public ProducerProcessor(MessagingProcessor messagingProcessor,
public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector,
String producerGroup, int sysFlag, List messageList, long timeoutMillis) {
CompletableFuture> future = new CompletableFuture<>();
+ long beginTimestampFirst = System.currentTimeMillis();
+ AddressableMessageQueue messageQueue = null;
try {
Message message = messageList.get(0);
String topic = message.getTopic();
@@ -79,7 +82,7 @@ public CompletableFuture> sendMessage(ProxyContext ctx, QueueSe
}
}
}
- AddressableMessageQueue messageQueue = queueSelector.select(ctx,
+ messageQueue = queueSelector.select(ctx,
this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(ctx, topic));
if (messageQueue == null) {
throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no writable queue");
@@ -90,6 +93,7 @@ public CompletableFuture> sendMessage(ProxyContext ctx, QueueSe
}
SendMessageRequestHeader requestHeader = buildSendMessageRequestHeader(messageList, producerGroup, sysFlag, messageQueue.getQueueId());
+ AddressableMessageQueue finalMessageQueue = messageQueue;
future = this.serviceManager.getMessageService().sendMessage(
ctx,
messageQueue,
@@ -102,11 +106,19 @@ public CompletableFuture> sendMessage(ProxyContext ctx, QueueSe
if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) &&
tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE &&
StringUtils.isNotBlank(sendResult.getTransactionId())) {
- fillTransactionData(ctx, producerGroup, messageQueue, sendResult, messageList);
+ fillTransactionData(ctx, producerGroup, finalMessageQueue, sendResult, messageList);
}
}
return sendResultList;
- }, this.executor);
+ }, this.executor)
+ .whenComplete((result, exception) -> {
+ long endTimestamp = System.currentTimeMillis();
+ if (exception != null) {
+ this.serviceManager.getTopicRouteService().updateFaultItem(finalMessageQueue.getBrokerName(), endTimestamp - beginTimestampFirst, true, false);
+ } else {
+ this.serviceManager.getTopicRouteService().updateFaultItem(finalMessageQueue.getBrokerName(),endTimestamp - beginTimestampFirst, false, true);
+ }
+ });
} catch (Throwable t) {
future.completeExceptionally(t);
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/RemotingProtocolServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/RemotingProtocolServer.java
index bcc9edd091c..3227d1e1c63 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/RemotingProtocolServer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/RemotingProtocolServer.java
@@ -22,17 +22,16 @@
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.acl.AccessValidator;
-import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.future.FutureTaskExt;
import org.apache.rocketmq.common.thread.ThreadPoolMonitor;
import org.apache.rocketmq.common.thread.ThreadPoolStatusMonitor;
import org.apache.rocketmq.common.utils.StartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
@@ -51,10 +50,12 @@
import org.apache.rocketmq.proxy.remoting.pipeline.AuthenticationPipeline;
import org.apache.rocketmq.proxy.remoting.pipeline.RequestPipeline;
import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
import org.apache.rocketmq.remoting.RemotingServer;
import org.apache.rocketmq.remoting.netty.NettyRemotingServer;
import org.apache.rocketmq.remoting.netty.NettyServerConfig;
import org.apache.rocketmq.remoting.netty.RequestTask;
+import org.apache.rocketmq.remoting.netty.ResponseFuture;
import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
@@ -178,7 +179,7 @@ public RemotingProtocolServer(MessagingProcessor messagingProcessor, List invokeToClient(Channel channel, Remoti
long timeoutMillis) {
CompletableFuture future = new CompletableFuture<>();
try {
- this.defaultRemotingServer.invokeAsync(channel, request, timeoutMillis, responseFuture -> {
- if (responseFuture.getResponseCommand() == null) {
- future.completeExceptionally(new MQClientException("response is null after send request to client", responseFuture.getCause()));
- return;
+ this.defaultRemotingServer.invokeAsync(channel, request, timeoutMillis, new InvokeCallback() {
+ @Override
+ public void operationComplete(ResponseFuture responseFuture) {
+
+ }
+
+ @Override
+ public void operationSucceed(RemotingCommand response) {
+ future.complete(response);
+ }
+
+ @Override
+ public void operationFail(Throwable throwable) {
+ future.completeExceptionally(throwable);
}
- future.complete(responseFuture.getResponseCommand());
});
} catch (Throwable t) {
future.completeExceptionally(t);
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
index 40946cabf86..d755fdcc493 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
@@ -34,6 +34,7 @@
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.common.channel.ChannelHelper;
+import org.apache.rocketmq.proxy.common.utils.ExceptionUtils;
import org.apache.rocketmq.proxy.common.utils.FutureUtils;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.processor.channel.ChannelExtendAttributeGetter;
@@ -158,10 +159,15 @@ protected CompletableFuture processGetConsumerRunningInfo(RemotingCommand
if (response.getCode() == ResponseCode.SUCCESS) {
ConsumerRunningInfo consumerRunningInfo = ConsumerRunningInfo.decode(response.getBody(), ConsumerRunningInfo.class);
responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, "", consumerRunningInfo));
+ } else {
+ String errMsg = String.format("get consumer running info failed, code:%s remark:%s", response.getCode(), response.getRemark());
+ RuntimeException e = new RuntimeException(errMsg);
+ responseFuture.completeExceptionally(e);
}
- String errMsg = String.format("get consumer running info failed, code:%s remark:%s", response.getCode(), response.getRemark());
- RuntimeException e = new RuntimeException(errMsg);
- responseFuture.completeExceptionally(e);
+ })
+ .exceptionally(t -> {
+ responseFuture.completeExceptionally(ExceptionUtils.getRealException(t));
+ return null;
});
return CompletableFuture.completedFuture(null);
} catch (Throwable t) {
@@ -183,10 +189,15 @@ protected CompletableFuture processConsumeMessageDirectly(RemotingCommand
if (response.getCode() == ResponseCode.SUCCESS) {
ConsumeMessageDirectlyResult result = ConsumeMessageDirectlyResult.decode(response.getBody(), ConsumeMessageDirectlyResult.class);
responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, "", result));
+ } else {
+ String errMsg = String.format("consume message directly failed, code:%s remark:%s", response.getCode(), response.getRemark());
+ RuntimeException e = new RuntimeException(errMsg);
+ responseFuture.completeExceptionally(e);
}
- String errMsg = String.format("consume message directly failed, code:%s remark:%s", response.getCode(), response.getRemark());
- RuntimeException e = new RuntimeException(errMsg);
- responseFuture.completeExceptionally(e);
+ })
+ .exceptionally(t -> {
+ responseFuture.completeExceptionally(ExceptionUtils.getRealException(t));
+ return null;
});
return CompletableFuture.completedFuture(null);
} catch (Throwable t) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java
index d2ddfc3527b..9786cec5577 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java
@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.proxy.service;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
@@ -27,23 +26,24 @@
import org.apache.rocketmq.broker.client.ProducerGroupEvent;
import org.apache.rocketmq.broker.client.ProducerManager;
import org.apache.rocketmq.client.common.NameserverAccessConfig;
+import org.apache.rocketmq.client.impl.mqclient.DoNothingClientRemotingProcessor;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.service.admin.AdminService;
import org.apache.rocketmq.proxy.service.admin.DefaultAdminService;
import org.apache.rocketmq.proxy.service.client.ClusterConsumerManager;
+import org.apache.rocketmq.proxy.service.client.ProxyClientRemotingProcessor;
import org.apache.rocketmq.proxy.service.message.ClusterMessageService;
import org.apache.rocketmq.proxy.service.message.MessageService;
import org.apache.rocketmq.proxy.service.metadata.ClusterMetadataService;
import org.apache.rocketmq.proxy.service.metadata.MetadataService;
-import org.apache.rocketmq.client.impl.mqclient.DoNothingClientRemotingProcessor;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
-import org.apache.rocketmq.proxy.service.client.ProxyClientRemotingProcessor;
import org.apache.rocketmq.proxy.service.relay.ClusterProxyRelayService;
import org.apache.rocketmq.proxy.service.relay.ProxyRelayService;
import org.apache.rocketmq.proxy.service.route.ClusterTopicRouteService;
@@ -73,7 +73,7 @@ public ClusterServiceManager(RPCHook rpcHook) {
ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig();
NameserverAccessConfig nameserverAccessConfig = new NameserverAccessConfig(proxyConfig.getNamesrvAddr(),
proxyConfig.getNamesrvDomain(), proxyConfig.getNamesrvDomainSubgroup());
- this.scheduledExecutorService = Executors.newScheduledThreadPool(3);
+ this.scheduledExecutorService = ThreadUtils.newScheduledThreadPool(3);
this.messagingClientAPIFactory = new MQClientAPIFactory(
nameserverAccessConfig,
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java
index 4d1ca7b6699..59cd92685a3 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java
@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.proxy.service;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.BrokerController;
@@ -28,6 +27,7 @@
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
import org.apache.rocketmq.common.utils.StartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.service.admin.AdminService;
@@ -58,7 +58,7 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser
private final MQClientAPIFactory mqClientAPIFactory;
private final ChannelManager channelManager;
- private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
+ private final ScheduledExecutorService scheduledExecutorService = ThreadUtils.newSingleThreadScheduledExecutor(
new ThreadFactoryImpl("LocalServiceManagerScheduledThread"));
public LocalServiceManager(BrokerController brokerController, RPCHook rpcHook) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java
index 9f163f1b987..70b72deae18 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java
@@ -20,9 +20,11 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
import org.apache.rocketmq.client.consumer.AckResult;
import org.apache.rocketmq.client.consumer.PopResult;
import org.apache.rocketmq.client.consumer.PullResult;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.consumer.ReceiptHandle;
import org.apache.rocketmq.common.message.Message;
@@ -31,7 +33,6 @@
import org.apache.rocketmq.proxy.common.ProxyException;
import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
import org.apache.rocketmq.proxy.common.utils.FutureUtils;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
import org.apache.rocketmq.proxy.service.route.TopicRouteService;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -137,6 +138,19 @@ public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle h
);
}
+ @Override
+ public CompletableFuture batchAckMessage(ProxyContext ctx, List handleList, String consumerGroup,
+ String topic, long timeoutMillis) {
+ List extraInfoList = handleList.stream().map(message -> message.getReceiptHandle().getReceiptHandle()).collect(Collectors.toList());
+ return this.mqClientAPIFactory.getClient().batchAckMessageAsync(
+ this.resolveBrokerAddrInReceiptHandle(ctx, handleList.get(0).getReceiptHandle()),
+ topic,
+ consumerGroup,
+ extraInfoList,
+ timeoutMillis
+ );
+ }
+
@Override
public CompletableFuture pullMessage(ProxyContext ctx, AddressableMessageQueue messageQueue,
PullMessageRequestHeader requestHeader, long timeoutMillis) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java
index eb2c4d9ee91..ca7dcc9eb0c 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java
@@ -19,6 +19,7 @@
import io.netty.channel.ChannelHandlerContext;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -54,6 +55,8 @@
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.body.BatchAck;
+import org.apache.rocketmq.remoting.protocol.body.BatchAckMessageRequestBody;
import org.apache.rocketmq.remoting.protocol.body.LockBatchRequestBody;
import org.apache.rocketmq.remoting.protocol.body.UnlockBatchRequestBody;
import org.apache.rocketmq.remoting.protocol.header.AckMessageRequestHeader;
@@ -364,6 +367,61 @@ public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle h
});
}
+ @Override
+ public CompletableFuture batchAckMessage(ProxyContext ctx, List handleList,
+ String consumerGroup, String topic, long timeoutMillis) {
+ SimpleChannel channel = channelManager.createChannel(ctx);
+ ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext();
+ RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.BATCH_ACK_MESSAGE, null);
+
+ Map batchAckMap = new HashMap<>();
+ for (ReceiptHandleMessage receiptHandleMessage : handleList) {
+ String extraInfo = receiptHandleMessage.getReceiptHandle().getReceiptHandle();
+ String[] extraInfoData = ExtraInfoUtil.split(extraInfo);
+ String mergeKey = ExtraInfoUtil.getRetry(extraInfoData) + "@" +
+ ExtraInfoUtil.getQueueId(extraInfoData) + "@" +
+ ExtraInfoUtil.getCkQueueOffset(extraInfoData) + "@" +
+ ExtraInfoUtil.getPopTime(extraInfoData);
+ BatchAck bAck = batchAckMap.computeIfAbsent(mergeKey, k -> {
+ BatchAck newBatchAck = new BatchAck();
+ newBatchAck.setConsumerGroup(consumerGroup);
+ newBatchAck.setTopic(topic);
+ newBatchAck.setRetry(ExtraInfoUtil.getRetry(extraInfoData));
+ newBatchAck.setStartOffset(ExtraInfoUtil.getCkQueueOffset(extraInfoData));
+ newBatchAck.setQueueId(ExtraInfoUtil.getQueueId(extraInfoData));
+ newBatchAck.setReviveQueueId(ExtraInfoUtil.getReviveQid(extraInfoData));
+ newBatchAck.setPopTime(ExtraInfoUtil.getPopTime(extraInfoData));
+ newBatchAck.setInvisibleTime(ExtraInfoUtil.getInvisibleTime(extraInfoData));
+ newBatchAck.setBitSet(new BitSet());
+ return newBatchAck;
+ });
+ bAck.getBitSet().set((int) (ExtraInfoUtil.getQueueOffset(extraInfoData) - ExtraInfoUtil.getCkQueueOffset(extraInfoData)));
+ }
+ BatchAckMessageRequestBody requestBody = new BatchAckMessageRequestBody();
+ requestBody.setBrokerName(brokerController.getBrokerConfig().getBrokerName());
+ requestBody.setAcks(new ArrayList<>(batchAckMap.values()));
+
+ command.setBody(requestBody.encode());
+ CompletableFuture future = new CompletableFuture<>();
+ try {
+ RemotingCommand response = brokerController.getAckMessageProcessor()
+ .processRequest(channelHandlerContext, command);
+ future.complete(response);
+ } catch (Exception e) {
+ log.error("Fail to process batchAckMessage command", e);
+ future.completeExceptionally(e);
+ }
+ return future.thenApply(r -> {
+ AckResult ackResult = new AckResult();
+ if (ResponseCode.SUCCESS == r.getCode()) {
+ ackResult.setStatus(AckStatus.OK);
+ } else {
+ ackResult.setStatus(AckStatus.NO_EXIST);
+ }
+ return ackResult;
+ });
+ }
+
@Override
public CompletableFuture pullMessage(ProxyContext ctx, AddressableMessageQueue messageQueue,
PullMessageRequestHeader requestHeader, long timeoutMillis) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java
index 15da1715402..58a835adb46 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java
@@ -91,6 +91,14 @@ CompletableFuture ackMessage(
long timeoutMillis
);
+ CompletableFuture batchAckMessage(
+ ProxyContext ctx,
+ List handleList,
+ String consumerGroup,
+ String topic,
+ long timeoutMillis
+ );
+
CompletableFuture pullMessage(
ProxyContext ctx,
AddressableMessageQueue messageQueue,
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/latency/FutureTaskExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ReceiptHandleMessage.java
similarity index 61%
rename from broker/src/main/java/org/apache/rocketmq/broker/latency/FutureTaskExt.java
rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ReceiptHandleMessage.java
index f132efaebcc..ae63fed491e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/latency/FutureTaskExt.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ReceiptHandleMessage.java
@@ -15,25 +15,25 @@
* limitations under the License.
*/
-package org.apache.rocketmq.broker.latency;
+package org.apache.rocketmq.proxy.service.message;
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
+import org.apache.rocketmq.common.consumer.ReceiptHandle;
-public class FutureTaskExt extends FutureTask {
- private final Runnable runnable;
+public class ReceiptHandleMessage {
- public FutureTaskExt(final Callable callable) {
- super(callable);
- this.runnable = null;
+ private final ReceiptHandle receiptHandle;
+ private final String messageId;
+
+ public ReceiptHandleMessage(ReceiptHandle receiptHandle, String messageId) {
+ this.receiptHandle = receiptHandle;
+ this.messageId = messageId;
}
- public FutureTaskExt(final Runnable runnable, final V result) {
- super(runnable, result);
- this.runnable = runnable;
+ public ReceiptHandle getReceiptHandle() {
+ return receiptHandle;
}
- public Runnable getRunnable() {
- return runnable;
+ public String getMessageId() {
+ return messageId;
}
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java
index bc9582ad816..d34a0efd9e1 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java
@@ -69,11 +69,13 @@ public ClusterMetadataService(TopicRouteService topicRouteService, MQClientAPIFa
);
this.topicConfigCache = CacheBuilder.newBuilder()
.maximumSize(config.getTopicConfigCacheMaxNum())
- .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS)
+ .expireAfterAccess(config.getTopicConfigCacheExpiredSeconds(), TimeUnit.SECONDS)
+ .refreshAfterWrite(config.getTopicConfigCacheRefreshSeconds(), TimeUnit.SECONDS)
.build(new ClusterTopicConfigCacheLoader());
this.subscriptionGroupConfigCache = CacheBuilder.newBuilder()
.maximumSize(config.getSubscriptionGroupConfigCacheMaxNum())
- .refreshAfterWrite(config.getSubscriptionGroupConfigCacheExpiredInSeconds(), TimeUnit.SECONDS)
+ .expireAfterAccess(config.getSubscriptionGroupConfigCacheExpiredSeconds(), TimeUnit.SECONDS)
+ .refreshAfterWrite(config.getSubscriptionGroupConfigCacheRefreshSeconds(), TimeUnit.SECONDS)
.build(new ClusterSubscriptionGroupConfigCacheLoader());
this.init();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/receipt/DefaultReceiptHandleManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/receipt/DefaultReceiptHandleManager.java
index 69f44344a03..207603fe811 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/receipt/DefaultReceiptHandleManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/receipt/DefaultReceiptHandleManager.java
@@ -24,7 +24,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -42,20 +41,21 @@
import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
import org.apache.rocketmq.common.utils.ConcurrentHashMapUtils;
import org.apache.rocketmq.common.utils.StartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.proxy.common.RenewEvent;
import org.apache.rocketmq.proxy.common.MessageReceiptHandle;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.common.ProxyException;
import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
import org.apache.rocketmq.proxy.common.ReceiptHandleGroup;
+import org.apache.rocketmq.proxy.common.ReceiptHandleGroupKey;
+import org.apache.rocketmq.proxy.common.RenewEvent;
import org.apache.rocketmq.proxy.common.RenewStrategyPolicy;
import org.apache.rocketmq.proxy.common.channel.ChannelHelper;
import org.apache.rocketmq.proxy.common.utils.ExceptionUtils;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
-import org.apache.rocketmq.proxy.common.ReceiptHandleGroupKey;
import org.apache.rocketmq.proxy.service.metadata.MetadataService;
import org.apache.rocketmq.remoting.protocol.subscription.RetryPolicy;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
@@ -68,7 +68,7 @@ public class DefaultReceiptHandleManager extends AbstractStartAndShutdown implem
protected final StateEventListener eventListener;
protected final static RetryPolicy RENEW_POLICY = new RenewStrategyPolicy();
protected final ScheduledExecutorService scheduledExecutorService =
- Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("RenewalScheduledThread_"));
+ ThreadUtils.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("RenewalScheduledThread_"));
protected final ThreadPoolExecutor renewalWorkerService;
public DefaultReceiptHandleManager(MetadataService metadataService, ConsumerManager consumerManager, StateEventListener eventListener) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java
index d67b68f38e9..aced15cee51 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java
@@ -54,7 +54,7 @@ public LocalTopicRouteService(BrokerController brokerController, MQClientAPIFact
@Override
public MessageQueueView getCurrentMessageQueueView(ProxyContext ctx, String topic) throws Exception {
TopicConfig topicConfig = this.brokerController.getTopicConfigManager().getTopicConfigTable().get(topic);
- return new MessageQueueView(topic, toTopicRouteData(topicConfig));
+ return new MessageQueueView(topic, toTopicRouteData(topicConfig), null);
}
@Override
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java
index 85cd18d45c9..f25fb907ef2 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.proxy.service.route;
import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
import com.google.common.math.IntMath;
import java.util.ArrayList;
import java.util.Collections;
@@ -30,6 +31,8 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.client.impl.producer.TopicPublishInfo;
+import org.apache.rocketmq.client.latency.MQFaultStrategy;
import org.apache.rocketmq.common.constant.PermName;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.protocol.route.QueueData;
@@ -44,8 +47,9 @@ public class MessageQueueSelector {
private final Map brokerNameQueueMap = new ConcurrentHashMap<>();
private final AtomicInteger queueIndex;
private final AtomicInteger brokerIndex;
+ private MQFaultStrategy mqFaultStrategy;
- public MessageQueueSelector(TopicRouteWrapper topicRouteWrapper, boolean read) {
+ public MessageQueueSelector(TopicRouteWrapper topicRouteWrapper, MQFaultStrategy mqFaultStrategy, boolean read) {
if (read) {
this.queues.addAll(buildRead(topicRouteWrapper));
} else {
@@ -55,6 +59,7 @@ public MessageQueueSelector(TopicRouteWrapper topicRouteWrapper, boolean read) {
Random random = new Random();
this.queueIndex = new AtomicInteger(random.nextInt());
this.brokerIndex = new AtomicInteger(random.nextInt());
+ this.mqFaultStrategy = mqFaultStrategy;
}
private static List buildRead(TopicRouteWrapper topicRoute) {
@@ -154,6 +159,86 @@ public AddressableMessageQueue selectOne(boolean onlyBroker) {
return selectOneByIndex(nextIndex, onlyBroker);
}
+ public AddressableMessageQueue selectOneByPipeline(boolean onlyBroker) {
+ if (mqFaultStrategy != null && mqFaultStrategy.isSendLatencyFaultEnable()) {
+ List messageQueueList = null;
+ MessageQueue messageQueue = null;
+ if (onlyBroker) {
+ messageQueueList = transferAddressableQueues(brokerActingQueues);
+ } else {
+ messageQueueList = transferAddressableQueues(queues);
+ }
+ AddressableMessageQueue addressableMessageQueue = null;
+
+ // use both available filter.
+ messageQueue = selectOneMessageQueue(messageQueueList, onlyBroker ? brokerIndex : queueIndex,
+ mqFaultStrategy.getAvailableFilter(), mqFaultStrategy.getReachableFilter());
+ addressableMessageQueue = transferQueue2Addressable(messageQueue);
+ if (addressableMessageQueue != null) {
+ return addressableMessageQueue;
+ }
+
+ // use available filter.
+ messageQueue = selectOneMessageQueue(messageQueueList, onlyBroker ? brokerIndex : queueIndex,
+ mqFaultStrategy.getAvailableFilter());
+ addressableMessageQueue = transferQueue2Addressable(messageQueue);
+ if (addressableMessageQueue != null) {
+ return addressableMessageQueue;
+ }
+
+ // no available filter, then use reachable filter.
+ messageQueue = selectOneMessageQueue(messageQueueList, onlyBroker ? brokerIndex : queueIndex,
+ mqFaultStrategy.getReachableFilter());
+ addressableMessageQueue = transferQueue2Addressable(messageQueue);
+ if (addressableMessageQueue != null) {
+ return addressableMessageQueue;
+ }
+ }
+
+ // SendLatency is not enabled, or no queue is selected, then select by index.
+ return selectOne(onlyBroker);
+ }
+
+ private MessageQueue selectOneMessageQueue(List messageQueueList, AtomicInteger sendQueue, TopicPublishInfo.QueueFilter...filter) {
+ if (messageQueueList == null || messageQueueList.isEmpty()) {
+ return null;
+ }
+ if (filter != null && filter.length != 0) {
+ for (int i = 0; i < messageQueueList.size(); i++) {
+ int index = Math.abs(sendQueue.incrementAndGet() % messageQueueList.size());
+ MessageQueue mq = messageQueueList.get(index);
+ boolean filterResult = true;
+ for (TopicPublishInfo.QueueFilter f: filter) {
+ Preconditions.checkNotNull(f);
+ filterResult &= f.filter(mq);
+ }
+ if (filterResult) {
+ return mq;
+ }
+ }
+ }
+ return null;
+ }
+
+ public List transferAddressableQueues(List addressableMessageQueueList) {
+ if (addressableMessageQueueList == null) {
+ return null;
+ }
+
+ return addressableMessageQueueList.stream()
+ .map(AddressableMessageQueue::getMessageQueue)
+ .collect(Collectors.toList());
+ }
+
+ private AddressableMessageQueue transferQueue2Addressable(MessageQueue messageQueue) {
+ for (AddressableMessageQueue amq: queues) {
+ if (amq.getMessageQueue().equals(messageQueue)) {
+ return amq;
+ }
+ }
+ return null;
+ }
+
public AddressableMessageQueue selectNextOne(AddressableMessageQueue last) {
boolean onlyBroker = last.getQueueId() < 0;
AddressableMessageQueue newOne = last;
@@ -190,6 +275,14 @@ public List getBrokerActingQueues() {
return brokerActingQueues;
}
+ public MQFaultStrategy getMQFaultStrategy() {
+ return mqFaultStrategy;
+ }
+
+ public void setMQFaultStrategy(MQFaultStrategy mqFaultStrategy) {
+ this.mqFaultStrategy = mqFaultStrategy;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java
index fe5387cfd7e..898e529f8cb 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java
@@ -17,20 +17,21 @@
package org.apache.rocketmq.proxy.service.route;
import com.google.common.base.MoreObjects;
+import org.apache.rocketmq.client.latency.MQFaultStrategy;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
public class MessageQueueView {
- public static final MessageQueueView WRAPPED_EMPTY_QUEUE = new MessageQueueView("", new TopicRouteData());
+ public static final MessageQueueView WRAPPED_EMPTY_QUEUE = new MessageQueueView("", new TopicRouteData(), null);
private final MessageQueueSelector readSelector;
private final MessageQueueSelector writeSelector;
private final TopicRouteWrapper topicRouteWrapper;
- public MessageQueueView(String topic, TopicRouteData topicRouteData) {
+ public MessageQueueView(String topic, TopicRouteData topicRouteData, MQFaultStrategy mqFaultStrategy) {
this.topicRouteWrapper = new TopicRouteWrapper(topicRouteData, topic);
- this.readSelector = new MessageQueueSelector(topicRouteWrapper, true);
- this.writeSelector = new MessageQueueSelector(topicRouteWrapper, false);
+ this.readSelector = new MessageQueueSelector(topicRouteWrapper, mqFaultStrategy, true);
+ this.writeSelector = new MessageQueueSelector(topicRouteWrapper, mqFaultStrategy, false);
}
public TopicRouteData getTopicRouteData() {
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java
index e012a5465a4..ccf094c03aa 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java
@@ -19,19 +19,24 @@
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
+import com.google.common.base.Optional;
import java.time.Duration;
import java.util.List;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
+import org.apache.rocketmq.client.latency.MQFaultStrategy;
+import org.apache.rocketmq.client.latency.Resolver;
+import org.apache.rocketmq.client.latency.ServiceDetector;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.thread.ThreadPoolMonitor;
import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
+import org.apache.rocketmq.common.utils.ThreadUtils;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.common.Address;
@@ -39,6 +44,7 @@
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.GetMaxOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -47,6 +53,7 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
private final MQClientAPIFactory mqClientAPIFactory;
+ private MQFaultStrategy mqFaultStrategy;
protected final LoadingCache topicCache;
protected final ScheduledExecutorService scheduledExecutorService;
@@ -55,7 +62,7 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown {
public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) {
ProxyConfig config = ConfigurationManager.getProxyConfig();
- this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
+ this.scheduledExecutorService = ThreadUtils.newSingleThreadScheduledExecutor(
new ThreadFactoryImpl("TopicRouteService_")
);
this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor(
@@ -68,10 +75,13 @@ public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) {
);
this.mqClientAPIFactory = mqClientAPIFactory;
- this.topicCache = Caffeine.newBuilder().maximumSize(config.getTopicRouteServiceCacheMaxNum()).
- refreshAfterWrite(config.getTopicRouteServiceCacheExpiredInSeconds(), TimeUnit.SECONDS).
- executor(cacheRefreshExecutor).build(new CacheLoader() {
- @Override public @Nullable MessageQueueView load(String topic) throws Exception {
+ this.topicCache = Caffeine.newBuilder().maximumSize(config.getTopicRouteServiceCacheMaxNum())
+ .expireAfterAccess(config.getTopicRouteServiceCacheExpiredSeconds(), TimeUnit.SECONDS)
+ .refreshAfterWrite(config.getTopicRouteServiceCacheRefreshSeconds(), TimeUnit.SECONDS)
+ .executor(cacheRefreshExecutor)
+ .build(new CacheLoader() {
+ @Override
+ public @Nullable MessageQueueView load(String topic) throws Exception {
try {
TopicRouteData topicRouteData = mqClientAPIFactory.getClient().getTopicRouteInfoFromNameServer(topic, Duration.ofSeconds(3).toMillis());
return buildMessageQueueView(topic, topicRouteData);
@@ -83,7 +93,8 @@ public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) {
}
}
- @Override public @Nullable MessageQueueView reload(@NonNull String key,
+ @Override
+ public @Nullable MessageQueueView reload(@NonNull String key,
@NonNull MessageQueueView oldValue) throws Exception {
try {
return load(key);
@@ -93,15 +104,91 @@ public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) {
}
}
});
-
+ ServiceDetector serviceDetector = new ServiceDetector() {
+ @Override
+ public boolean detect(String endpoint, long timeoutMillis) {
+ Optional candidateTopic = pickTopic();
+ if (!candidateTopic.isPresent()) {
+ return false;
+ }
+ try {
+ GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader();
+ requestHeader.setTopic(candidateTopic.get());
+ requestHeader.setQueueId(0);
+ Long maxOffset = mqClientAPIFactory.getClient().getMaxOffset(endpoint, requestHeader, timeoutMillis).get();
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ };
+ mqFaultStrategy = new MQFaultStrategy(extractClientConfigFromProxyConfig(config), new Resolver() {
+ @Override
+ public String resolve(String name) {
+ try {
+ String brokerAddr = getBrokerAddr(ProxyContext.createForInner("MQFaultStrategy"), name);
+ return brokerAddr;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }, serviceDetector);
this.init();
}
+ // pickup one topic in the topic cache
+ private Optional pickTopic() {
+ if (topicCache.asMap().isEmpty()) {
+ return Optional.absent();
+ }
+ return Optional.of(topicCache.asMap().keySet().iterator().next());
+ }
+
protected void init() {
this.appendShutdown(this.scheduledExecutorService::shutdown);
this.appendStartAndShutdown(this.mqClientAPIFactory);
}
+ @Override
+ public void shutdown() throws Exception {
+ if (this.mqFaultStrategy.isStartDetectorEnable()) {
+ mqFaultStrategy.shutdown();
+ }
+ }
+
+ @Override
+ public void start() throws Exception {
+ if (this.mqFaultStrategy.isStartDetectorEnable()) {
+ this.mqFaultStrategy.startDetector();
+ }
+ }
+
+ public ClientConfig extractClientConfigFromProxyConfig(ProxyConfig proxyConfig) {
+ ClientConfig tempClientConfig = new ClientConfig();
+ tempClientConfig.setSendLatencyEnable(proxyConfig.getSendLatencyEnable());
+ tempClientConfig.setStartDetectorEnable(proxyConfig.getStartDetectorEnable());
+ tempClientConfig.setDetectTimeout(proxyConfig.getDetectTimeout());
+ tempClientConfig.setDetectInterval(proxyConfig.getDetectInterval());
+ return tempClientConfig;
+ }
+
+ public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation,
+ boolean reachable) {
+ checkSendFaultToleranceEnable();
+ this.mqFaultStrategy.updateFaultItem(brokerName, currentLatency, isolation, reachable);
+ }
+
+ public void checkSendFaultToleranceEnable() {
+ boolean hotLatencySwitch = ConfigurationManager.getProxyConfig().isSendLatencyEnable();
+ boolean hotDetectorSwitch = ConfigurationManager.getProxyConfig().isStartDetectorEnable();
+ this.mqFaultStrategy.setSendLatencyFaultEnable(hotLatencySwitch);
+ this.mqFaultStrategy.setStartDetectorEnable(hotDetectorSwitch);
+ }
+
+ public MQFaultStrategy getMqFaultStrategy() {
+ return this.mqFaultStrategy;
+ }
+
public MessageQueueView getAllMessageQueueView(ProxyContext ctx, String topicName) throws Exception {
return getCacheMessageQueueWrapper(this.topicCache, topicName);
}
@@ -132,7 +219,7 @@ protected static boolean isTopicRouteValid(TopicRouteData routeData) {
protected MessageQueueView buildMessageQueueView(String topic, TopicRouteData topicRouteData) {
if (isTopicRouteValid(topicRouteData)) {
- MessageQueueView tmp = new MessageQueueView(topic, topicRouteData);
+ MessageQueueView tmp = new MessageQueueView(topic, topicRouteData, TopicRouteService.this.getMqFaultStrategy());
log.debug("load topic route from namesrv. topic: {}, queue: {}", topic, tmp);
return tmp;
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
index f70c06b8f46..fee3ea87d27 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
@@ -18,6 +18,7 @@
package org.apache.rocketmq.proxy.service.sysmessage;
import com.alibaba.fastjson.JSON;
+import io.netty.channel.Channel;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
@@ -73,16 +74,8 @@ protected void init() {
);
this.consumerManager.appendConsumerIdsChangeListener(new ConsumerIdsChangeListener() {
@Override
- public void handle(ConsumerGroupEvent event, String s, Object... args) {
- if (event == ConsumerGroupEvent.CLIENT_UNREGISTER) {
- if (args == null || args.length < 1) {
- return;
- }
- if (args[0] instanceof ClientChannelInfo) {
- ClientChannelInfo clientChannelInfo = (ClientChannelInfo) args[0];
- remoteChannelMap.remove(clientChannelInfo.getChannel().id().asLongText());
- }
- }
+ public void handle(ConsumerGroupEvent event, String group, Object... args) {
+ processConsumerGroupEvent(event, group, args);
}
@Override
@@ -98,6 +91,18 @@ public void shutdown() throws Exception {
super.shutdown();
}
+ protected void processConsumerGroupEvent(ConsumerGroupEvent event, String group, Object... args) {
+ if (event == ConsumerGroupEvent.CLIENT_UNREGISTER) {
+ if (args == null || args.length < 1) {
+ return;
+ }
+ if (args[0] instanceof ClientChannelInfo) {
+ ClientChannelInfo clientChannelInfo = (ClientChannelInfo) args[0];
+ remoteChannelMap.remove(buildKey(group, clientChannelInfo.getChannel()));
+ }
+ }
+ }
+
public void onConsumerRegister(String consumerGroup, ClientChannelInfo clientChannelInfo,
ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere,
Set subList) {
@@ -189,7 +194,7 @@ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeCo
}
RemoteChannel decodedChannel = RemoteChannel.decode(data.getChannelData());
- RemoteChannel channel = remoteChannelMap.computeIfAbsent(data.getGroup() + "@" + decodedChannel.id().asLongText(), key -> decodedChannel);
+ RemoteChannel channel = remoteChannelMap.computeIfAbsent(buildKey(data.getGroup(), decodedChannel), key -> decodedChannel);
channel.setExtendAttribute(decodedChannel.getChannelExtendAttribute());
ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
channel,
@@ -228,4 +233,8 @@ private String buildLocalProxyId() {
// use local address, remoting port and grpc port to build unique local proxy Id
return proxyConfig.getLocalServeAddr() + "%" + proxyConfig.getRemotingListenPort() + "%" + proxyConfig.getGrpcServerPort();
}
+
+ private static String buildKey(String group, Channel channel) {
+ return group + "@" + channel.id().asLongText();
+ }
}
diff --git a/proxy/src/main/resources/rmq.proxy.logback.xml b/proxy/src/main/resources/rmq.proxy.logback.xml
index d38827f92d8..f968a45e631 100644
--- a/proxy/src/main/resources/rmq.proxy.logback.xml
+++ b/proxy/src/main/resources/rmq.proxy.logback.xml
@@ -418,6 +418,11 @@
+
+
+
+
+
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java
index 49fdfc6a8bf..3c474610518 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java
@@ -20,21 +20,32 @@
import apache.rocketmq.v2.AckMessageEntry;
import apache.rocketmq.v2.AckMessageRequest;
import apache.rocketmq.v2.AckMessageResponse;
+import apache.rocketmq.v2.AckMessageResultEntry;
import apache.rocketmq.v2.Code;
import apache.rocketmq.v2.Resource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.apache.rocketmq.client.consumer.AckResult;
import org.apache.rocketmq.client.consumer.AckStatus;
import org.apache.rocketmq.proxy.common.ProxyException;
import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
+import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest;
+import org.apache.rocketmq.proxy.processor.BatchAckResult;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.stubbing.Answer;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
public class AckMessageActivityTest extends BaseActivityTest {
@@ -52,43 +63,197 @@ public void before() throws Throwable {
@Test
public void testAckMessage() throws Throwable {
- when(this.messagingProcessor.ackMessage(any(), any(), eq("msg1"), anyString(), anyString()))
+ ConfigurationManager.getProxyConfig().setEnableBatchAck(false);
+
+ String msg1 = "msg1";
+ String msg2 = "msg2";
+ String msg3 = "msg3";
+
+ when(this.messagingProcessor.ackMessage(any(), any(), eq(msg1), anyString(), anyString()))
.thenThrow(new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "receipt handle is expired"));
AckResult msg2AckResult = new AckResult();
msg2AckResult.setStatus(AckStatus.OK);
- when(this.messagingProcessor.ackMessage(any(), any(), eq("msg2"), anyString(), anyString()))
+ when(this.messagingProcessor.ackMessage(any(), any(), eq(msg2), anyString(), anyString()))
.thenReturn(CompletableFuture.completedFuture(msg2AckResult));
AckResult msg3AckResult = new AckResult();
msg3AckResult.setStatus(AckStatus.NO_EXIST);
- when(this.messagingProcessor.ackMessage(any(), any(), eq("msg3"), anyString(), anyString()))
+ when(this.messagingProcessor.ackMessage(any(), any(), eq(msg3), anyString(), anyString()))
.thenReturn(CompletableFuture.completedFuture(msg3AckResult));
- AckMessageResponse response = this.ackMessageActivity.ackMessage(
- createContext(),
- AckMessageRequest.newBuilder()
- .setTopic(Resource.newBuilder().setName(TOPIC).build())
- .setGroup(Resource.newBuilder().setName(GROUP).build())
- .addEntries(AckMessageEntry.newBuilder()
- .setMessageId("msg1")
- .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis() - 10000, 1000))
- .build())
- .addEntries(AckMessageEntry.newBuilder()
- .setMessageId("msg2")
- .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
- .build())
- .addEntries(AckMessageEntry.newBuilder()
- .setMessageId("msg3")
- .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
- .build())
- .build()
- ).get();
-
- assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode());
- assertEquals(3, response.getEntriesCount());
- assertEquals(Code.INVALID_RECEIPT_HANDLE, response.getEntries(0).getStatus().getCode());
- assertEquals(Code.OK, response.getEntries(1).getStatus().getCode());
- assertEquals(Code.INTERNAL_SERVER_ERROR, response.getEntries(2).getStatus().getCode());
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg1)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis() - 10000, 1000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.INVALID_RECEIPT_HANDLE, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg2)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis() - 10000, 1000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.OK, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg3)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis() - 10000, 1000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.INTERNAL_SERVER_ERROR, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg1)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis() - 10000, 1000))
+ .build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg2)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(msg3)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .build()
+ ).get();
+
+ assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode());
+ assertEquals(3, response.getEntriesCount());
+ assertEquals(Code.INVALID_RECEIPT_HANDLE, response.getEntries(0).getStatus().getCode());
+ assertEquals(Code.OK, response.getEntries(1).getStatus().getCode());
+ assertEquals(Code.INTERNAL_SERVER_ERROR, response.getEntries(2).getStatus().getCode());
+ }
+ }
+
+ @Test
+ public void testAckMessageInBatch() throws Throwable {
+ ConfigurationManager.getProxyConfig().setEnableBatchAck(true);
+
+ String successMessageId = "msg1";
+ String notOkMessageId = "msg2";
+ String exceptionMessageId = "msg3";
+
+ doAnswer((Answer>>) invocation -> {
+ List receiptHandleMessageList = invocation.getArgument(1, List.class);
+ List batchAckResultList = new ArrayList<>();
+ for (ReceiptHandleMessage receiptHandleMessage : receiptHandleMessageList) {
+ BatchAckResult batchAckResult;
+ if (receiptHandleMessage.getMessageId().equals(successMessageId)) {
+ AckResult ackResult = new AckResult();
+ ackResult.setStatus(AckStatus.OK);
+ batchAckResult = new BatchAckResult(receiptHandleMessage, ackResult);
+ } else if (receiptHandleMessage.getMessageId().equals(notOkMessageId)) {
+ AckResult ackResult = new AckResult();
+ ackResult.setStatus(AckStatus.NO_EXIST);
+ batchAckResult = new BatchAckResult(receiptHandleMessage, ackResult);
+ } else {
+ batchAckResult = new BatchAckResult(receiptHandleMessage, new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, ""));
+ }
+ batchAckResultList.add(batchAckResult);
+ }
+ return CompletableFuture.completedFuture(batchAckResultList);
+ }).when(this.messagingProcessor).batchAckMessage(any(), anyList(), anyString(), anyString());
+
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(successMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.OK, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(notOkMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.INTERNAL_SERVER_ERROR, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(exceptionMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .build()
+ ).get();
+ assertEquals(Code.INVALID_RECEIPT_HANDLE, response.getStatus().getCode());
+ }
+ {
+ AckMessageResponse response = this.ackMessageActivity.ackMessage(
+ createContext(),
+ AckMessageRequest.newBuilder()
+ .setTopic(Resource.newBuilder().setName(TOPIC).build())
+ .setGroup(Resource.newBuilder().setName(GROUP).build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(successMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(notOkMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .addEntries(AckMessageEntry.newBuilder()
+ .setMessageId(exceptionMessageId)
+ .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000))
+ .build())
+ .build()
+ ).get();
+
+ assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode());
+ assertEquals(3, response.getEntriesCount());
+ Map msgCode = new HashMap<>();
+ for (AckMessageResultEntry entry : response.getEntriesList()) {
+ msgCode.put(entry.getMessageId(), entry.getStatus().getCode());
+ }
+ assertEquals(Code.OK, msgCode.get(successMessageId));
+ assertEquals(Code.INTERNAL_SERVER_ERROR, msgCode.get(notOkMessageId));
+ assertEquals(Code.INVALID_RECEIPT_HANDLE, msgCode.get(exceptionMessageId));
+ }
}
}
\ No newline at end of file
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java
index 7fd9a9ffdf0..77ae5e4d111 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java
@@ -93,7 +93,6 @@ public void testReceiveMessagePollingTime() {
pollTimeCaptor.capture(), anyInt(), any(), anyBoolean(), any(), isNull(), anyLong()))
.thenReturn(CompletableFuture.completedFuture(new PopResult(PopStatus.NO_NEW_MSG, Collections.emptyList())));
-
ProxyContext context = createContext();
context.setRemainingMs(1L);
this.receiveMessageActivity.receiveMessage(
@@ -274,7 +273,7 @@ private Code getResponseCodeFromReceiveMessageResponseList(List queueDatas = new ArrayList<>();
for (int i = 0; i < 2; i++) {
@@ -298,7 +297,7 @@ public void testReceiveMessageQueueSelector() {
}
topicRouteData.setBrokerDatas(brokerDatas);
- MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData);
+ MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData, null);
ReceiveMessageActivity.ReceiveMessageQueueSelector selector = new ReceiveMessageActivity.ReceiveMessageQueueSelector("");
AddressableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView);
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java
index 588423bb93f..4882a5ed8b7 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java
@@ -35,6 +35,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.client.ClientConfig;
+import org.apache.rocketmq.client.latency.MQFaultStrategy;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.MixAll;
@@ -49,6 +51,7 @@
import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException;
import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
import org.apache.rocketmq.proxy.service.route.MessageQueueView;
+import org.apache.rocketmq.proxy.service.route.TopicRouteService;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.remoting.protocol.route.QueueData;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
@@ -62,15 +65,19 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class SendMessageActivityTest extends BaseActivityTest {
protected static final String BROKER_NAME = "broker";
+ protected static final String BROKER_NAME2 = "broker2";
protected static final String CLUSTER_NAME = "cluster";
protected static final String BROKER_ADDR = "127.0.0.1:10911";
+ protected static final String BROKER_ADDR2 = "127.0.0.1:10912";
private static final String TOPIC = "topic";
private static final String CONSUMER_GROUP = "consumerGroup";
+ MQFaultStrategy mqFaultStrategy;
private SendMessageActivity sendMessageActivity;
@@ -262,7 +269,7 @@ public void testTxMessage() {
}
@Test
- public void testSendOrderMessageQueueSelector() {
+ public void testSendOrderMessageQueueSelector() throws Exception {
TopicRouteData topicRouteData = new TopicRouteData();
QueueData queueData = new QueueData();
BrokerData brokerData = new BrokerData();
@@ -277,7 +284,7 @@ public void testSendOrderMessageQueueSelector() {
brokerData.setBrokerAddrs(brokerAddrs);
topicRouteData.setBrokerDatas(Lists.newArrayList(brokerData));
- MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData);
+ MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData, null);
SendMessageActivity.SendMessageQueueSelector selector1 = new SendMessageActivity.SendMessageQueueSelector(
SendMessageRequest.newBuilder()
.addMessages(Message.newBuilder()
@@ -288,6 +295,12 @@ public void testSendOrderMessageQueueSelector() {
.build()
);
+ TopicRouteService topicRouteService = mock(TopicRouteService.class);
+ MQFaultStrategy mqFaultStrategy = mock(MQFaultStrategy.class);
+ when(topicRouteService.getAllMessageQueueView(any(), any())).thenReturn(messageQueueView);
+ when(topicRouteService.getMqFaultStrategy()).thenReturn(mqFaultStrategy);
+ when(mqFaultStrategy.isSendLatencyFaultEnable()).thenReturn(false);
+
SendMessageActivity.SendMessageQueueSelector selector2 = new SendMessageActivity.SendMessageQueueSelector(
SendMessageRequest.newBuilder()
.addMessages(Message.newBuilder()
@@ -328,12 +341,17 @@ public void testSendNormalMessageQueueSelector() {
brokerData.setBrokerAddrs(brokerAddrs);
topicRouteData.setBrokerDatas(Lists.newArrayList(brokerData));
- MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData);
+
SendMessageActivity.SendMessageQueueSelector selector = new SendMessageActivity.SendMessageQueueSelector(
SendMessageRequest.newBuilder()
.addMessages(Message.newBuilder().build())
.build()
);
+ TopicRouteService topicRouteService = mock(TopicRouteService.class);
+ MQFaultStrategy mqFaultStrategy = mock(MQFaultStrategy.class);
+ when(topicRouteService.getMqFaultStrategy()).thenReturn(mqFaultStrategy);
+ when(mqFaultStrategy.isSendLatencyFaultEnable()).thenReturn(false);
+ MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData, topicRouteService.getMqFaultStrategy());
AddressableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView);
AddressableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView);
@@ -343,6 +361,45 @@ public void testSendNormalMessageQueueSelector() {
assertNotEquals(firstSelect, secondSelect);
}
+ @Test
+ public void testSendNormalMessageQueueSelectorPipeLine() throws Exception {
+ TopicRouteData topicRouteData = new TopicRouteData();
+ int queueNums = 2;
+
+ QueueData queueData = createQueueData(BROKER_NAME, queueNums);
+ QueueData queueData2 = createQueueData(BROKER_NAME2, queueNums);
+ topicRouteData.setQueueDatas(Lists.newArrayList(queueData,queueData2));
+
+
+ BrokerData brokerData = createBrokerData(CLUSTER_NAME, BROKER_NAME, BROKER_ADDR);
+ BrokerData brokerData2 = createBrokerData(CLUSTER_NAME, BROKER_NAME2, BROKER_ADDR2);
+ topicRouteData.setBrokerDatas(Lists.newArrayList(brokerData, brokerData2));
+
+ SendMessageActivity.SendMessageQueueSelector selector = new SendMessageActivity.SendMessageQueueSelector(
+ SendMessageRequest.newBuilder()
+ .addMessages(Message.newBuilder().build())
+ .build()
+ );
+
+ ClientConfig cc = new ClientConfig();
+ this.mqFaultStrategy = new MQFaultStrategy(cc, null, null);
+ mqFaultStrategy.setSendLatencyFaultEnable(true);
+ mqFaultStrategy.updateFaultItem(BROKER_NAME2, 1000, true, true);
+ mqFaultStrategy.updateFaultItem(BROKER_NAME, 1000, true, false);
+
+ TopicRouteService topicRouteService = mock(TopicRouteService.class);
+ when(topicRouteService.getMqFaultStrategy()).thenReturn(mqFaultStrategy);
+ MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData, topicRouteService.getMqFaultStrategy());
+
+
+ AddressableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView);
+ assertEquals(firstSelect.getBrokerName(), BROKER_NAME2);
+
+ mqFaultStrategy.updateFaultItem(BROKER_NAME2, 1000, true, false);
+ mqFaultStrategy.updateFaultItem(BROKER_NAME, 1000, true, true);
+ AddressableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView);
+ assertEquals(secondSelect.getBrokerName(), BROKER_NAME);
+ }
@Test
public void testParameterValidate() {
// too large message body
@@ -850,4 +907,23 @@ private static String createStr(int len) {
}
return sb.toString();
}
+
+ private static QueueData createQueueData(String brokerName, int writeQueueNums) {
+ QueueData queueData = new QueueData();
+ queueData.setBrokerName(brokerName);
+ queueData.setWriteQueueNums(writeQueueNums);
+ queueData.setPerm(PermName.PERM_WRITE);
+ return queueData;
+ }
+
+ private static BrokerData createBrokerData(String clusterName, String brokerName, String brokerAddrs) {
+ BrokerData brokerData = new BrokerData();
+ brokerData.setCluster(clusterName);
+ brokerData.setBrokerName(brokerName);
+ HashMap brokerAddrsMap = new HashMap<>();
+ brokerAddrsMap.put(MixAll.MASTER_ID, brokerAddrs);
+ brokerData.setBrokerAddrs(brokerAddrsMap);
+
+ return brokerData;
+ }
}
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java
index 5c1ea9627e6..072630e3947 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java
@@ -66,14 +66,6 @@ public class BaseProcessorTest extends InitConfigTest {
protected ProxyRelayService proxyRelayService;
@Mock
protected MetadataService metadataService;
- @Mock
- protected ProducerProcessor producerProcessor;
- @Mock
- protected ConsumerProcessor consumerProcessor;
- @Mock
- protected TransactionProcessor transactionProcessor;
- @Mock
- protected ClientProcessor clientProcessor;
public void before() throws Throwable {
super.before();
@@ -92,6 +84,13 @@ protected static ProxyContext createContext() {
}
protected static MessageExt createMessageExt(String topic, String tags, int reconsumeTimes, long invisibleTime) {
+ return createMessageExt(topic, tags, reconsumeTimes, invisibleTime, System.currentTimeMillis(),
+ RANDOM.nextInt(Integer.MAX_VALUE), RANDOM.nextInt(Integer.MAX_VALUE), RANDOM.nextInt(Integer.MAX_VALUE),
+ RANDOM.nextInt(Integer.MAX_VALUE), "mockBroker");
+ }
+
+ protected static MessageExt createMessageExt(String topic, String tags, int reconsumeTimes, long invisibleTime, long popTime,
+ long startOffset, int reviveQid, int queueId, long queueOffset, String brokerName) {
MessageExt messageExt = new MessageExt();
messageExt.setTopic(topic);
messageExt.setTags(tags);
@@ -100,8 +99,7 @@ protected static MessageExt createMessageExt(String topic, String tags, int reco
messageExt.setMsgId(MessageClientIDSetter.createUniqID());
messageExt.setCommitLogOffset(RANDOM.nextInt(Integer.MAX_VALUE));
MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_POP_CK,
- ExtraInfoUtil.buildExtraInfo(RANDOM.nextInt(Integer.MAX_VALUE), System.currentTimeMillis(), invisibleTime,
- RANDOM.nextInt(Integer.MAX_VALUE), topic, "mockBroker", RANDOM.nextInt(Integer.MAX_VALUE), RANDOM.nextInt(Integer.MAX_VALUE)));
+ ExtraInfoUtil.buildExtraInfo(startOffset, popTime, invisibleTime, reviveQid, topic, brokerName, queueId, queueOffset));
return messageExt;
}
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java
index 717e86fc056..db268a06e6a 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java
@@ -20,8 +20,11 @@
import com.google.common.collect.Sets;
import java.time.Duration;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
@@ -39,7 +42,10 @@
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.proxy.common.ProxyContext;
+import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
+import org.apache.rocketmq.proxy.common.utils.FutureUtils;
import org.apache.rocketmq.proxy.common.utils.ProxyUtils;
+import org.apache.rocketmq.proxy.service.message.ReceiptHandleMessage;
import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
import org.apache.rocketmq.proxy.service.route.MessageQueueView;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -50,16 +56,22 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.stubbing.Answer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ConsumerProcessorTest extends BaseProcessorTest {
@@ -162,6 +174,109 @@ public void testAckMessage() throws Throwable {
assertEquals(handle.getReceiptHandle(), requestHeaderArgumentCaptor.getValue().getExtraInfo());
}
+ @Test
+ public void testBatchAckExpireMessage() throws Throwable {
+ String brokerName1 = "brokerName1";
+
+ List receiptHandleMessageList = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ MessageExt expireMessage = createMessageExt(TOPIC, "", 0, 3000, System.currentTimeMillis() - 10000,
+ 0, 0, 0, i, brokerName1);
+ ReceiptHandle expireHandle = create(expireMessage);
+ receiptHandleMessageList.add(new ReceiptHandleMessage(expireHandle, expireMessage.getMsgId()));
+ }
+
+ List batchAckResultList = this.consumerProcessor.batchAckMessage(createContext(), receiptHandleMessageList, CONSUMER_GROUP, TOPIC, 3000).get();
+
+ verify(this.messageService, never()).batchAckMessage(any(), anyList(), anyString(), anyString(), anyLong());
+ assertEquals(receiptHandleMessageList.size(), batchAckResultList.size());
+ for (BatchAckResult batchAckResult : batchAckResultList) {
+ assertNull(batchAckResult.getAckResult());
+ assertNotNull(batchAckResult.getProxyException());
+ assertNotNull(batchAckResult.getReceiptHandleMessage());
+ }
+
+ }
+
+ @Test
+ public void testBatchAckMessage() throws Throwable {
+ String brokerName1 = "brokerName1";
+ String brokerName2 = "brokerName2";
+ String errThrowBrokerName = "errThrowBrokerName";
+ MessageExt expireMessage = createMessageExt(TOPIC, "", 0, 3000, System.currentTimeMillis() - 10000,
+ 0, 0, 0, 0, brokerName1);
+ ReceiptHandle expireHandle = create(expireMessage);
+
+ List